diff --git a/go.mod b/go.mod
index 3acfd98c..96f34001 100644
--- a/go.mod
+++ b/go.mod
@@ -10,4 +10,5 @@ require (
github.com/therecipe/qt v0.0.0-20200126204426-5074eb6d8c41
github.com/therecipe/qt/internal/binding/files/docs/5.12.0 v0.0.0-20200126204426-5074eb6d8c41 // indirect
github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20200126204426-5074eb6d8c41 // indirect
+ golang.org/x/crypto v0.0.0-20200320181102-891825fb96df
)
diff --git a/go/constants/settings.go b/go/constants/settings.go
index 6e148d14..1604b68e 100644
--- a/go/constants/settings.go
+++ b/go/constants/settings.go
@@ -1,5 +1,5 @@
package constants
-const BlockUnknownPeersSetting = ".blockunknownpeers"
-const LocaleSetting = ".locale"
-const ZoomSetting = ".zoom"
+const BlockUnknownPeersSetting = "blockunknownpeers"
+const LocaleSetting = "locale"
+const ZoomSetting = "zoom"
diff --git a/go/handlers/peerHandler.go b/go/handlers/peerHandler.go
index 537edc39..c6c8f02e 100644
--- a/go/handlers/peerHandler.go
+++ b/go/handlers/peerHandler.go
@@ -174,7 +174,6 @@ func upgradeSchema1(p peerC.CwtchPeer) {
if zoom, exists := p.GetAttribute("settings.zoom"); exists {
p.SetAttribute(attr.GetSettingsScope(constants.ZoomSetting), zoom)
-
}
if blockunknown, exists := p.GetAttribute("settings.blockunknownpeers"); exists {
diff --git a/go/the/globals.go b/go/the/globals.go
index 10511e45..5ad7e9c2 100644
--- a/go/the/globals.go
+++ b/go/the/globals.go
@@ -4,6 +4,7 @@ import (
"cwtch.im/cwtch/app"
"cwtch.im/cwtch/event"
libPeer "cwtch.im/cwtch/peer"
+ "cwtch.im/cwtch/storage/v1"
"git.openprivacy.ca/openprivacy/connectivity"
)
@@ -18,3 +19,4 @@ var ACN connectivity.ACN
var Peer libPeer.CwtchPeer
var CwtchDir string
var IPCBridge event.IPCBridge
+var GlobalSettingsFile v1.FileStore
diff --git a/go/ui/gcd.go b/go/ui/gcd.go
index afabe59e..0910fc7a 100644
--- a/go/ui/gcd.go
+++ b/go/ui/gcd.go
@@ -20,11 +20,13 @@ import (
type GrandCentralDispatcher struct {
core.QObject
- QMLEngine *qml.QQmlApplicationEngine
+ QMLEngine *qml.QQmlApplicationEngine
Translator, OpaqueTranslator *core.QTranslator
uIManagers map[string]Manager // profile-onion : Manager
+ GlobalSettings *GlobalSettings
+
profileLock sync.Mutex
conversationLock sync.Mutex
@@ -32,7 +34,9 @@ type GrandCentralDispatcher struct {
m_selectedConversation string
_ string `property:"os"`
- _ float32 `property:"themeScale"`
+ _ float32 `property:"themeScale,auto,changed"`
+ _ string `property:"theme,auto,changed`
+ _ string `property:"locale,auto,changed"`
_ string `property:"version"`
_ string `property:"buildDate"`
_ string `property:"assetPath"`
@@ -73,14 +77,13 @@ type GrandCentralDispatcher struct {
// settings helpers
_ func(str string) `signal:"InvokePopup"`
- _ func(zoom, locale string, blockunknownpeers bool) `signal:"SupplySettings"`
+ _ func(locale string, zoom float32, theme string) `signal:"SupplySettings"`
_ func(groupID, name, server, invitation string, accepted bool, addrbooknames, addrbookaddrs []string) `signal:"SupplyGroupSettings"`
_ func(onion, nick string, blocked bool) `signal:"SupplyPeerSettings"`
// signals emitted from the ui (written in go, below)
// ui
- _ func() `signal:"onActivate,auto"`
- _ func(locale string) `signal:"setLocale,auto"`
+ _ func() `signal:"onActivate,auto"`
// profile managemenet
_ func(onion, nick string) `signal:"updateNick,auto"`
_ func(handle string) `signal:"loadProfile,auto"`
@@ -102,7 +105,6 @@ type GrandCentralDispatcher struct {
_ func(groupID string) `signal:"leaveGroup,auto"`
_ func(groupID string) `signal:"acceptGroup,auto"`
_ func() `signal:"requestSettings,auto"`
- _ func(zoom, locale string) `signal:"saveSettings,auto"`
_ func(groupID string) `signal:"requestGroupSettings,auto"`
_ func(groupID, nick string) `signal:"saveGroupSettings,auto"`
_ func() `signal:"requestPeerSettings,auto"`
@@ -117,6 +119,9 @@ type GrandCentralDispatcher struct {
func (this *GrandCentralDispatcher) init() {
this.uIManagers = make(map[string]Manager)
+ this.GlobalSettings = ReadGlobalSettings()
+ this.SetThemeScale(this.GlobalSettings.Zoom)
+ this.SetTheme(this.GlobalSettings.Theme)
}
// GetUiManager gets (and creates if required) a ui Manager for the supplied profile id
@@ -323,31 +328,11 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) {
}
func (this *GrandCentralDispatcher) requestSettings() {
- zoom, exists := the.Peer.GetAttribute(attr.GetSettingsScope(constants.ZoomSetting))
- if !exists {
- zoom = "1.0"
- }
- locale, exists := the.Peer.GetAttribute(attr.GetSettingsScope(constants.LocaleSetting))
- if !exists {
- // TODO: pull env locale
- locale = ""
- }
-
- blockunkownpeers, exists := the.Peer.GetAttribute(attr.GetSettingsScope(constants.BlockUnknownPeersSetting))
- if !exists {
- blockunkownpeers = "false"
- }
- this.SupplySettings(zoom, locale, blockunkownpeers == "true")
+ this.SupplySettings(this.GlobalSettings.Locale, this.GlobalSettings.Zoom, this.GlobalSettings.Theme)
}
func (this *GrandCentralDispatcher) saveSettings(zoom, locale string) {
- // saveSettings accidentally gets called once when the app first starts but before the app has been prepared
- // so let's just ignore that one
- if the.CwtchApp == nil {
- return
- }
- the.Peer.SetAttribute(attr.GetSettingsScope(constants.ZoomSetting), zoom)
}
func (this *GrandCentralDispatcher) requestPeerSettings() {
@@ -360,6 +345,9 @@ func (this *GrandCentralDispatcher) requestPeerSettings() {
name := getNick(contact.Onion)
+ // Todo: Move to profile settings
+ //blockunkownpeers, _ := the.Peer.GetAttribute(attr.GetPeerScope(constants.BlockUnknownPeersSetting))
+
this.SupplyPeerSettings(contact.Onion, name, contact.Blocked)
}
@@ -558,15 +546,51 @@ func (this *GrandCentralDispatcher) allowUnknownPeers() {
the.EventBus.Publish(event.NewEvent(event.AllowUnknownPeers, map[event.Field]string{}))
}
-func (this *GrandCentralDispatcher) setLocale(locale string) {
- this.SetLocale_helper(locale)
+func (this *GrandCentralDispatcher) localeChanged(locale string) {
+ this.GlobalSettings.Locale = locale
+ WriteGlobalSettings(this.GlobalSettings)
+ this.setLocaleHelper(locale)
+}
- the.Peer.SetAttribute(attr.GetSettingsScope(constants.LocaleSetting), locale)
+func (this *GrandCentralDispatcher) setLocaleHelper(locale string) {
+ log.Debugf("Loading translators for '%v'\n", locale)
+ newTranslator := core.NewQTranslator(nil)
+ success := newTranslator.Load("translation_"+locale, ":/i18n/", "", "")
+ if success {
+ core.QCoreApplication_RemoveTranslator(this.Translator)
+ this.Translator = newTranslator
+ core.QCoreApplication_InstallTranslator(this.Translator)
+ } else {
+ log.Errorf("Could not load translator for '%v'\n", locale)
+ }
- zoom, _ := the.Peer.GetAttribute(attr.GetSettingsScope(constants.ZoomSetting))
- blockunkownpeers, _ := the.Peer.GetAttribute(attr.GetPeerScope(constants.BlockUnknownPeersSetting))
- this.SupplySettings(zoom, locale, blockunkownpeers == "true")
+ newOpaqueTranslator := core.NewQTranslator(nil)
+ success = newOpaqueTranslator.Load("translation_"+locale, ":/qml/opaque/i18n/", "", "")
+ if success {
+ core.QCoreApplication_RemoveTranslator(this.OpaqueTranslator)
+ this.OpaqueTranslator = newOpaqueTranslator
+ core.QCoreApplication_InstallTranslator(this.OpaqueTranslator)
+ } else {
+ log.Errorf("Could not load opaque translator for '%v'\n", locale)
+ }
+ this.QMLEngine.Retranslate()
+}
+
+func (this *GrandCentralDispatcher) themeScaleChanged(newThemeScale float32) {
+ // TODO: solve why themeScale > 2.0 halts app launch - related task - solve all the qml launch warnings around anchors/layouts
+ if this.Os() != "android" {
+ if newThemeScale > 1.99 {
+ this.SetThemeScale(1.99)
+ }
+ }
+ this.GlobalSettings.Zoom = newThemeScale
+ WriteGlobalSettings(this.GlobalSettings)
+}
+
+func (this *GrandCentralDispatcher) themeChanged(newTheme string) {
+ this.GlobalSettings.Theme = newTheme
+ WriteGlobalSettings(this.GlobalSettings)
}
func (this *GrandCentralDispatcher) onActivate() {
@@ -576,14 +600,6 @@ func (this *GrandCentralDispatcher) onActivate() {
}
}
-func (this *GrandCentralDispatcher) SetLocale_helper(locale string) {
- core.QCoreApplication_RemoveTranslator(this.Translator)
- this.Translator = core.NewQTranslator(nil)
- this.Translator.Load("translation_"+locale, ":/i18n/", "", "")
- core.QCoreApplication_InstallTranslator(this.Translator)
- this.QMLEngine.Retranslate()
-}
-
func (this *GrandCentralDispatcher) unlockProfiles(password string) {
the.CwtchApp.LoadProfiles(password)
}
@@ -618,13 +634,6 @@ func (this *GrandCentralDispatcher) loadProfile(onion string) {
// Only join servers for active and explicitly accepted groups.
this.GetUiManager(this.selectedProfile()).AddContact(groups[i])
}
-
- // load ui preferences
- this.RequestSettings()
- locale, exists := the.Peer.GetAttribute(attr.GetSettingsScope(constants.LocaleSetting))
- if exists {
- this.SetLocale_helper(locale)
- }
}
func (this *GrandCentralDispatcher) createProfile(nick string, defaultPass bool, password string) {
diff --git a/go/ui/settings.go b/go/ui/settings.go
new file mode 100644
index 00000000..1b4e4208
--- /dev/null
+++ b/go/ui/settings.go
@@ -0,0 +1,104 @@
+package ui
+
+import (
+ "crypto/rand"
+ "cwtch.im/cwtch/storage/v1"
+ "cwtch.im/ui/go/the"
+ "encoding/json"
+ "git.openprivacy.ca/openprivacy/log"
+ "github.com/therecipe/qt/core"
+ "golang.org/x/crypto/pbkdf2"
+ "golang.org/x/crypto/sha3"
+ "io"
+ "io/ioutil"
+ "os"
+ "path"
+ "runtime"
+)
+
+const GlobalSettingsFilename = "ui.globals"
+const saltFile = "SALT"
+
+type GlobalSettings struct {
+ Zoom float32
+ Locale string
+ Theme string
+}
+
+var DefaultGlobalSettings = GlobalSettings{
+ Zoom: 1.0,
+ Locale: "en",
+ Theme: "light",
+}
+
+// createKeySalt derives a key from a password: returns key, salt, err
+func createKeySalt(password string) ([32]byte, [128]byte, error) {
+ var salt [128]byte
+ if _, err := io.ReadFull(rand.Reader, salt[:]); err != nil {
+ log.Errorf("Cannot read from random: %v\n", err)
+ return [32]byte{}, salt, err
+ }
+ dk := pbkdf2.Key([]byte(password), salt[:], 4096, 32, sha3.New512)
+
+ var dkr [32]byte
+ copy(dkr[:], dk)
+ return dkr, salt, nil
+}
+
+func createKey(password string, salt []byte) [32]byte {
+ dk := pbkdf2.Key([]byte(password), salt, 4096, 32, sha3.New512)
+
+ var dkr [32]byte
+ copy(dkr[:], dk)
+ return dkr
+}
+
+func InitGlobalSettingsFile(directory string, password string) error {
+ var key [32]byte
+ salt, err := ioutil.ReadFile(path.Join(directory, saltFile))
+ if err != nil {
+ var newSalt [128]byte
+ key, newSalt, err = createKeySalt(password)
+ if err != nil {
+ return err
+ }
+ os.Mkdir(directory, 0700)
+ err := ioutil.WriteFile(path.Join(directory, saltFile), newSalt[:], 0600)
+ if err != nil {
+ return err
+ }
+ } else {
+ key = createKey(password, salt)
+ }
+
+ the.GlobalSettingsFile = v1.NewFileStore(directory, GlobalSettingsFilename, key)
+ return nil
+}
+
+func ReadGlobalSettings() *GlobalSettings {
+ settings := DefaultGlobalSettings
+ if runtime.GOOS == "android" {
+ settings.Zoom = 2.9
+ }
+ settings.Locale = core.QLocale_System().Name()
+
+ settingsBytes, err := the.GlobalSettingsFile.Read()
+ if err != nil {
+ log.Errorf("Could not read global ui settings: %v\n", err)
+ return &settings
+ }
+
+ err = json.Unmarshal(settingsBytes, &settings)
+ if err != nil {
+ log.Errorf("Could not parse global ui settings: %v\n", err)
+ }
+ return &settings
+}
+
+func WriteGlobalSettings(globalSettings *GlobalSettings) {
+ bytes, _ := json.Marshal(globalSettings)
+ err := the.GlobalSettingsFile.Write(bytes)
+ if err != nil {
+ log.Errorf("Could not write global ui settings: %v\n", err)
+ }
+}
diff --git a/i18n/translation_de.qm b/i18n/translation_de.qm
index 135d603d..c442202f 100644
Binary files a/i18n/translation_de.qm and b/i18n/translation_de.qm differ
diff --git a/i18n/translation_de.ts b/i18n/translation_de.ts
index af483be3..b843b25d 100644
--- a/i18n/translation_de.ts
+++ b/i18n/translation_de.ts
@@ -227,38 +227,38 @@
PeerSettingsPane
-
+
Adresse
-
+
Kopieren
-
+
notification: copied to clipboard
in die Zwischenablage kopiert
-
+
Angezeigter Name
-
+
speichern
-
+
löschen
-
+
@@ -410,36 +410,110 @@
Cwtch Einstellungen
-
Interface zoom (mostly affects text and button sizes)
- Benutzeroberflächen-Zoom (betriftt hauptsächlich Text- und Knopgrößen)
+ Benutzeroberflächen-Zoom (betriftt hauptsächlich Text- und Knopgrößen)
-
+
+
+ Language
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Interface Zoom
+
+
+
+
Groß
-
-
- "Default size text (scale factor: "
- defaultmäßige Textgröße (Skalierungsfaktor:
-
-
-
-
- Klein
-
-
-
-
- Version: %1 Built on: %2
+
+
+ Theme
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+ Version %1
+
+
+
+
+
+ Built on: %2
+
+
+
+
+ "Default size text (scale factor: "
+ defaultmäßige Textgröße (Skalierungsfaktor:
+
+
+
+
+ Klein
+
+
+
+ Statusbar
+
+
+
+ Disconnected from the internet, check your connection
+
+
+
+
+
+ Attempting to connect to Tor network
+
+
+
+
+
+ Connecting...
+
+
+
+
+
+ Online
diff --git a/i18n/translation_en.qm b/i18n/translation_en.qm
index fb3618ba..49063bb7 100644
Binary files a/i18n/translation_en.qm and b/i18n/translation_en.qm differ
diff --git a/i18n/translation_en.ts b/i18n/translation_en.ts
index bce3a55a..91af2302 100644
--- a/i18n/translation_en.ts
+++ b/i18n/translation_en.ts
@@ -322,33 +322,33 @@ Right-click to reset.
PeerSettingsPane
-
+
Address
-
+
Copy
-
+
notification: copied to clipboard
Copied to Clipboard
-
+
Display Name
-
+
Save
-
+
Block Peer
@@ -357,7 +357,7 @@ Right-click to reset.
Unblock Peer
-
+
Delete
@@ -517,35 +517,91 @@ Right-click to reset.
Cwtch Settings
-
Version: %1 Built on: %2
- Version: %1 Built on: %2
+ Version: %1 Built on: %2
-
Interface zoom (mostly affects text and button sizes)
- Interface zoom (mostly affects text and button sizes)
+ Interface zoom (mostly affects text and button sizes)
-
- Block Unknown Peers
+ Block Unknown Peers
-
+
+
+ Language
+ Language
+
+
+
+
+ English
+
+
+
+
+ Frances
+
+
+
+
+ Portuguesa
+
+
+
+
+ Deutsche
+
+
+
+
+ Interface Zoom
+ Zoom level
+
+
+
Large
-
-
- "Default size text (scale factor: "
- Default size text (scale factor:
+
+
+ Theme
+ Theme
-
+
+
+ Light
+
+
+
+
+ Dark
+
+
+
+
+ Version %1
+ Version %1
+
+
+
+
+ Built on: %2
+ Built on: %2
+
+
+
+ "Default size text (scale factor: "
+ Default size text (scale factor:
+
+
+
Small
@@ -561,24 +617,28 @@ Right-click to reset.
Statusbar
+
Disconnected from the internet, check your connection
- Disconnected from the internet, check your connection
+ Disconnected from the internet, check your connection
+
Attempting to connect to Tor network
- Attempting to connect to Tor network
+ Attempting to connect to Tor network
+
Connecting...
- Connecting to network and peers...
+ Connecting to network and peers...
+
Online
- Online
+ Online
diff --git a/i18n/translation_fr.qm b/i18n/translation_fr.qm
index 7b55a58d..3026fc59 100644
Binary files a/i18n/translation_fr.qm and b/i18n/translation_fr.qm differ
diff --git a/i18n/translation_fr.ts b/i18n/translation_fr.ts
index 6453d504..0193e6f0 100644
--- a/i18n/translation_fr.ts
+++ b/i18n/translation_fr.ts
@@ -227,38 +227,38 @@
PeerSettingsPane
-
+
Adresse
-
+
Copier
-
+
notification: copied to clipboard
Copié dans le presse-papier
-
+
Pseudo
-
+
Sauvegarder
-
+
Effacer
-
+
@@ -410,36 +410,110 @@
Préférences Cwtch
-
Interface zoom (mostly affects text and button sizes)
- Interface zoom (essentiellement la taille du texte et des composants de l'interface)
+ Interface zoom (essentiellement la taille du texte et des composants de l'interface)
-
+
+
+ Language
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Interface Zoom
+
+
+
+
Large
-
-
- "Default size text (scale factor: "
- Taille par défaut du texte (échelle:
-
-
-
-
- Petit
-
-
-
-
- Version: %1 Built on: %2
+
+
+ Theme
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+ Version %1
+
+
+
+
+
+ Built on: %2
+
+
+
+
+ "Default size text (scale factor: "
+ Taille par défaut du texte (échelle:
+
+
+
+
+ Petit
+
+
+
+ Statusbar
+
+
+
+ Disconnected from the internet, check your connection
+
+
+
+
+
+ Attempting to connect to Tor network
+
+
+
+
+
+ Connecting...
+
+
+
+
+
+ Online
diff --git a/i18n/translation_pt.qm b/i18n/translation_pt.qm
index a1155b51..39f9c4bd 100644
Binary files a/i18n/translation_pt.qm and b/i18n/translation_pt.qm differ
diff --git a/i18n/translation_pt.ts b/i18n/translation_pt.ts
index 2c823d90..4bcda35a 100644
--- a/i18n/translation_pt.ts
+++ b/i18n/translation_pt.ts
@@ -227,38 +227,38 @@
PeerSettingsPane
-
+
Endereço
-
+
Copiar
-
+
notification: copied to clipboard
Copiado
-
+
Nome de Exibição
-
+
Salvar
-
+
Deletar
-
+
@@ -410,36 +410,110 @@
Configurações do Cwtch
-
Interface zoom (mostly affects text and button sizes)
- Zoom da interface (afeta principalmente tamanho de texto e botões)
+ Zoom da interface (afeta principalmente tamanho de texto e botões)
-
+
+
+ Language
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Interface Zoom
+
+
+
+
Grande
-
-
- "Default size text (scale factor: "
- Texto tamanho padrão (fator de escala:
-
-
-
-
- Pequeno
-
-
-
-
- Version: %1 Built on: %2
+
+
+ Theme
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+ Version %1
+
+
+
+
+
+ Built on: %2
+
+
+
+
+ "Default size text (scale factor: "
+ Texto tamanho padrão (fator de escala:
+
+
+
+
+ Pequeno
+
+
+
+ Statusbar
+
+
+
+ Disconnected from the internet, check your connection
+
+
+
+
+
+ Attempting to connect to Tor network
+
+
+
+
+
+ Connecting...
+
+
+
+
+
+ Online
diff --git a/main.go b/main.go
index f506b647..b2b987a7 100644
--- a/main.go
+++ b/main.go
@@ -131,6 +131,11 @@ func mainUi(flagLocal bool, flagClientUI bool) {
app := gui.NewQGuiApplication(len(os.Args), os.Args)
// our globals
+ err := ui.InitGlobalSettingsFile(path.Join(the.CwtchDir, "global"), the.AppPassword)
+ if err != nil {
+ log.Errorf("Could not access global ui config: %v\n", err)
+ os.Exit(-1)
+ }
gcd := ui.NewGrandCentralDispatcher(nil)
gcd.SetOs(runtime.GOOS)
dir := core.QCoreApplication_ApplicationDirPath()
@@ -154,9 +159,6 @@ func mainUi(flagLocal bool, flagClientUI bool) {
gcd.SetBuildDate("now")
}
- //TODO: put theme stuff somewhere better
- gcd.SetThemeScale(1.0)
-
// this is to load local qml files quickly when developing
var qmlSource *core.QUrl
if flagLocal {
@@ -175,17 +177,11 @@ func mainUi(flagLocal bool, flagClientUI bool) {
opaqueTranslator.Load("translation_en", ":/qml/opaque/i18n/", "", "")
core.QCoreApplication_InstallTranslator(opaqueTranslator)
- gcd.Translator = core.NewQTranslator(nil)
- gcd.Translator.Load("translation_"+core.QLocale_System().Name(), ":/i18n/", "", "")
- core.QCoreApplication_InstallTranslator(gcd.Translator)
- gcd.OpaqueTranslator = core.NewQTranslator(nil)
- gcd.OpaqueTranslator.Load("translation_"+core.QLocale_System().Name(), ":/qml/opaque/i18n/", "", "")
- core.QCoreApplication_InstallTranslator(gcd.OpaqueTranslator)
-
core.QCoreApplication_SetAttribute(core.Qt__AA_EnableHighDpiScaling, true)
quickcontrols2.QQuickStyle_SetStyle("Universe")
engine := qml.NewQQmlApplicationEngine(nil)
gcd.QMLEngine = engine
+ gcd.SetLocale(gcd.GlobalSettings.Locale)
// prevent qt from initiating network connections (possible deanon attempts!)
factory := qml.NewQQmlNetworkAccessManagerFactory()
@@ -199,12 +195,6 @@ func mainUi(flagLocal bool, flagClientUI bool) {
})
engine.SetNetworkAccessManagerFactory(factory)
- // variables we want to access from inside qml
- if runtime.GOOS == "android" {
- gcd.SetThemeScale(2.9)
- } else {
- gcd.SetThemeScale(1.0)
- }
engine.RootContext().SetContextProperty("gcd", gcd)
var androidCwtchActivity = android.NewCwtchActivity(nil)
diff --git a/qml.qrc b/qml.qrc
index d8bacb3c..794ee803 100644
--- a/qml.qrc
+++ b/qml.qrc
@@ -11,14 +11,15 @@
qml/panes/PeerSettingsPane.qml
qml/panes/SettingsPane.qml
qml/panes/SplashPane.qml
- qml/panes/ProfileManagerPane.qml
- qml/panes/ProfileAddEditPane.qml
+ qml/panes/ProfileManagerPane.qml
+ qml/panes/ProfileAddEditPane.qml
qml/widgets/ContactList.qml
qml/widgets/ContactRow.qml
qml/widgets/Message.qml
qml/widgets/MyProfile.qml
qml/widgets/ProfileList.qml
qml/widgets/ProfileRow.qml
+ qml/widgets/Statusbar.qml
i18n/translation_de.qm
i18n/translation_en.qm
i18n/translation_fr.qm
diff --git a/qml/main.qml b/qml/main.qml
index 0fe47487..845ff519 100644
--- a/qml/main.qml
+++ b/qml/main.qml
@@ -81,6 +81,12 @@ ApplicationWindow {
Toolbar {
id: toolbar
+
+ onLeftMenu: {
+ gcd.requestSettings()
+ parentStack.pane = parentStack.settingsPane
+ }
+
onBack: { backFn() }
onRightMenu: {
@@ -104,16 +110,16 @@ ApplicationWindow {
readonly property int splashPane: 0
readonly property int managementPane: 1
- readonly property int addEditProfilePane: 2
- readonly property int profilePane: 3
+ readonly property int settingsPane: 2
+ readonly property int addEditProfilePane: 3
+ readonly property int profilePane: 4
property alias pane: parentStack.currentIndex
Rectangle { // Splash pane
color: Theme.backgroundMainColor
- //Layout.fillHeight: true
- //Layout.minimumWidth: Layout.maximumWidth
- //Layout.minimumHeight: parent.height
- anchors.fill: parent
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ //anchors.fill: parent
visible: true
@@ -125,7 +131,9 @@ ApplicationWindow {
}
Rectangle { // Profile login/management pane
- anchors.fill: parent
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ //anchors.fill: parent
visible: false
color: Theme.backgroundMainColor
@@ -135,8 +143,23 @@ ApplicationWindow {
}
}
- Rectangle { // Profile login/management pane
- anchors.fill: parent
+ Rectangle { // Settings pane
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ //anchors.fill: parent
+ color: Theme.backgroundMainColor
+
+ SettingsPane {
+ id: settingsPane
+ anchors.fill: parent
+ }
+ }
+
+
+ Rectangle { // Profile Add / Edit pane
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ //anchors.fill: parent
color: Theme.backgroundMainColor
@@ -148,7 +171,9 @@ ApplicationWindow {
RowLayout { // CONTAINS EVERYTHING EXCEPT THE TOOLBAR
- anchors.fill: parent
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ //anchors.fill: parent
spacing: 0
Rectangle { // THE LEFT PANE WITH TOOLS AND CONTACTS
@@ -179,10 +204,9 @@ ApplicationWindow {
property alias pane: theStack.currentIndex
readonly property int emptyPane: 0
readonly property int messagePane: 1
- readonly property int settingsPane: 2
- readonly property int userProfilePane: 3
- readonly property int groupProfilePane: 4
- readonly property int addGroupPane: 5
+ readonly property int userProfilePane: 2
+ readonly property int groupProfilePane: 3
+ readonly property int addGroupPane: 4
Item { anchors.fill: parent } // empty
@@ -190,7 +214,6 @@ ApplicationWindow {
anchors.fill: parent
}
- SettingsPane { anchors.fill: parent }
PeerSettingsPane { anchors.fill: parent }
@@ -239,17 +262,20 @@ ApplicationWindow {
} else {
toolbar.leftMenuVisible = false
toolbar.backVisible = true
-
- if (currentIndex == addEditProfilePane) {
- toolbar.color = Theme.backgroundPaneColor
- } else if (currentIndex == profilePane) {
- toolbar.color = Theme.backgroundPaneColor
- }
+ toolbar.color = Theme.backgroundPaneColor
}
}
}
Component.onCompleted: updateToolbar()
+
+ Connections {
+ target: Theme
+
+ onThemeChanged: {
+ parentStack.updateToolbar()
+ }
+ }
}
Statusbar {
diff --git a/qml/opaque b/qml/opaque
index db305895..0ec6a2df 160000
--- a/qml/opaque
+++ b/qml/opaque
@@ -1 +1 @@
-Subproject commit db305895e70fbb599d2600a7e1f2245a56380217
+Subproject commit 0ec6a2df571e1a9c462d902cfc89f2402a9bef97
diff --git a/qml/panes/PeerSettingsPane.qml b/qml/panes/PeerSettingsPane.qml
index d9f39dbf..b6b9904c 100644
--- a/qml/panes/PeerSettingsPane.qml
+++ b/qml/panes/PeerSettingsPane.qml
@@ -11,131 +11,93 @@ import "../opaque" as Opaque
import "../opaque/styles"
import "../opaque/theme"
-ColumnLayout { // peerSettingsPane
+Opaque.SettingsList { // settingsPane
id: root
anchors.fill: parent
+
property bool blocked
- Flickable {
+ settings: Column {
anchors.fill: parent
- boundsBehavior: Flickable.StopAtBounds
- clip:true
- contentWidth: tehcol.width
- contentHeight: tehcol.height
+
+ Opaque.Setting {
+ inline: false
+ label: qsTr("address-label")
+
+ field: Opaque.ButtonTextField {
+ id: txtOnion
+ readOnly: true
+ button_text: qsTr("copy-btn")
+ dropShadowColor: Theme.dropShadowPaneColor
+ onClicked: {
+ //: notification: copied to clipboard
+ gcd.popup(qsTr("copied-to-clipboard-notification"))
+ txtOnion.selectAll()
+ txtOnion.copy()
+ }
+ }
+ }
+
+
+
+ Opaque.Setting {
+ inline: false
+
+ label: qsTr("display-name-label")
+
+ field: Opaque.ButtonTextField {
+ id: txtDisplayName
+ button_text: qsTr("save-btn")
+ dropShadowColor: Theme.dropShadowPaneColor
+ onClicked: {
+ gcd.savePeerSettings(txtOnion.text, txtDisplayName.text)
+ // TODO: broken
+ theStack.title = txtDisplayName.text
+ theStack.pane = theStack.messagePane
+ }
+ }
+ }
+
+
+
+
+ Opaque.Setting {
+ label: qsTr("block-btn")
+
+
+ field: Opaque.ToggleSwitch {
+ anchors.right: parent.right
+
+ isToggled: root.blocked // ? qsTr("unblock-btn") : qsTr("block-btn")
+ onToggled: function() {
+ if (root.blocked) {
+ gcd.unblockPeer(txtOnion.text)
+ } else {
+ gcd.blockPeer(txtOnion.text)
+ }
+ root.blocked = !root.blocked
+ isToggled = root.blocked
+ }
+ }
+ }
Column {
- id: tehcol
- width: root.width
- padding:20
- spacing: 10
- GridLayout {
- columns: 1
- width:parent.width * 0.95
- anchors.horizontalCenter: parent.horizontalCenter
- Opaque.EllipsisLabel {
- anchors.left:parent.left
- color: Theme.mainTextColor
- text: qsTr("address-label")
- font.styleName: "ExtraBold"
- font.pointSize: 15 * gcd.themeScale
- }
+ width:parent.width * 0.95
+ anchors.horizontalCenter: parent.horizontalCenter
+ Opaque.Button {
+ icon: "regular/trash-alt"
+ text: qsTr("delete-btn")
+ anchors.right: parent.right
- Opaque.ButtonTextField {
- id: txtOnion
- anchors.left:parent.left
- anchors.right:parent.right
- readOnly: true
- button_text: qsTr("copy-btn")
- dropShadowColor: Theme.dropShadowPaneColor
- onClicked: {
- //: notification: copied to clipboard
- gcd.popup(qsTr("copied-to-clipboard-notification"))
- txtOnion.selectAll()
- txtOnion.copy()
- }
+
+ onClicked: {
+ gcd.deleteContact(txtOnion.text)
+ theStack.pane = theStack.emptyPane
}
}
+ }
- Opaque.HLine{}
-
- GridLayout {
- columns: 1
- width:parent.width * 0.95
- anchors.horizontalCenter: parent.horizontalCenter
- Opaque.EllipsisLabel {
- anchors.left:parent.left
- color: Theme.mainTextColor
- text: qsTr("display-name-label")
- font.styleName: "ExtraBold"
- font.pointSize: 15 * gcd.themeScale
- }
-
-
- Opaque.ButtonTextField {
- id: txtDisplayName
- anchors.left:parent.left
- anchors.right:parent.right
- button_text: qsTr("save-btn")
- dropShadowColor: Theme.dropShadowPaneColor
- onClicked: {
- gcd.savePeerSettings(txtOnion.text, txtDisplayName.text)
- theStack.title = txtDisplayName.text
- theStack.pane = theStack.messagePane
- }
- }
- }
-
-
- Opaque.HLine{}
-
-
- GridLayout {
- columns: 2
- width:parent.width * 0.95
- anchors.horizontalCenter: parent.horizontalCenter
- Opaque.EllipsisLabel {
- color: Theme.mainTextColor
- text: qsTr("block-btn")
- font.styleName: "ExtraBold"
- font.pointSize: 15 * gcd.themeScale
- }
-
- Opaque.ToggleSwitch {
- isToggled: root.blocked // ? qsTr("unblock-btn") : qsTr("block-btn")
- anchors.right: parent.right
- onToggled: function() {
- if (root.blocked) {
- gcd.unblockPeer(txtOnion.text)
- } else {
- gcd.blockPeer(txtOnion.text)
- }
- root.blocked = !root.blocked
- isToggled = root.blocked
- }
- }
-
-
- }
-
- Opaque.HLine{}
- Column {
- width:parent.width * 0.95
- anchors.horizontalCenter: parent.horizontalCenter
- Opaque.Button {
- icon: "regular/trash-alt"
- text: qsTr("delete-btn")
- anchors.right: parent.right
-
-
- onClicked: {
- gcd.deleteContact(txtOnion.text)
- theStack.pane = theStack.emptyPane
- }
- }
- }
-
- }//end of column with padding
- }//end of flickable
+ }
Connections {
diff --git a/qml/panes/SettingsPane.qml b/qml/panes/SettingsPane.qml
index 91f48e2d..848f92ba 100644
--- a/qml/panes/SettingsPane.qml
+++ b/qml/panes/SettingsPane.qml
@@ -9,130 +9,192 @@ import QtQuick.Controls.Styles 1.4
import "../opaque" as Opaque
import "../opaque/controls"
+import "../opaque/theme"
-ColumnLayout { // settingsPane
+Opaque.SettingsList { // settingsPane
id: root
anchors.fill: parent
- Flickable {
- anchors.fill: parent
- boundsBehavior: Flickable.StopAtBounds
- clip:true
- contentWidth: tehcol.width
- contentHeight: tehcol.height
+ settings: Column {
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: 700
+ Opaque.Setting {
+ //: Language
+ label: qsTr("setting-language")
- Column {
- id: tehcol
- leftPadding: 10
- spacing: 5
- width: root.width
+ field: ComboBox {
+ id: cbLanguage
+ anchors.right: parent.right
+ anchors.left: parent.left
- Opaque.ScalingLabel {
- width: parent.width
- wrapMode: TextEdit.Wrap
- //: Version: %1 Built on: %2
- text: qsTr("version %1 builddate %2").arg(gcd.version).arg(gcd.buildDate)
- }
+ property bool inited: false
- Opaque.ScalingLabel {
- width: parent.width
- wrapMode: TextEdit.Wrap
- //: Interface zoom (mostly affects text and button sizes)
- text: qsTr("zoom-label") + ":"
- }
-
- Slider {
- id: zoomSlider
- minimumValue: 0.5
- maximumValue: 4.0
- value: gcd.themeScale
- updateValueWhileDragging: false
- onValueChanged: {
- gcd.themeScale = zoomSlider.value
- saveSettings()
+ model: ListModel {
+ id: cbLangItems
+ ListElement { text: qsTr("locale-en"); value: "en" }
+ ListElement { text: qsTr("locale-fr"); value: "fr" }
+ ListElement { text: qsTr("locale-pt"); value: "pt" }
+ ListElement { text: qsTr("locale-de"); value: "de" }
}
- width: 400
- }
-
- CheckBox {
- id: blockUnknownToggle
- checked: true
- onClicked: {
- if (blockUnknownToggle.checked) {
- gcd.blockUnknownPeers()
- } else {
- gcd.allowUnknownPeers()
+ onCurrentIndexChanged: {
+ var item = cbLangItems.get(cbLanguage.currentIndex)
+ // Comboboxes seem to fire one Change on load...
+ if (!cbLanguage.inited) {
+ cbLanguage.inited = true
+ return
}
+ gcd.locale = item["value"]
}
- style: CheckBoxStyle {
- label: Opaque.ScalingLabel {
- text: qsTr("block-unknown-label")
+
+ }
+ }
+
+ Opaque.Setting {
+ //: Interface Zoom
+ label: qsTr("setting-interface-zoom")
+
+ field: Row {
+ spacing: 10
+ anchors.verticalCenter: parent.verticalCenter
+
+ Opaque.ScalingLabel {
+ text: qsTr("small-text-label")
+ size: 8
+ }
+
+ Slider {
+ id: zoomSlider
+ minimumValue: 0.5
+ // TODO: find out why > 2.0 halts desktop app on load - task: fix all the qml anchor/layout warnings on load
+ maximumValue: gcd.os == "android" ? 4.0 : 1.9
+ value: gcd.themeScale
+ updateValueWhileDragging: false
+ onValueChanged: {
+ gcd.themeScale = zoomSlider.value
}
- }
- }
-
- Opaque.ScalingLabel {
- wrapMode: TextEdit.Wrap
- text: qsTr("large-text-label")
- size: 20
- }
-
- Opaque.ScalingLabel{
- width: parent.width
- wrapMode: TextEdit.Wrap
- //: "Default size text (scale factor: "
- text: qsTr("default-scaling-text") + " " + Math.round(zoomSlider.value * 100) / 100 + ")"
- }
-
- Opaque.ScalingLabel {
- text: qsTr("small-text-label")
- size: 8
- }
-
- GridLayout {
- columns: 2
- columnSpacing: 10
-
-
- FlagButton {
- emoji: "1f1e9-1f1ea"
- locale: "de"
+ width: 200
}
- FlagButton {
- emoji: "1f1e8-1f1e6"
- locale: "en"
- selected: true
- }
- FlagButton {
- locale: "fr"
- emoji: "1f1eb-1f1f7"
- }
-
- FlagButton {
- locale: "pt"
- emoji: "1f1e7-1f1f7"
+ Opaque.ScalingLabel {
+ anchors.verticalCenter: parent.verticalCenter
+ wrapMode: TextEdit.Wrap
+ text: qsTr("large-text-label")
+ size: 20
}
}
+ }
- }//end of column with padding
- }//end of flickable
+ Opaque.Setting {
+ //: Theme
+ label: qsTr("setting-theme")
+
+ field: ComboBox {
+ id: cbTheme
+ property bool inited: false
+ anchors.right: parent.right
+ anchors.left: parent.left
+ model: ListModel {
+ id: cbThemeItems
+ ListElement { text: qsTr("theme-light"); value: 'light' }
+ ListElement { text: qsTr("theme-dark"); value: 'dark' }
+ }
+
+ onCurrentIndexChanged: {
+ var item = cbThemeItems.get(cbTheme.currentIndex)
+ // Comboboxes seem to fire one Change on load...
+ if (!cbTheme.inited) {
+ cbTheme.inited = true
+ return
+ }
+ gcd.theme = item["value"]
+ }
+ }
+ }
- function saveSettings() {
- // language switcher saves itself because erinn is a bad (read: amazing) programmer
- gcd.saveSettings(zoomSlider.value, "")
}
+
Connections {
target: gcd
- onSupplySettings: function(zoom, locale, blockunknown) {
+ onSupplySettings: function(locale, zoom, theme) {
if (zoom != "") zoomSlider.value = zoom
- // (locale is handled automatically by FlagButton)
- blockUnknownToggle.checked = blockunknown
+
+ for (var i=0; i < cbLangItems.count; i++) {
+ var item = cbLangItems.get(i)
+ if (item["value"] == locale) {
+ cbLanguage.currentIndex = i
+ break
+ }
+ }
+
+ for (var i=0; i < cbThemeItems.count; i++) {
+ var item = cbThemeItems.get(i)
+ if (item["value"] == theme) {
+ cbTheme.currentIndex = i
+ break
+ }
+ }
}
}
+
+
+
+ Opaque.ScalingLabel {
+ id: versionLabel
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: builddateLabel.top
+ //: Version %1
+ text: qsTr("version %1").arg(gcd.version)
+ }
+
+ Opaque.ScalingLabel {
+ id: builddateLabel
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: 10
+ //: Built on: %2
+ text: qsTr("builddate %2").arg(gcd.buildDate)
+ }
+
+
+ //end of flickable
}
+
+
+/* Opaque.ScalingLabel {
+width: parent.width
+wrapMode: TextEdit.Wrap
+//: Interface zoom (mostly affects text and button sizes)
+text: qsTr("zoom-label") + ":"
+}
+
+
+
+
+CheckBox {
+id: blockUnknownToggle
+checked: true
+onClicked: {
+if (blockUnknownToggle.checked) {
+gcd.blockUnknownPeers()
+} else {
+gcd.allowUnknownPeers()
+}
+}
+style: CheckBoxStyle {
+label: Opaque.ScalingLabel {
+text: qsTr("block-unknown-label")
+}
+}
+}
+
+
+
+
+*/
+
+
diff --git a/qml/widgets/ContactList.qml b/qml/widgets/ContactList.qml
index 6420d707..f2cf8fdf 100644
--- a/qml/widgets/ContactList.qml
+++ b/qml/widgets/ContactList.qml
@@ -28,28 +28,28 @@ ColumnLayout {
Opaque.IconTextField {
- id: searchAddText
- anchors.horizontalCenter: parent.horizontalCenter
+ id: searchAddText
+ anchors.horizontalCenter: parent.horizontalCenter
- Layout.minimumWidth: parent.width - 60
- Layout.maximumWidth: parent.width - 60
+ Layout.minimumWidth: parent.width - 60
+ Layout.maximumWidth: parent.width - 60
- //: ex: "... paste an address here to add a contact ..."
- placeholderText: qsTr("paste-address-to-add-contact")
- horizontalAlignment: TextInput.AlignHCenter
- icon: gcd.assetPath + "core/search-24px.svg"
+ //: ex: "... paste an address here to add a contact ..."
+ placeholderText: qsTr("paste-address-to-add-contact")
+ horizontalAlignment: TextInput.AlignHCenter
+ icon: gcd.assetPath + "core/search-24px.svg"
- onTextChanged: {
- if (text != "") {
- gcd.importString(text)
- text = ""
- }
+ onTextChanged: {
+ if (text != "") {
+ gcd.importString(text)
+ text = ""
}
}
+ }
Flickable { // THE ACTUAL CONTACT LIST
diff --git a/qml/widgets/MyProfile.qml b/qml/widgets/MyProfile.qml
index 8a9b8898..70c6269b 100644
--- a/qml/widgets/MyProfile.qml
+++ b/qml/widgets/MyProfile.qml
@@ -108,11 +108,8 @@ Item {
Opaque.EllipsisLabel {
id: name
- anchors.right: undefined
- anchors.left: undefined
-
color: Theme.portraitOnlineTextColor
- pixelSize: Theme.usernameSize * gcd.themeScale
+ size: Theme.usernameSize * gcd.themeScale
weight: Font.Bold
text: nick
extraPadding: addBtn.width + 30
diff --git a/qml/widgets/Statusbar.qml b/qml/widgets/Statusbar.qml
index e1dfa0c0..8c8bc747 100644
--- a/qml/widgets/Statusbar.qml
+++ b/qml/widgets/Statusbar.qml
@@ -158,18 +158,18 @@ Rectangle {
}
function show() {
- if (isHover || status != statusOnline) {
- hideAnim.stop()
- showAnim.start()
- }
- }
+ if (isHover || status != statusOnline) {
+ hideAnim.stop()
+ showAnim.start()
+ }
+ }
- function hide() {
- if (!isHover && status == statusOnline) {
- showAnim.stop()
- hideAnim.start()
- }
- }
+ function hide() {
+ if (!isHover && status == statusOnline) {
+ showAnim.stop()
+ hideAnim.start()
+ }
+ }
onStatusChanged: { changeStatus() }
@@ -183,4 +183,12 @@ Rectangle {
}
}
+ Connections {
+ target: Theme
+
+ onThemeChanged: {
+ changeStatus()
+ }
+ }
+
}