Browse Source

Experimental Gating + Server List Sketch

pull/351/head
Sarah Jamie Lewis 1 year ago
parent
commit
bfb431cbaf
  1. 4
      go.mod
  2. 10
      go.sum
  3. 8
      go/constants/server_manager_events.go
  4. 57
      go/servers/server_manager.go
  5. 37
      go/ui/gcd.go
  6. 13
      go/ui/settings.go
  7. 4
      main.go
  8. 12
      qml/main.qml
  9. 3
      qml/panes/ProfileManagerPane.qml
  10. 63
      qml/panes/ServerAddEditPane.qml
  11. 63
      qml/panes/SettingsPane.qml
  12. 16
      qml/utils.js
  13. 24
      qml/widgets/ExperimentToggle.qml
  14. 51
      qml/widgets/ServerList.qml
  15. 60
      qml/widgets/ServerRow.qml

4
go.mod

@ -16,4 +16,8 @@ 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
go.etcd.io/bbolt v1.3.5 // indirect
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 // indirect
golang.org/x/net v0.0.0-20201022231255-08b38378de70 // indirect
golang.org/x/sys v0.0.0-20201022201747-fb209a7c41cd // indirect
)

10
go.sum

@ -1,3 +1,4 @@
cwtch.im v0.4.3 h1:3c//RcO0+YFqm0XOILq7ScsGgQsA4waLU1XAbQRH3n4=
cwtch.im/cwtch v0.4.2-0.20201008200820-a2c5a28e092d h1:CuqoPJdfmKqvGnZhQtrv/9YqTRei3t06AvCGrCmD3gU=
cwtch.im/cwtch v0.4.2-0.20201008200820-a2c5a28e092d/go.mod h1:EvZQDbvXNu38m785dWF0MMljqJzwWrNTFT40HvoEAhI=
cwtch.im/cwtch v0.4.2-0.20201016053957-1933fb703fb0 h1:8d2hJyb6qupb9wS6px3734Hy1aHOrtwk4fpM1z/o3Tg=
@ -60,6 +61,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/struCoder/pidusage v0.1.3 h1:pZcSa6asBE38TJtW0Nui6GeCjLTpaT/jAnNP7dUTLSQ=
github.com/struCoder/pidusage v0.1.3/go.mod h1:pWBlW3YuSwRl6h7R5KbvA4N8oOqe9LjaKW5CwT1SPjI=
github.com/therecipe/qt v0.0.0-20200126204426-5074eb6d8c41 h1:yBVcrpbaQYJBdKT2pxTdlL4hBE/eM4UPcyj9YpyvSok=
github.com/therecipe/qt v0.0.0-20200126204426-5074eb6d8c41/go.mod h1:SUUR2j3aE1z6/g76SdD6NwACEpvCxb3fvG82eKbD6us=
@ -70,6 +72,8 @@ github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20200126204426
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0=
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@ -80,6 +84,8 @@ golang.org/x/crypto v0.0.0-20200420104511-884d27f42877/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee h1:4yd7jl+vXjalO5ztz6Vc1VADv+S/80LGJmyl1ROJ2AI=
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
@ -93,6 +99,8 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb h1:mUVeFHoDKis5nxCAzoAi7E8Ghb86EXh/RK6wtvJIqRY=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201022231255-08b38378de70 h1:Z6x4N9mAi4oF0TbHweCsH618MO6OI6UFgV0FP5n0wBY=
golang.org/x/net v0.0.0-20201022231255-08b38378de70/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -111,6 +119,8 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d h1:nc5K6ox/4lTFbMVSL9WRR81ix
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201022201747-fb209a7c41cd h1:WgqgiQvkiZWz7XLhphjt2GI2GcGCTIZs9jqXMWmH+oc=
golang.org/x/sys v0.0.0-20201022201747-fb209a7c41cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

8
go/constants/server_manager_events.go

@ -0,0 +1,8 @@
package constants
import "cwtch.im/cwtch/event"
// The server manage defines its own events...
const (
ListServers = event.Type("ListServers")
)

57
go/servers/server_manager.go

@ -0,0 +1,57 @@
package servers
import (
"cwtch.im/cwtch/event"
"cwtch.im/cwtch/server"
"cwtch.im/ui/go/constants"
"cwtch.im/ui/go/the"
"cwtch.im/ui/go/ui"
"git.openprivacy.ca/openprivacy/log"
)
// ServerManager is responsible for managing user operated servers
type ServerManager struct {
servers map[string]server.Server
}
func LaunchServiceManager(gcd *ui.GrandCentralDispatcher) {
sm := new(ServerManager)
sm.Init(gcd)
}
func (sm * ServerManager) Init(gcd *ui.GrandCentralDispatcher) {
sm.servers = make(map[string]server.Server)
q := event.NewQueue()
the.AppBus.Subscribe(constants.ListServers, q)
for {
e := q.Next()
switch e.EventType {
case constants.ListServers: {
sm.ListServers(gcd)
}
}
}
}
// TODO Replace with details from actual hosted servers. Right now these values are used to sketch / test out the
// UI QML
func (sm * ServerManager) ListServers(gcd *ui.GrandCentralDispatcher) {
log.Debugf("Listing Servers...")
gcd.AddServer("Server 1","Server 1","server",0)
gcd.AddServer("Server 2","Server 2","server",4)
gcd.AddServer("Server 3","Server 3","server",4)
}
func (sm * ServerManager) StartServer(handle string) {
// TODO Start the server with the given handle config
}
func (sm * ServerManager) StopServer(handle string) {
// TODO Stop the given server
}

37
go/ui/gcd.go

@ -1,17 +1,16 @@
package ui
import (
"encoding/base64"
"strconv"
"sync"
"cwtch.im/cwtch/app"
"cwtch.im/cwtch/event"
"cwtch.im/cwtch/model"
"cwtch.im/cwtch/model/attr"
"cwtch.im/cwtch/protocol/connections"
"cwtch.im/ui/go/constants"
"encoding/base64"
"github.com/therecipe/qt/qml"
"strconv"
"sync"
"cwtch.im/ui/go/the"
"encoding/base32"
@ -46,6 +45,8 @@ type GrandCentralDispatcher struct {
_ string `property:"assetPath"`
_ string `property:"selectedProfile,auto"`
_ string `property:"selectedConversation,auto"`
_ bool `property:experimentsEnabled,auto,changed`
_ map[string]bool `property:experiments,auto,changed`
// profile management stuff
_ func() `signal:"Loaded"`
@ -55,6 +56,10 @@ type GrandCentralDispatcher struct {
_ func() `signal:"ResetProfileList"`
_ func(failed bool) `signal:"ChangePasswordResponse"`
// server management
_ func(handle, displayname, image string, status int) `signal:"AddServer"`
_ func() `signal:"requestServers,auto"`
// contact list stuff
_ func(handle, displayName, image string, badge, status int, authorization string, loading bool, lastMsgTime int) `signal:"AddContact"`
_ func(handle, displayName string) `signal:"UpdateContactDisplayName"`
@ -130,6 +135,8 @@ func (this *GrandCentralDispatcher) init() {
this.GlobalSettings = ReadGlobalSettings()
this.SetThemeScale(this.GlobalSettings.Zoom)
this.SetTheme(this.GlobalSettings.Theme)
this.SetExperimentsEnabled(this.GlobalSettings.ExperimentsEnabled)
this.SetExperiments(this.GlobalSettings.Experiments)
}
// GetUiManager gets (and creates if required) a ui Manager for the supplied profile id
@ -377,6 +384,12 @@ func (this *GrandCentralDispatcher) requestServerSettings(groupID string) {
this.SupplyServerSettings(group.GroupServer, keyNames, keys)
}
func (this *GrandCentralDispatcher) requestServers() {
the.AppBus.Publish(event.NewEvent(constants.ListServers, map[event.Field]string{
}))
}
func (this *GrandCentralDispatcher) requestGroupSettings(groupID string) {
group := the.Peer.GetGroup(groupID)
@ -631,6 +644,22 @@ func (this *GrandCentralDispatcher) themeScaleChanged(newThemeScale float32) {
WriteGlobalSettings(this.GlobalSettings)
}
// Turn on/off global experiments
func (this *GrandCentralDispatcher) experimentsEnabledChanged(enabled bool) {
this.GlobalSettings.ExperimentsEnabled = enabled
log.Debugf("Experiments Enabled: %v %v", enabled, this.GlobalSettings.ExperimentsEnabled)
WriteGlobalSettings(this.GlobalSettings)
}
// Turn on/off global experiments
func (this *GrandCentralDispatcher) experimentsChanged(experiments map[string]bool) {
for k, v := range experiments {
this.GlobalSettings.Experiments[k] = v
}
log.Debugf("Experiments: %v", experiments)
WriteGlobalSettings(this.GlobalSettings)
}
func (this *GrandCentralDispatcher) themeChanged(newTheme string) {
this.GlobalSettings.Theme = newTheme
WriteGlobalSettings(this.GlobalSettings)

13
go/ui/settings.go

@ -16,10 +16,12 @@ const GlobalSettingsFilename = "ui.globals"
const saltFile = "SALT"
type GlobalSettings struct {
Zoom float32
Locale string
Theme string
PreviousPid int64
Zoom float32
Locale string
Theme string
PreviousPid int64
ExperimentsEnabled bool
Experiments map[string]bool
}
var DefaultGlobalSettings = GlobalSettings{
@ -27,6 +29,8 @@ var DefaultGlobalSettings = GlobalSettings{
Locale: "en",
Theme: "light",
PreviousPid: -1,
ExperimentsEnabled: false,
Experiments: make(map[string]bool),
}
func InitGlobalSettingsFile(directory string, password string) error {
@ -68,6 +72,7 @@ func ReadGlobalSettings() *GlobalSettings {
if err != nil {
log.Errorf("Could not parse global ui settings: %v\n", err)
}
log.Debugf("MAP: %v", settings.Experiments)
return &settings
}

4
main.go

@ -4,10 +4,11 @@ import (
"crypto/rand"
libapp "cwtch.im/cwtch/app"
"cwtch.im/cwtch/event"
"cwtch.im/cwtch/peer"
"cwtch.im/cwtch/event/bridge"
"cwtch.im/cwtch/peer"
"cwtch.im/ui/go/handlers"
os2 "cwtch.im/ui/go/os"
"cwtch.im/ui/go/servers"
"cwtch.im/ui/go/the"
"cwtch.im/ui/go/ui"
"cwtch.im/ui/go/ui/android"
@ -319,6 +320,7 @@ func loadNetworkingAndFiles(gcd *ui.GrandCentralDispatcher, service bool, client
the.AppBus = the.CwtchApp.GetPrimaryBus()
subscribed := make(chan bool)
go handlers.App(gcd, subscribed, clientUI)
go servers.LaunchServiceManager(gcd)
<-subscribed
}

12
qml/main.qml

@ -111,6 +111,7 @@ ApplicationWindow {
readonly property int settingsPane: 2
readonly property int addEditProfilePane: 3
readonly property int profilePane: 4
readonly property int addEditServerPane: 5
property alias pane: parentStack.currentIndex
Rectangle { // Splash pane
@ -164,7 +165,6 @@ ApplicationWindow {
}
}
RowLayout { // Profile Pane (contact list + overlays)
Layout.fillHeight: true
Layout.fillWidth: true
@ -251,7 +251,17 @@ ApplicationWindow {
}
}
Rectangle { // Server Add / Edit pane
Layout.fillHeight: true
Layout.fillWidth: true
color: Theme.backgroundPaneColor
ServerAddEditPane{
id: serverAddEditPane
anchors.fill: parent
}
}
focus: true
Keys.onPressed: {

3
qml/panes/ProfileManagerPane.qml

@ -16,6 +16,7 @@ import "../opaque/styles"
import "../opaque/theme"
import "../opaque/fonts"
import "../utils.js" as Utils
ColumnLayout {
id: thecol
@ -127,6 +128,8 @@ ColumnLayout {
}
Rectangle {
// TODO Remove Experiment Check once Feature is Stable
visible: gcd.experimentsEnabled && Utils.checkMap(gcd.experiments, "tapir-servers-experiment")
color: Theme.backgroundMainColor
Layout.fillHeight: true

63
qml/panes/ServerAddEditPane.qml

@ -0,0 +1,63 @@
import QtGraphicalEffects 1.0
import QtQuick 2.7
import QtQuick.Controls 2.13
import QtQuick.Controls.Material 2.0
import QtQuick.Layouts 1.3
import QtQuick.Window 2.11
import "../opaque" as Opaque
import "../opaque/theme"
// import "../styles"
Opaque.SettingsList { // Add Profile Pane
id: serverAddEditPane
anchors.fill: parent
function reset() {
serverAddEditPane.server_name = "";
serverAddEditPane.server_available = false;
}
property string server_name;
property bool server_available;
function load(server_onion, server_name, server_available) {
reset();
serverAddEditPane.server_name = server_name;
serverAddEditPane.server_available = server_available;
}
settings: Column {
anchors.horizontalCenter: parent.horizontalCenter
width: 700
Opaque.ScalingLabel {
text: server_name
size: 48
}
Opaque.Setting {
label: qsTr("server-availability")
field: Opaque.ToggleSwitch {
anchors.right: parent.right
isToggled: serverAddEditPane.server_available
onToggled: function() {
serverAddEditPane.serverAddEditPane = !serverAddEditPane
}
}
}
}
Connections { // UPDATE UNREAD MESSAGES COUNTER
target: gcd
}
}

63
qml/panes/SettingsPane.qml

@ -10,6 +10,8 @@ import QtQuick.Controls.Styles 1.4
import "../opaque" as Opaque
import "../opaque/controls"
import "../opaque/theme"
import "../widgets" as Widgets
import "../utils.js" as Utils
Opaque.SettingsList { // settingsPane
id: root
@ -118,6 +120,37 @@ Opaque.SettingsList { // settingsPane
}
}
// Experimental Gating
Opaque.Setting {
//: Theme
label: qsTr("experiments-enabled")
field: Opaque.ToggleSwitch {
anchors.right: parent.right
id: experimentsEnabledToggle
isToggled: gcd.experimentsEnabled
onToggled: function() {
console.log("experiments enabled: " + gcd.experimentsEnabled + " " + experimentsEnabledToggle.isToggled) ;
if (gcd.experimentsEnabled == false) {
gcd.experimentsEnabled = true;
} else {
gcd.experimentsEnabled = false;
}
}
}
}
Widgets.ExperimentToggle {
name: "servers_enabled"
experiment_id: "tapir-servers-experiment"
}
Widgets.ExperimentToggle {
name: "groups_enabled"
experiment_id: "tapir-groups-experiment"
}
}
@ -168,33 +201,3 @@ Opaque.SettingsList { // settingsPane
//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")
}
}
}
*/

16
qml/utils.js

@ -46,6 +46,22 @@ function isGridOccupied(x, y, points) {
return inPoints
}
function checkMap(obj, key) {
let map = buildMap(obj);
if (map[key] != undefined) {
return map[key];
}
return false
}
function buildMap(obj) {
let map = new Map();
Object.keys(obj).forEach(key => {
map[key] = obj[key];
});
return map;
}
function isGroup(id) {
return id.length == 32
}

24
qml/widgets/ExperimentToggle.qml

@ -0,0 +1,24 @@
import "../opaque" as Opaque
import "../opaque/controls"
import "../opaque/theme"
import "../utils.js" as Utils
Opaque.Setting {
//: Theme
id: experiment
property string name;
property string experiment_id;
visible: gcd.experimentsEnabled
label: qsTr(name)
field: Opaque.ToggleSwitch {
anchors.right: parent.right
id: expToggle
isToggled: Utils.checkMap(gcd.experiments, experiment.experiment_id)
onToggled: function() {
let experimentsMap = Utils.buildMap(gcd.experiments);
experimentsMap[experiment.experiment_id] = expToggle.isToggled ? false : true;
gcd.experiments = experimentsMap;
}
}
}

51
qml/widgets/ServerList.qml

@ -36,62 +36,54 @@ ColumnLayout {
Connections { // ADD/REMOVE CONTACT ENTRIES
target: gcd
onAddProfile: function(handle, displayName, image, tag) {
onLoaded: function() {
gcd.requestServers();
}
onAddServer: function(handle, displayName, image, status) {
// don't add duplicates
for (var i = 0; i < profilesModel.count; i++) {
if (profilesModel.get(i)["_handle"] == handle) {
for (var i = 0; i < serversModel.count; i++) {
if (serversModel.get(i)["_handle"] == handle) {
return
}
}
// find index for insert (sort by onion)
var index = profilesModel.count
for (var i = 0; i < profilesModel.count; i++) {
if (profilesModel.get(i)["_handle"] > handle) {
var index = serversModel.count
for (var i = 0; i < serversModel.count; i++) {
if (serversModel.get(i)["_handle"] > handle) {
index = i
break
}
}
profilesModel.insert(index,
serversModel.insert(index,
{
_handle: handle,
_displayName: displayName,
_image: image,
_tag: tag,
_status: 4,
_status: status,
})
}
/*
onRemoveProfile: function(handle) {
for(var i = 0; i < profilesModel.count; i++){
if(profilesModel.get(i)["_handle"] == handle) {
console.log("deleting contact " + profilesModel.get(i)["_handle"])
profilesModel.remove(i)
return
}
}
}*/
onResetProfileList: function() {
profilesModel.clear()
onResetServerList: function() {
serversModel.clear()
}
}
ListModel { // Profile OBJECTS ARE STORED HERE ...
id: profilesModel
id: serversModel
}
Repeater {
id: profileList
model: profilesModel // ... AND DISPLAYED HERE
delegate: ProfileRow {
id: serverList
model: serversModel // ... AND DISPLAYED HERE
delegate: ServerRow {
handle: _handle
displayName: _displayName
image: _image
tag: _tag
status: _status
Layout.fillWidth: true
}
}
@ -113,8 +105,11 @@ ColumnLayout {
}
badgeColor: Theme.defaultButtonColor
onClicked: function(handle) { profileAddEditPane.reset(); parentStack.pane = parentStack.addEditProfilePane }
onClicked: function(handle) { serverAddEditPane.reset(); parentStack.pane = parentStack.addEditServerPane }
}
}
}
}

60
qml/widgets/ServerRow.qml

@ -0,0 +1,60 @@
import QtGraphicalEffects 1.0
import QtQuick 2.7
import QtQuick.Controls 2.4
import QtQuick.Controls.Material 2.0
import QtQuick.Layouts 1.3
import CustomQmlTypes 1.0
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import "../opaque" as Opaque
import "../opaque/styles"
import "../opaque/theme"
Opaque.PortraitRow {
id: root
property int status;
portraitBorderColor: Theme.portraitOnlineBorderColor
portraitColor: Theme.portraitOnlineBackgroundColor
nameColor: Theme.portraitOnlineTextColor
onionColor: Theme.portraitOnlineTextColor
badgeColor: status == 4 ? Theme.portraitOnlineBadgeColor : Theme.portraitOfflineBadgeColor
badgeVisible: true
Opaque.Icon {// Edit BUTTON
id: btnEdit
source: gcd.assetPath + "core/edit-24px.svg"
backgroundColor: root.color
iconColor: Theme.altTextColor
anchors.right: parent.right
//rectUnread.left
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 1 * gcd.themeScale
anchors.rightMargin: 20 * gcd.themeScale
height: parent.height * 0.5
width: parent.height * 0.5
size: parent.height * 0.5
onClicked: {
serverAddEditPane.load(handle, displayName, status)
parentStack.pane = parentStack.addEditServerPane
}
onHover: function (hover) {
root.isHover = hover
}
}
onClicked: function openClick(handle) {
}
}