mirror of
https://git.jami.net/savoirfairelinux/jami-client-qt.git
synced 2025-04-22 06:02:03 +02:00
misc: save split view states
This commit simplifies the view coordinator and restructures the main view stack to not include a split view. This removes workaround logic for single pane view support that was previously in the view coordinator. The main view is now a stack that may contain both single and dual pane views. The ListSelectionView further specializes DualPaneView to add an index-based or custom selection mechanism. Gitlab: #902 Change-Id: I81c9fe579b95c8d4774c3e491a16d7600323c40c
This commit is contained in:
parent
f5f5ae13ab
commit
9ff32433cf
29 changed files with 1027 additions and 888 deletions
|
@ -89,7 +89,7 @@ ApplicationWindow {
|
|||
!UtilsAdapter.getAccountListSize()) {
|
||||
// Save the window geometry and state before quitting.
|
||||
layoutManager.saveWindowSettings()
|
||||
viewCoordinator.dismissAll()
|
||||
viewCoordinator.deinit()
|
||||
Qt.quit()
|
||||
} else {
|
||||
layoutManager.closeToTray()
|
||||
|
@ -160,11 +160,13 @@ ApplicationWindow {
|
|||
|
||||
// Present the welcome view once the viewCoordinator is setup.
|
||||
viewCoordinator.initialized.connect(function() {
|
||||
viewCoordinator.preload("SidePanel")
|
||||
viewCoordinator.preload("SettingsSidePanel")
|
||||
viewCoordinator.present("WelcomePage")
|
||||
viewCoordinator.preload("ConversationView")
|
||||
})
|
||||
// Set the viewCoordinator's root item.
|
||||
viewCoordinator.setRootView(item)
|
||||
viewCoordinator.init(item)
|
||||
}
|
||||
if (Qt.platform.os.toString() === "osx") {
|
||||
MainApplication.setEventFilter()
|
||||
|
|
|
@ -22,104 +22,54 @@ import QtQuick.Layouts
|
|||
import net.jami.Constants 1.1
|
||||
import net.jami.Models 1.1
|
||||
|
||||
// This object should be implemented as a QML singleton, or be instantiated
|
||||
// once in the main application window component. The top-level application window
|
||||
// contains a loader[mainview, wizardview] and "rootView" MUST parent a horizontal
|
||||
// SplitView with a StackView in each pane.
|
||||
import "commoncomponents"
|
||||
|
||||
QtObject {
|
||||
id: root
|
||||
|
||||
required property QtObject viewManager
|
||||
|
||||
signal initialized
|
||||
signal requestAppWindowWizardView
|
||||
|
||||
// A map of view names to file paths for QML files that define each view.
|
||||
property variant resources: {
|
||||
"WelcomePage": "mainview/components/WelcomePage.qml",
|
||||
"SidePanel": "mainview/components/SidePanel.qml",
|
||||
"WelcomePage": "mainview/components/WelcomePage.qml",
|
||||
"ConversationView": "mainview/ConversationView.qml",
|
||||
"NewSwarmPage": "mainview/components/NewSwarmPage.qml",
|
||||
"WizardView": "wizardview/WizardView.qml",
|
||||
"SettingsView": "settingsview/SettingsView.qml",
|
||||
"SettingsSidePanel": "settingsview/SettingsSidePanel.qml",
|
||||
}
|
||||
|
||||
// Maybe this state needs to be toggled because the SidePanel content is replaced.
|
||||
// This makes it so the state can't be inferred from loaded views in single pane mode.
|
||||
property bool inSettings: viewManager.hasView("SettingsView")
|
||||
property bool inWizard: viewManager.hasView("WizardView")
|
||||
property bool inNewSwarm: viewManager.hasView("NewSwarmPage")
|
||||
property bool inhibitConversationView: inSettings || inWizard || inNewSwarm
|
||||
|
||||
property bool busy: false
|
||||
|
||||
// The `main` view of the application window.
|
||||
property Item rootView: null
|
||||
property StackView rootView
|
||||
|
||||
// HACKS.
|
||||
property real mainViewWidth: rootView ? rootView.width : 0
|
||||
property real previousWidth: mainViewWidth
|
||||
property real mainViewSidePanelRectWidth: sv1 ? sv1.width : 0
|
||||
property real lastSideBarSplitSize: mainViewSidePanelRectWidth
|
||||
onMainViewWidthChanged: resolvePanes()
|
||||
property var currentViewName: rootView && rootView.currentItem.objectName || null
|
||||
|
||||
function resolvePanes(force=false) {
|
||||
if (forceSinglePane) return
|
||||
const isExpanding = previousWidth < mainViewWidth
|
||||
if (mainViewWidth < JamiTheme.chatViewHeaderMinimumWidth + mainViewSidePanelRectWidth
|
||||
&& sv2.visible && (!isExpanding || force)) {
|
||||
lastSideBarSplitSize = mainViewSidePanelRectWidth
|
||||
singlePane = true
|
||||
} else if (mainViewWidth >= lastSideBarSplitSize + JamiTheme.chatViewHeaderMinimumWidth
|
||||
&& !sv2.visible && (isExpanding || force) && !layoutManager.isFullScreen) {
|
||||
singlePane = false
|
||||
function init(appWindow) {
|
||||
rootView = Qt.createQmlObject(`import QtQuick; import QtQuick.Controls
|
||||
StackView { anchors.fill: parent }`,
|
||||
appWindow)
|
||||
initialized()
|
||||
}
|
||||
|
||||
function deinit() {
|
||||
viewManager.destroyAllViews()
|
||||
rootView.destroy()
|
||||
}
|
||||
|
||||
// Finds a view and gets its index within the StackView it's in.
|
||||
function getStackIndex(viewName) {
|
||||
for (const [key, value] of Object.entries(viewManager.views)) {
|
||||
if (value.objectName === viewName) {
|
||||
return value.StackView.index
|
||||
}
|
||||
}
|
||||
previousWidth = mainViewWidth
|
||||
return -1
|
||||
}
|
||||
|
||||
// Must be the child of `rootView`.
|
||||
property Item splitView: null
|
||||
|
||||
// StackView objects, which are children of `splitView`.
|
||||
property StackView sv1: null
|
||||
property StackView sv2: null
|
||||
|
||||
// The StackView object that is currently active, determined by the value
|
||||
// of singlePane.
|
||||
readonly property StackView activeStackView: singlePane ? sv1 : sv2
|
||||
|
||||
readonly property string currentViewName: {
|
||||
if (activeStackView == null || activeStackView.depth === 0) return ''
|
||||
return activeStackView.currentItem.objectName
|
||||
}
|
||||
|
||||
readonly property var currentView: {
|
||||
return activeStackView ? activeStackView.currentItem : null
|
||||
}
|
||||
|
||||
// Handle single/dual pane mode.
|
||||
property bool forceSinglePane: false
|
||||
property bool singlePane
|
||||
onForceSinglePaneChanged: {
|
||||
if (forceSinglePane) singlePane = true
|
||||
else resolvePanes(true)
|
||||
}
|
||||
|
||||
onSinglePaneChanged: {
|
||||
// Hiding sv2 before moving items from, and after moving
|
||||
// items to, reduces stack item visibility change events.
|
||||
if (singlePane) {
|
||||
sv2.visible = false
|
||||
if (forceSinglePane) Qt.callLater(move, sv2, sv1)
|
||||
else move(sv2, sv1)
|
||||
} else {
|
||||
move(sv1, sv2)
|
||||
sv2.visible = true
|
||||
}
|
||||
}
|
||||
|
||||
// Emitted once at the end of setRootView.
|
||||
signal initialized()
|
||||
|
||||
// Create, present, and return a dialog object.
|
||||
function presentDialog(parent, path, props={}) {
|
||||
// Open the dialog once the object is created
|
||||
|
@ -135,120 +85,42 @@ QtObject {
|
|||
}, props)
|
||||
}
|
||||
|
||||
// Dismiss all views.
|
||||
function dismissAll() {
|
||||
for (var path in viewManager.views) {
|
||||
viewManager.destroyView(path)
|
||||
}
|
||||
}
|
||||
// Present a view by name.
|
||||
function present(viewName, props) {
|
||||
const path = resources[viewName]
|
||||
|
||||
// Get a view regardless of whether it is currently active.
|
||||
function getView(viewName) {
|
||||
if (!viewManager.hasView(viewName)) {
|
||||
return null
|
||||
}
|
||||
return viewManager.views[viewManager.viewPaths[viewName]]
|
||||
}
|
||||
|
||||
// Sets object references, onInitialized is a good time to present views.
|
||||
function setRootView(obj) {
|
||||
rootView = obj
|
||||
splitView = rootView.splitView
|
||||
sv1 = rootView.sv1
|
||||
sv1.parent = Qt.binding(() => singlePane ? rootView : splitView)
|
||||
sv1.anchors.fill = Qt.binding(() => singlePane ? rootView : undefined)
|
||||
sv2 = rootView.sv2
|
||||
|
||||
initialized()
|
||||
resolvePanes()
|
||||
}
|
||||
|
||||
// Finds a view and gets its index within the StackView it's in.
|
||||
function getStackIndex(viewName) {
|
||||
for (const [key, value] of Object.entries(viewManager.views)) {
|
||||
if (value.objectName === viewName) {
|
||||
return value.StackView.index
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Load a view without presenting it.
|
||||
function preload(viewName) {
|
||||
if (!viewManager.createView(resources[viewName], null)) {
|
||||
console.log("Failed to load view: " + viewName)
|
||||
}
|
||||
}
|
||||
|
||||
// This function presents the view with the given viewName in the
|
||||
// specified StackView. Return the view if successful.
|
||||
function present(viewName, sv=activeStackView) {
|
||||
if (!rootView) return
|
||||
|
||||
if (viewName === "ConversationView" && inhibitConversationView) {
|
||||
// Check if the current view should inhibit the presentation of this view.
|
||||
if (rootView.currentItem && rootView.currentItem.inhibits.includes(viewName)) {
|
||||
print("inhibiting view:", viewName)
|
||||
return
|
||||
}
|
||||
|
||||
// If the view already exists in the StackView, the function will attempt
|
||||
// to navigate to its StackView position by dismissing elevated views.
|
||||
if (sv.find(function(item) {
|
||||
if (rootView.find(function(item) {
|
||||
return item.objectName === viewName;
|
||||
})) {
|
||||
}, StackView.DontLoad)) {
|
||||
const viewIndex = getStackIndex(viewName)
|
||||
if (viewIndex >= 0) {
|
||||
for (var i = (sv.depth - 1); i > viewIndex; i--) {
|
||||
dismissObj(sv.get(i, StackView.DontLoad))
|
||||
}
|
||||
return true
|
||||
for (var i = (rootView.depth - 1); i > viewIndex; i--) {
|
||||
dismissObj(rootView.get(i, StackView.DontLoad))
|
||||
}
|
||||
return false
|
||||
return
|
||||
}
|
||||
|
||||
// If we are in single-pane mode and the view was previously forced into
|
||||
// sv2, we can move it back to the top of sv1.
|
||||
if (singlePane && sv === sv1) {
|
||||
// See if the item is at the top of sv2
|
||||
if (sv2.currentItem && sv2.currentItem.objectName === viewName) {
|
||||
// Move it to the top of sv1
|
||||
const view = sv2.pop(StackView.Immediate)
|
||||
sv1.push(view, StackView.Immediate)
|
||||
view.presented()
|
||||
return view
|
||||
if (!viewManager.createView(path, rootView, function(view) {
|
||||
// push the view onto the stack if it's not already there
|
||||
if (rootView.currentItem !== view) {
|
||||
rootView.push(view, StackView.Immediate)
|
||||
}
|
||||
}
|
||||
|
||||
const obj = viewManager.createView(resources[viewName], appWindow)
|
||||
if (!obj) {
|
||||
if (!view.managed) view.presented()
|
||||
}, props)) {
|
||||
print("could not create view:", viewName)
|
||||
return null
|
||||
}
|
||||
if (obj === currentView) {
|
||||
print("view is current:", viewName)
|
||||
return null
|
||||
}
|
||||
|
||||
// If we are in single-pane mode and the view should start hidden
|
||||
// (requiresIndex), we can push it into sv2.
|
||||
if (singlePane && sv === sv1 && obj.requiresIndex) {
|
||||
sv = sv2
|
||||
} else {
|
||||
forceSinglePane = obj.singlePaneOnly
|
||||
}
|
||||
|
||||
const view = sv.push(obj, StackView.Immediate)
|
||||
if (!view) {
|
||||
return null
|
||||
}
|
||||
if (view.objectName === '') {
|
||||
view.objectName = viewName
|
||||
}
|
||||
view.presented()
|
||||
return view
|
||||
}
|
||||
|
||||
// Dismiss by object.
|
||||
function dismissObj(obj, sv=activeStackView) {
|
||||
if (obj.StackView.view !== sv) {
|
||||
function dismissObj(obj) {
|
||||
if (obj.StackView.view !== rootView) {
|
||||
print("view not in the stack:", obj)
|
||||
return
|
||||
}
|
||||
|
@ -256,27 +128,28 @@ QtObject {
|
|||
// If we are dismissing a view that is not at the top of the stack,
|
||||
// we need to store each of the views on top into a temporary stack
|
||||
// and then restore them after the view is dismissed.
|
||||
// So we get the index of the view we are dismissing.
|
||||
const viewIndex = obj.StackView.index
|
||||
var tempStack = []
|
||||
for (var i = (sv.depth - 1); i > viewIndex; i--) {
|
||||
var item = sv.pop(StackView.Immediate)
|
||||
for (var i = (rootView.depth - 1); i > viewIndex; i--) {
|
||||
var item = rootView.pop(StackView.Immediate)
|
||||
tempStack.push(item)
|
||||
}
|
||||
// And we define a function to restore and resolve the views.
|
||||
var resolveStack = () => {
|
||||
for (var i = 0; i < tempStack.length; i++) {
|
||||
sv.push(tempStack[i], StackView.Immediate)
|
||||
rootView.push(tempStack[i], StackView.Immediate)
|
||||
}
|
||||
|
||||
forceSinglePane = sv.currentItem.singlePaneOnly
|
||||
sv.currentItem.presented()
|
||||
if (rootView.depth > 0) rootView.currentItem.presented()
|
||||
}
|
||||
|
||||
// Now we can dismiss the view at the top of the stack.
|
||||
const depth = sv.depth
|
||||
if (obj === sv.get(depth - 1, StackView.DontLoad)) {
|
||||
var view = sv.pop(StackView.Immediate)
|
||||
const depth = rootView.depth
|
||||
if (obj === rootView.get(depth - 1, StackView.DontLoad)) {
|
||||
var view
|
||||
if (rootView.depth === 1) {
|
||||
view = rootView.currentItem
|
||||
rootView.clear()
|
||||
} else view = rootView.pop(StackView.Immediate)
|
||||
if (!view) {
|
||||
print("could not pop view:", obj.objectName)
|
||||
resolveStack()
|
||||
|
@ -290,51 +163,37 @@ QtObject {
|
|||
if (!viewManager.destroyView(resources[objectName])) {
|
||||
print("could not destroy view:", objectName)
|
||||
}
|
||||
} else {
|
||||
view.dismissed()
|
||||
}
|
||||
} else view.dismissed()
|
||||
}
|
||||
resolveStack()
|
||||
}
|
||||
|
||||
// Dismiss by view name.
|
||||
function dismiss(viewName) {
|
||||
if (!rootView) return
|
||||
|
||||
const depth = activeStackView.depth
|
||||
for (var i = (depth - 1); i >= 0; i--) {
|
||||
const view = activeStackView.get(i, StackView.DontLoad)
|
||||
if (view.objectName === viewName) {
|
||||
dismissObj(view)
|
||||
return
|
||||
// Dismiss a view by name or the top view if unspecified.
|
||||
function dismiss(viewName=undefined) {
|
||||
if (!rootView || rootView.depth === 0) return
|
||||
if (viewName !== undefined) {
|
||||
const depth = rootView.depth
|
||||
for (var i = (depth - 1); i >= 0; i--) {
|
||||
const view = rootView.get(i, StackView.DontLoad)
|
||||
if (view.objectName === viewName) {
|
||||
dismissObj(view)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the view is hidden on the top of sv2 (if in single-pane mode),
|
||||
// and dismiss it in that case.
|
||||
if (singlePane && sv2.currentItem && sv2.currentItem.objectName === viewName) {
|
||||
dismissObj(sv2.currentItem, sv2)
|
||||
return
|
||||
} else {
|
||||
dismissObj(rootView.currentItem)
|
||||
}
|
||||
}
|
||||
|
||||
// Move items from one stack to another. We avoid the recursive technique to
|
||||
// avoid visibility change events.
|
||||
function move(from, to, depth=1) {
|
||||
busy = true
|
||||
var tempStack = []
|
||||
while (from.depth > depth) {
|
||||
var item = from.pop(StackView.Immediate)
|
||||
tempStack.push(item)
|
||||
}
|
||||
while (tempStack.length) {
|
||||
to.push(tempStack.pop(), StackView.Immediate)
|
||||
}
|
||||
busy = false
|
||||
function getView(viewName) {
|
||||
return viewManager.getView(viewName)
|
||||
}
|
||||
|
||||
// Effectively hide the current view by moving it to the other StackView.
|
||||
// This function only works when in single-pane mode.
|
||||
function hideCurrentView() {
|
||||
if (singlePane) move(sv1, sv2)
|
||||
}
|
||||
// Load a view without presenting it.
|
||||
function preload(viewName) {
|
||||
if (!viewManager.createView(resources[viewName], null)) {
|
||||
console.log("Failed to load view: " + viewName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,9 +27,19 @@ QtObject {
|
|||
// The number of views.
|
||||
property int nViews: 0
|
||||
|
||||
// Destroy all views.
|
||||
function destroyAllViews() {
|
||||
for (var path in views) {
|
||||
destroyView(path)
|
||||
}
|
||||
}
|
||||
|
||||
function createView(path, parent=null, cb=null, props={}) {
|
||||
if (views[path] !== undefined) {
|
||||
// an instance of <path> already exists
|
||||
if (cb !== null) {
|
||||
cb(views[path])
|
||||
}
|
||||
return views[path]
|
||||
}
|
||||
|
||||
|
@ -84,4 +94,8 @@ QtObject {
|
|||
function hasView(viewName) {
|
||||
return nViews && viewPaths[viewName] !== undefined
|
||||
}
|
||||
|
||||
function getView(viewName) {
|
||||
return views[viewPaths[viewName]] || null
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,9 +40,9 @@ AppSettingsManager::AppSettingsManager(QObject* parent)
|
|||
}
|
||||
|
||||
QVariant
|
||||
AppSettingsManager::getValue(const Settings::Key key)
|
||||
AppSettingsManager::getValue(const QString& key, const QVariant& defaultValue)
|
||||
{
|
||||
auto value = settings_->value(Settings::toString(key), Settings::defaultValue(key));
|
||||
auto value = settings_->value(key, defaultValue);
|
||||
|
||||
if (QString(value.typeName()) == "QString"
|
||||
&& (value.toString() == "false" || value.toString() == "true"))
|
||||
|
@ -51,10 +51,22 @@ AppSettingsManager::getValue(const Settings::Key key)
|
|||
return value;
|
||||
}
|
||||
|
||||
void
|
||||
AppSettingsManager::setValue(const QString& key, const QVariant& value)
|
||||
{
|
||||
settings_->setValue(key, value);
|
||||
}
|
||||
|
||||
QVariant
|
||||
AppSettingsManager::getValue(const Settings::Key key)
|
||||
{
|
||||
return getValue(Settings::toString(key), Settings::defaultValue(key));
|
||||
}
|
||||
|
||||
void
|
||||
AppSettingsManager::setValue(const Settings::Key key, const QVariant& value)
|
||||
{
|
||||
settings_->setValue(Settings::toString(key), value);
|
||||
setValue(Settings::toString(key), value);
|
||||
}
|
||||
|
||||
QString
|
||||
|
|
|
@ -109,8 +109,12 @@ public:
|
|||
explicit AppSettingsManager(QObject* parent = nullptr);
|
||||
~AppSettingsManager() = default;
|
||||
|
||||
Q_INVOKABLE QVariant getValue(const QString& key, const QVariant& defaultValue = {});
|
||||
Q_INVOKABLE void setValue(const QString& key, const QVariant& value = {});
|
||||
|
||||
Q_INVOKABLE QVariant getValue(const Settings::Key key);
|
||||
Q_INVOKABLE void setValue(const Settings::Key key, const QVariant& value);
|
||||
Q_INVOKABLE void setValue(const Settings::Key key, const QVariant& value = {});
|
||||
|
||||
QString getLanguage();
|
||||
|
||||
void loadTranslations();
|
||||
|
|
|
@ -25,12 +25,8 @@ Rectangle {
|
|||
// only be destroyed when its parent is destroyed.
|
||||
property bool managed: true
|
||||
|
||||
// True if this view functions in a single-pane context only.
|
||||
property bool singlePaneOnly: false
|
||||
|
||||
// True if this view requires and initial selection from
|
||||
// a group of menu options when in single-pane mode (e.g. settings).
|
||||
property bool requiresIndex: false
|
||||
// A list of view names that this view inhibits the presentation of.
|
||||
property var inhibits: []
|
||||
|
||||
function dismiss() { viewCoordinator.dismiss(objectName) }
|
||||
|
||||
|
|
88
src/app/commoncomponents/DualPaneView.qml
Normal file
88
src/app/commoncomponents/DualPaneView.qml
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Savoir-faire Linux Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
|
||||
BaseView {
|
||||
id: viewNode
|
||||
|
||||
required property Item leftPaneItem
|
||||
required property Item rightPaneItem
|
||||
|
||||
property alias leftPane: leftPane
|
||||
property alias rightPane: rightPane
|
||||
|
||||
property alias splitViewStateKey: splitView.splitViewStateKey
|
||||
|
||||
property real leftPaneMinWidth: JamiTheme.mainViewLeftPaneMinWidth
|
||||
property real rightPaneMinWidth: JamiTheme.mainViewPaneMinWidth
|
||||
|
||||
property bool isSinglePane
|
||||
|
||||
onPresented: {
|
||||
leftPaneItem.parent = leftPane
|
||||
rightPaneItem.parent = rightPane
|
||||
|
||||
splitView.restoreSplitViewState()
|
||||
|
||||
resolvePanes()
|
||||
}
|
||||
onDismissed: splitView.saveSplitViewState()
|
||||
|
||||
Component.onCompleted: {
|
||||
// Avoid double triggering this handler during instantiation.
|
||||
onIsSinglePaneChanged.connect(isSinglePaneChangedHandler)
|
||||
}
|
||||
|
||||
property real previousLeftPaneWidth: leftPane.width
|
||||
onWidthChanged: resolvePanes()
|
||||
function resolvePanes() {
|
||||
isSinglePane = width < rightPaneMinWidth + previousLeftPaneWidth
|
||||
}
|
||||
|
||||
// Override this if needed.
|
||||
property var isSinglePaneChangedHandler: function() {
|
||||
rightPaneItem.parent = isSinglePane ? leftPane : rightPane
|
||||
}
|
||||
|
||||
JamiSplitView {
|
||||
id: splitView
|
||||
anchors.fill: parent
|
||||
splitViewStateKey: viewNode.objectName
|
||||
|
||||
Item {
|
||||
id: leftPane
|
||||
onWidthChanged: if (!isSinglePane) previousLeftPaneWidth = width
|
||||
SplitView.minimumWidth: isSinglePane ?
|
||||
viewNode.width :
|
||||
viewNode.leftPaneMinWidth
|
||||
SplitView.maximumWidth: isSinglePane ?
|
||||
viewNode.width :
|
||||
viewNode.width - rightPaneMinWidth
|
||||
SplitView.preferredWidth: viewNode.leftPaneMinWidth
|
||||
clip: true
|
||||
}
|
||||
Item {
|
||||
id: rightPane
|
||||
clip: true
|
||||
}
|
||||
}
|
||||
}
|
54
src/app/commoncomponents/JamiSplitView.qml
Normal file
54
src/app/commoncomponents/JamiSplitView.qml
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Savoir-faire Linux Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
|
||||
SplitView {
|
||||
id: root
|
||||
|
||||
property string splitViewStateKey: objectName
|
||||
property bool autoManageState: !(parent instanceof BaseView)
|
||||
|
||||
function saveSplitViewState() {
|
||||
UtilsAdapter.setAppValue("sv_" + splitViewStateKey, root.saveState())
|
||||
}
|
||||
|
||||
function restoreSplitViewState() {
|
||||
root.restoreState(UtilsAdapter.getAppValue("sv_" + splitViewStateKey))
|
||||
}
|
||||
|
||||
onResizingChanged: if (!resizing) saveSplitViewState()
|
||||
onVisibleChanged: {
|
||||
if (!autoManageState) return
|
||||
visible ? restoreSplitViewState() : saveSplitViewState()
|
||||
}
|
||||
|
||||
handle: Rectangle {
|
||||
implicitWidth: JamiTheme.splitViewHandlePreferredWidth
|
||||
implicitHeight: root.height
|
||||
color: JamiTheme.primaryBackgroundColor
|
||||
Rectangle {
|
||||
implicitWidth: 1
|
||||
implicitHeight: root.height
|
||||
color: JamiTheme.tabbarBorderColor
|
||||
}
|
||||
}
|
||||
}
|
88
src/app/commoncomponents/ListSelectionView.qml
Normal file
88
src/app/commoncomponents/ListSelectionView.qml
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Savoir-faire Linux Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick
|
||||
|
||||
DualPaneView {
|
||||
id: viewNode
|
||||
|
||||
property bool hideRightPaneInSinglePaneMode : false
|
||||
|
||||
Component.onCompleted: {
|
||||
if (hideRightPaneInSinglePaneMode) return
|
||||
onIndexChanged.connect(function() {
|
||||
if (hasValidSelection) {
|
||||
if (selectionFallback && isSinglePane)
|
||||
rightPaneItem.parent = leftPane
|
||||
return
|
||||
}
|
||||
if (!isSinglePane) dismiss()
|
||||
else isSinglePaneChangedHandler()
|
||||
})
|
||||
}
|
||||
|
||||
// True if we should dismiss to the left pane if in single pane mode.
|
||||
// Also causes selection of a default index (0) in dual pane mode.
|
||||
property bool selectionFallback: false
|
||||
|
||||
// When this property is set, the view updates its display to show the
|
||||
// corresponding item if `hasValidSelection` has no override.
|
||||
property int index: -1
|
||||
function selectIndex(index) { viewNode.index = index }
|
||||
|
||||
// Override this predicate if needed.
|
||||
property bool hasValidSelection: viewNode.index >= 0
|
||||
onHasValidSelectionChanged: isSinglePaneChangedHandler()
|
||||
|
||||
// Override BaseView.dismiss with some selection logic.
|
||||
function dismiss() {
|
||||
if (isSinglePane) {
|
||||
if (!selectionFallback) viewCoordinator.dismiss(objectName)
|
||||
else if (isSinglePane && leftPane.children.length > 1) {
|
||||
rightPaneItem.parent = null
|
||||
leftPaneItem.deselect()
|
||||
}
|
||||
} else viewCoordinator.dismiss(objectName)
|
||||
}
|
||||
|
||||
onPresented: isSinglePaneChangedHandler()
|
||||
|
||||
onDismissed: {
|
||||
if (leftPaneItem) {
|
||||
leftPaneItem.indexSelected.disconnect(selectIndex)
|
||||
leftPaneItem.deselect()
|
||||
}
|
||||
}
|
||||
|
||||
onLeftPaneItemChanged: {
|
||||
if (leftPaneItem) leftPaneItem.indexSelected.connect(selectIndex)
|
||||
}
|
||||
isSinglePaneChangedHandler: () => {
|
||||
if (hideRightPaneInSinglePaneMode) return
|
||||
// When transitioning from split to single pane, we need to move
|
||||
// the right pane item to left stack view if it has a valid index.
|
||||
if (isSinglePane) {
|
||||
if (hasValidSelection) {
|
||||
rightPaneItem.parent = leftPane
|
||||
}
|
||||
} else {
|
||||
rightPaneItem.parent = rightPane
|
||||
// We may need a default selection of item 0 here.
|
||||
if (!hasValidSelection && selectionFallback) leftPaneItem.select(0)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
import QtQuick
|
||||
|
||||
import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
|
||||
// This component is used to display and edit a value.
|
||||
|
@ -32,6 +33,7 @@ Loader {
|
|||
required property string placeholderText
|
||||
property string staticText: ""
|
||||
property string dynamicText
|
||||
|
||||
property bool inputIsValid: true
|
||||
property string infoTipText
|
||||
property bool isPersistent: true
|
||||
|
|
14
src/app/commoncomponents/SidePanelBase.qml
Normal file
14
src/app/commoncomponents/SidePanelBase.qml
Normal file
|
@ -0,0 +1,14 @@
|
|||
import QtQuick
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
// Override these if needed.
|
||||
property var select: function() {}
|
||||
property var deselect: function() {}
|
||||
|
||||
signal indexSelected(int index)
|
||||
signal deselected
|
||||
}
|
|
@ -290,6 +290,8 @@ Item {
|
|||
|
||||
|
||||
// Sizes
|
||||
property real mainViewLeftPaneMinWidth: 300
|
||||
property real mainViewPaneMinWidth: 430
|
||||
property real qrCodeImageSize: 256
|
||||
property real splitViewHandlePreferredWidth: 4
|
||||
property real indicatorFontSize: calcSize(6)
|
||||
|
@ -421,7 +423,6 @@ Item {
|
|||
property real chatViewHairLineSize: 1
|
||||
property real chatViewMaximumWidth: 900
|
||||
property real chatViewHeaderPreferredHeight: 64
|
||||
property real chatViewHeaderMinimumWidth: 430
|
||||
property real chatViewFooterPreferredHeight: 50
|
||||
property real chatViewFooterMaximumHeight: 280
|
||||
property real chatViewFooterRowSpacing: 1
|
||||
|
|
|
@ -69,6 +69,7 @@ public:
|
|||
CurrentConversationMembers* uris() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void reloadInteractions();
|
||||
void scrollTo(const QString& msgId);
|
||||
void showDetails();
|
||||
|
||||
|
|
|
@ -27,15 +27,19 @@ import net.jami.Constants 1.1
|
|||
import "../commoncomponents"
|
||||
import "components"
|
||||
|
||||
BaseView {
|
||||
id: root
|
||||
ListSelectionView {
|
||||
id: viewNode
|
||||
objectName: "ConversationView"
|
||||
managed: false
|
||||
|
||||
onPresented: {
|
||||
if (!visible && viewCoordinator.singlePane &&
|
||||
CurrentConversation.id !== '') {
|
||||
viewCoordinator.present(objectName)
|
||||
splitViewStateKey: "Main"
|
||||
hasValidSelection: CurrentConversation.id !== ''
|
||||
|
||||
Connections {
|
||||
target: CurrentConversation
|
||||
function onReloadInteractions() {
|
||||
UtilsAdapter.clearInteractionsCache(CurrentAccount.id, CurrentConversation.id)
|
||||
MessagesAdapter.loadMoreMessages()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,13 +58,15 @@ BaseView {
|
|||
|
||||
color: JamiTheme.transparentColor
|
||||
|
||||
StackLayout {
|
||||
leftPaneItem: viewCoordinator.getView("SidePanel")
|
||||
|
||||
rightPaneItem: StackLayout {
|
||||
currentIndex: !CurrentConversation.hasCall ? 0 : 1
|
||||
onCurrentIndexChanged: chatView.parent = currentIndex == 1 ?
|
||||
onCurrentIndexChanged: chatView.parent = currentIndex === 1 ?
|
||||
callStackView.chatViewContainer :
|
||||
chatViewContainer
|
||||
|
||||
anchors.fill: root
|
||||
anchors.fill: parent
|
||||
|
||||
Item {
|
||||
id: chatViewContainer
|
||||
|
@ -86,7 +92,7 @@ BaseView {
|
|||
|
||||
onDismiss: {
|
||||
if (parent == chatViewContainer) {
|
||||
root.dismiss()
|
||||
viewNode.dismiss()
|
||||
} else {
|
||||
callStackView.chatViewContainer.visible = false
|
||||
callStackView.contentView.forceActiveFocus()
|
||||
|
|
|
@ -59,48 +59,6 @@ Rectangle {
|
|||
onWidthChanged: Qt.callLater(JamiQmlUtils.updateMessageBarButtonsPoints)
|
||||
onHeightChanged: Qt.callLater(JamiQmlUtils.updateMessageBarButtonsPoints)
|
||||
|
||||
// Needed by ViewCoordinator.
|
||||
property alias splitView: splitView
|
||||
property alias sv1: sv1
|
||||
property alias sv2: sv2
|
||||
|
||||
StackView {
|
||||
id: mainStackView
|
||||
anchors.fill: parent
|
||||
|
||||
initialItem: SplitView {
|
||||
id: splitView
|
||||
|
||||
handle: Rectangle {
|
||||
implicitWidth: JamiTheme.splitViewHandlePreferredWidth
|
||||
implicitHeight: splitView.height
|
||||
color: JamiTheme.primaryBackgroundColor
|
||||
Rectangle {
|
||||
implicitWidth: 1
|
||||
implicitHeight: splitView.height
|
||||
color: JamiTheme.tabbarBorderColor
|
||||
}
|
||||
}
|
||||
|
||||
StackView {
|
||||
id: sv1
|
||||
objectName: "sv1"
|
||||
SplitView.minimumWidth: 300
|
||||
SplitView.preferredWidth: 300
|
||||
SplitView.fillHeight: true
|
||||
clip: true
|
||||
initialItem: SidePanel {}
|
||||
}
|
||||
|
||||
StackView {
|
||||
id: sv2
|
||||
objectName: "sv2"
|
||||
SplitView.fillHeight: true
|
||||
clip: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
JamiQmlUtils.mainViewRectObj = mainView
|
||||
}
|
||||
|
|
|
@ -30,9 +30,13 @@ import "../../commoncomponents"
|
|||
Label {
|
||||
id: root
|
||||
|
||||
signal settingBtnClicked
|
||||
property alias popup: comboBoxPopup
|
||||
|
||||
width: parent ? parent.width : o
|
||||
height: JamiTheme.accountListItemHeight
|
||||
|
||||
property bool inSettings: viewCoordinator.currentViewName === "SettingsView"
|
||||
|
||||
// TODO: remove these refresh hacks use QAbstractItemModels correctly
|
||||
Connections {
|
||||
target: AccountAdapter
|
||||
|
@ -86,6 +90,7 @@ Label {
|
|||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
enabled: visible
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
|
@ -206,18 +211,20 @@ Label {
|
|||
id: settingsButton
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
source: !viewCoordinator.inSettings ?
|
||||
source: !inSettings ?
|
||||
JamiResources.settings_24dp_svg :
|
||||
JamiResources.round_close_24dp_svg
|
||||
|
||||
normalColor: JamiTheme.backgroundColor
|
||||
imageColor: JamiTheme.textColor
|
||||
toolTipText: !viewCoordinator.inSettings ?
|
||||
toolTipText: !inSettings ?
|
||||
JamiStrings.openSettings :
|
||||
JamiStrings.closeSettings
|
||||
|
||||
onClicked: {
|
||||
settingBtnClicked()
|
||||
!inSettings ?
|
||||
viewCoordinator.present("SettingsView") :
|
||||
viewCoordinator.dismiss("SettingsView")
|
||||
background.state = "normal"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ Rectangle {
|
|||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: JamiTheme.chatViewHeaderPreferredHeight
|
||||
Layout.maximumHeight: JamiTheme.chatViewHeaderPreferredHeight
|
||||
Layout.minimumWidth: JamiTheme.chatViewHeaderMinimumWidth
|
||||
Layout.minimumWidth: JamiTheme.mainViewPaneMinWidth
|
||||
|
||||
DropArea {
|
||||
anchors.fill: parent
|
||||
|
@ -125,7 +125,7 @@ Rectangle {
|
|||
if (!swarmDetailsPanel.visible && !messagesResearchPanel.visible) {
|
||||
chatContents.visible = true
|
||||
} else {
|
||||
if (chatViewHeader.width - JamiTheme.detailsPageMinWidth < JamiTheme.chatViewHeaderMinimumWidth)
|
||||
if (chatViewHeader.width - JamiTheme.detailsPageMinWidth < JamiTheme.mainViewPaneMinWidth)
|
||||
chatContents.visible = false
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ Rectangle {
|
|||
|
||||
if (!swarmDetailsPanel.visible && !addMemberPanel.visible && !messagesResearchPanel.visible)
|
||||
return
|
||||
if (chatViewHeader.width < JamiTheme.detailsPageMinWidth + JamiTheme.chatViewHeaderMinimumWidth
|
||||
if (chatViewHeader.width < JamiTheme.detailsPageMinWidth + JamiTheme.mainViewPaneMinWidth
|
||||
&& !isExpanding && chatContents.visible) {
|
||||
lastContentsSplitSize = chatContents.width
|
||||
lastDetailsSplitSize = Math.min(JamiTheme.detailsPageMinWidth, (swarmDetailsPanel.visible
|
||||
|
@ -166,7 +166,7 @@ Rectangle {
|
|||
? addMemberPanel.width
|
||||
: messagesResearchPanel.width))
|
||||
chatContents.visible = false
|
||||
} else if (chatViewHeader.width >= JamiTheme.chatViewHeaderMinimumWidth + lastDetailsSplitSize
|
||||
} else if (chatViewHeader.width >= JamiTheme.mainViewPaneMinWidth + lastDetailsSplitSize
|
||||
&& isExpanding && !layoutManager.isFullScreen && !chatContents.visible) {
|
||||
chatContents.visible = true
|
||||
}
|
||||
|
@ -199,7 +199,7 @@ Rectangle {
|
|||
if (addMemberPanel.visible) {
|
||||
chatContents.visible = true
|
||||
} else {
|
||||
if (chatViewHeader.width - JamiTheme.detailsPageMinWidth < JamiTheme.chatViewHeaderMinimumWidth)
|
||||
if (chatViewHeader.width - JamiTheme.detailsPageMinWidth < JamiTheme.mainViewPaneMinWidth)
|
||||
chatContents.visible = false
|
||||
}
|
||||
addMemberPanel.visible = !addMemberPanel.visible
|
||||
|
@ -277,19 +277,19 @@ Rectangle {
|
|||
|
||||
handle: Rectangle {
|
||||
implicitWidth: JamiTheme.splitViewHandlePreferredWidth
|
||||
implicitHeight: viewCoordinator.splitView.height
|
||||
implicitHeight: root.height
|
||||
color: JamiTheme.primaryBackgroundColor
|
||||
Rectangle {
|
||||
implicitWidth: 1
|
||||
implicitHeight: viewCoordinator.splitView.height
|
||||
implicitHeight: root.height
|
||||
color: JamiTheme.tabbarBorderColor
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: chatContents
|
||||
SplitView.maximumWidth: viewCoordinator.splitView.width
|
||||
SplitView.minimumWidth: JamiTheme.chatViewHeaderMinimumWidth
|
||||
SplitView.maximumWidth: root.width
|
||||
SplitView.minimumWidth: JamiTheme.mainViewPaneMinWidth
|
||||
SplitView.fillWidth: true
|
||||
|
||||
StackLayout {
|
||||
|
@ -362,7 +362,7 @@ Rectangle {
|
|||
id: messagesResearchPanel
|
||||
|
||||
visible: false
|
||||
SplitView.maximumWidth: viewCoordinator.splitView.width
|
||||
SplitView.maximumWidth: root.width
|
||||
SplitView.minimumWidth: JamiTheme.detailsPageMinWidth
|
||||
SplitView.preferredWidth: JamiTheme.detailsPageMinWidth
|
||||
}
|
||||
|
@ -371,7 +371,7 @@ Rectangle {
|
|||
id: swarmDetailsPanel
|
||||
visible: false
|
||||
|
||||
SplitView.maximumWidth: viewCoordinator.splitView.width
|
||||
SplitView.maximumWidth: root.width
|
||||
SplitView.preferredWidth: JamiTheme.detailsPageMinWidth
|
||||
SplitView.minimumWidth: JamiTheme.detailsPageMinWidth
|
||||
}
|
||||
|
@ -380,7 +380,7 @@ Rectangle {
|
|||
id: addMemberPanel
|
||||
visible: false
|
||||
|
||||
SplitView.maximumWidth: viewCoordinator.splitView.width
|
||||
SplitView.maximumWidth: root.width
|
||||
SplitView.preferredWidth: JamiTheme.detailsPageMinWidth
|
||||
SplitView.minimumWidth: JamiTheme.detailsPageMinWidth
|
||||
}
|
||||
|
|
|
@ -26,10 +26,9 @@ import net.jami.Constants 1.1
|
|||
|
||||
import "../../commoncomponents"
|
||||
|
||||
BaseView {
|
||||
id: root
|
||||
|
||||
color: JamiTheme.chatviewBgColor
|
||||
DualPaneView {
|
||||
id: viewNode
|
||||
objectName: "NewSwarmPage"
|
||||
|
||||
signal createSwarmClicked(string title, string description, string avatar)
|
||||
signal removeMember(string convId, string member)
|
||||
|
@ -42,188 +41,199 @@ BaseView {
|
|||
|
||||
property var members: []
|
||||
|
||||
RowLayout {
|
||||
id: labelsMember
|
||||
Layout.topMargin: 16
|
||||
Layout.preferredWidth: root.width
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
spacing: 16
|
||||
visible: root.members.length
|
||||
splitViewStateKey: "Main"
|
||||
inhibits: ["ConversationView"]
|
||||
|
||||
Label {
|
||||
text: JamiStrings.to
|
||||
font.bold: true
|
||||
color: JamiTheme.textColor
|
||||
Layout.leftMargin: 16
|
||||
}
|
||||
leftPaneItem: viewCoordinator.getView("SidePanel")
|
||||
rightPaneItem: Rectangle {
|
||||
id: root
|
||||
color: JamiTheme.chatviewBgColor
|
||||
|
||||
Flow {
|
||||
anchors.fill: parent
|
||||
|
||||
RowLayout {
|
||||
id: labelsMember
|
||||
Layout.topMargin: 16
|
||||
Layout.preferredWidth: root.width - 80
|
||||
Layout.preferredHeight: childrenRect.height + 16
|
||||
spacing: 8
|
||||
Layout.preferredWidth: root.width
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
spacing: 16
|
||||
visible: viewNode.members.length
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
Label {
|
||||
text: JamiStrings.to
|
||||
font.bold: true
|
||||
color: JamiTheme.textColor
|
||||
Layout.leftMargin: 16
|
||||
}
|
||||
|
||||
delegate: Rectangle {
|
||||
id: delegate
|
||||
radius: (delegate.height + 12) / 2
|
||||
width: label.width + 36
|
||||
height: label.height + 12
|
||||
Flow {
|
||||
Layout.topMargin: 16
|
||||
Layout.preferredWidth: root.width - 80
|
||||
Layout.preferredHeight: childrenRect.height + 16
|
||||
spacing: 8
|
||||
|
||||
RowLayout {
|
||||
anchors.centerIn: parent
|
||||
Repeater {
|
||||
id: repeater
|
||||
|
||||
Label {
|
||||
id: label
|
||||
text: UtilsAdapter.getBestNameForUri(CurrentAccount.id, modelData.uri)
|
||||
color: JamiTheme.textColor
|
||||
Layout.leftMargin: 8
|
||||
delegate: Rectangle {
|
||||
id: delegate
|
||||
radius: (delegate.height + 12) / 2
|
||||
width: label.width + 36
|
||||
height: label.height + 12
|
||||
|
||||
RowLayout {
|
||||
anchors.centerIn: parent
|
||||
|
||||
Label {
|
||||
id: label
|
||||
text: UtilsAdapter.getBestNameForUri(CurrentAccount.id, modelData.uri)
|
||||
color: JamiTheme.textColor
|
||||
Layout.leftMargin: 8
|
||||
}
|
||||
|
||||
PushButton {
|
||||
id: removeUserBtn
|
||||
|
||||
preferredSize: 24
|
||||
|
||||
source: JamiResources.round_close_24dp_svg
|
||||
toolTipText: JamiStrings.removeMember
|
||||
|
||||
normalColor: "transparent"
|
||||
imageColor: "transparent"
|
||||
|
||||
onClicked: removeMember(modelData.convId, modelData.uri)
|
||||
}
|
||||
}
|
||||
|
||||
PushButton {
|
||||
id: removeUserBtn
|
||||
color: JamiTheme.selectedColor
|
||||
}
|
||||
model: viewNode.members
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
preferredSize: 24
|
||||
Rectangle {
|
||||
anchors.top: labelsMember.bottom
|
||||
visible: labelsMember.visible
|
||||
height: 1
|
||||
width: root.width
|
||||
color: "transparent"
|
||||
border.width: 1
|
||||
border.color: JamiTheme.selectedColor
|
||||
}
|
||||
|
||||
source: JamiResources.round_close_24dp_svg
|
||||
toolTipText: JamiStrings.removeMember
|
||||
ColumnLayout {
|
||||
id: mainLayout
|
||||
objectName: "mainLayout"
|
||||
anchors.centerIn: root
|
||||
|
||||
normalColor: "transparent"
|
||||
imageColor: "transparent"
|
||||
PhotoboothView {
|
||||
id: currentAccountAvatar
|
||||
|
||||
onClicked: root.removeMember(modelData.convId, modelData.uri)
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
darkTheme: UtilsAdapter.luma(root.color)
|
||||
width: avatarSize
|
||||
height: avatarSize
|
||||
|
||||
newItem: true
|
||||
imageId: root.visible ? "temp" : ""
|
||||
avatarSize: 180
|
||||
buttonSize: JamiTheme.smartListAvatarSize
|
||||
}
|
||||
|
||||
EditableLineEdit {
|
||||
id: title
|
||||
objectName: "titleLineEdit"
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.topMargin: JamiTheme.preferredMarginSize
|
||||
Layout.preferredWidth: JamiTheme.preferredFieldWidth
|
||||
|
||||
font.pointSize: JamiTheme.titleFontSize
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
placeholderText: JamiStrings.swarmName
|
||||
tooltipText: JamiStrings.swarmName
|
||||
backgroundColor: root.color
|
||||
color: UtilsAdapter.luma(backgroundColor) ?
|
||||
JamiTheme.chatviewTextColorLight :
|
||||
JamiTheme.chatviewTextColorDark
|
||||
placeholderTextColor: {
|
||||
if (editable) {
|
||||
if (UtilsAdapter.luma(root.color)) {
|
||||
return JamiTheme.placeholderTextColorWhite
|
||||
} else {
|
||||
return JamiTheme.placeholderTextColor
|
||||
}
|
||||
} else {
|
||||
if (UtilsAdapter.luma(root.color)) {
|
||||
return JamiTheme.chatviewTextColorLight
|
||||
} else {
|
||||
return JamiTheme.chatviewTextColorDark
|
||||
}
|
||||
}
|
||||
|
||||
color: JamiTheme.selectedColor
|
||||
}
|
||||
model: root.members
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.top: labelsMember.bottom
|
||||
visible: labelsMember.visible
|
||||
height: 1
|
||||
width: root.width
|
||||
color: "transparent"
|
||||
border.width: 1
|
||||
border.color: JamiTheme.selectedColor
|
||||
}
|
||||
EditableLineEdit {
|
||||
id: description
|
||||
objectName: "descriptionLineEdit"
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.topMargin: JamiTheme.preferredMarginSize
|
||||
Layout.preferredWidth: JamiTheme.preferredFieldWidth
|
||||
|
||||
ColumnLayout {
|
||||
id: mainLayout
|
||||
objectName: "mainLayout"
|
||||
anchors.centerIn: root
|
||||
font.pointSize: JamiTheme.menuFontSize
|
||||
|
||||
PhotoboothView {
|
||||
id: currentAccountAvatar
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
darkTheme: UtilsAdapter.luma(root.color)
|
||||
width: avatarSize
|
||||
height: avatarSize
|
||||
|
||||
newItem: true
|
||||
imageId: root.visible ? "temp" : ""
|
||||
avatarSize: 180
|
||||
buttonSize: JamiTheme.smartListAvatarSize
|
||||
}
|
||||
|
||||
EditableLineEdit {
|
||||
id: title
|
||||
objectName: "titleLineEdit"
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.topMargin: JamiTheme.preferredMarginSize
|
||||
Layout.preferredWidth: JamiTheme.preferredFieldWidth
|
||||
|
||||
font.pointSize: JamiTheme.titleFontSize
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
placeholderText: JamiStrings.swarmName
|
||||
tooltipText: JamiStrings.swarmName
|
||||
backgroundColor: root.color
|
||||
color: UtilsAdapter.luma(backgroundColor) ?
|
||||
JamiTheme.chatviewTextColorLight :
|
||||
JamiTheme.chatviewTextColorDark
|
||||
placeholderTextColor: {
|
||||
if (editable) {
|
||||
if (UtilsAdapter.luma(root.color)) {
|
||||
return JamiTheme.placeholderTextColorWhite
|
||||
placeholderText: JamiStrings.addADescription
|
||||
tooltipText: JamiStrings.addADescription
|
||||
backgroundColor: root.color
|
||||
color: UtilsAdapter.luma(backgroundColor) ?
|
||||
JamiTheme.chatviewTextColorLight :
|
||||
JamiTheme.chatviewTextColorDark
|
||||
placeholderTextColor: {
|
||||
if (editable) {
|
||||
if (UtilsAdapter.luma(root.color)) {
|
||||
return JamiTheme.placeholderTextColorWhite
|
||||
} else {
|
||||
return JamiTheme.placeholderTextColor
|
||||
}
|
||||
} else {
|
||||
return JamiTheme.placeholderTextColor
|
||||
}
|
||||
} else {
|
||||
if (UtilsAdapter.luma(root.color)) {
|
||||
return JamiTheme.chatviewTextColorLight
|
||||
} else {
|
||||
return JamiTheme.chatviewTextColorDark
|
||||
if (UtilsAdapter.luma(root.color)) {
|
||||
return JamiTheme.chatviewTextColorLight
|
||||
} else {
|
||||
return JamiTheme.chatviewTextColorDark
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EditableLineEdit {
|
||||
id: description
|
||||
objectName: "descriptionLineEdit"
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.topMargin: JamiTheme.preferredMarginSize
|
||||
Layout.preferredWidth: JamiTheme.preferredFieldWidth
|
||||
MaterialButton {
|
||||
id: btnCreateSwarm
|
||||
|
||||
font.pointSize: JamiTheme.menuFontSize
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
placeholderText: JamiStrings.addADescription
|
||||
tooltipText: JamiStrings.addADescription
|
||||
backgroundColor: root.color
|
||||
color: UtilsAdapter.luma(backgroundColor) ?
|
||||
JamiTheme.chatviewTextColorLight :
|
||||
JamiTheme.chatviewTextColorDark
|
||||
placeholderTextColor: {
|
||||
if (editable) {
|
||||
if (UtilsAdapter.luma(root.color)) {
|
||||
return JamiTheme.placeholderTextColorWhite
|
||||
} else {
|
||||
return JamiTheme.placeholderTextColor
|
||||
}
|
||||
} else {
|
||||
if (UtilsAdapter.luma(root.color)) {
|
||||
return JamiTheme.chatviewTextColorLight
|
||||
} else {
|
||||
return JamiTheme.chatviewTextColorDark
|
||||
}
|
||||
TextMetrics {
|
||||
id: textSize
|
||||
font.weight: Font.Bold
|
||||
font.pixelSize: JamiTheme.wizardViewButtonFontPixelSize
|
||||
font.capitalization: Font.AllUppercase
|
||||
text: btnCreateSwarm.text
|
||||
}
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.topMargin: JamiTheme.preferredMarginSize
|
||||
autoAccelerator: true
|
||||
|
||||
preferredWidth: textSize.width + 2 * JamiTheme.buttontextWizzardPadding
|
||||
|
||||
primary: true
|
||||
text: JamiStrings.createTheSwarm
|
||||
|
||||
onClicked: createSwarmClicked(title.text,
|
||||
description.text,
|
||||
UtilsAdapter.tempCreationImage())
|
||||
}
|
||||
}
|
||||
|
||||
MaterialButton {
|
||||
id: btnCreateSwarm
|
||||
|
||||
TextMetrics{
|
||||
id: textSize
|
||||
font.weight: Font.Bold
|
||||
font.pixelSize: JamiTheme.wizardViewButtonFontPixelSize
|
||||
font.capitalization: Font.AllUppercase
|
||||
text: btnCreateSwarm.text
|
||||
}
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.topMargin: JamiTheme.preferredMarginSize
|
||||
autoAccelerator: true
|
||||
|
||||
preferredWidth: textSize.width + 2*JamiTheme.buttontextWizzardPadding
|
||||
|
||||
primary: true
|
||||
text: JamiStrings.createTheSwarm
|
||||
|
||||
onClicked: createSwarmClicked(title.text,
|
||||
description.text,
|
||||
UtilsAdapter.tempCreationImage())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ Rectangle {
|
|||
}
|
||||
|
||||
onWidthChanged: {
|
||||
if (chatViewContainer.visible && root.width < JamiTheme.chatViewHeaderMinimumWidth * 2) {
|
||||
if (chatViewContainer.visible && root.width < JamiTheme.mainViewPaneMinWidth * 2) {
|
||||
callPageMainRect.visible = false
|
||||
} else {
|
||||
callPageMainRect.visible = true
|
||||
|
@ -146,7 +146,7 @@ Rectangle {
|
|||
id: callPageMainRect
|
||||
|
||||
SplitView.preferredHeight: mainColumnLayout.isHorizontal ? root.height : (root.height / 3) * 2
|
||||
SplitView.minimumWidth: JamiTheme.chatViewHeaderMinimumWidth
|
||||
SplitView.minimumWidth: JamiTheme.mainViewPaneMinWidth
|
||||
SplitView.fillWidth: true
|
||||
|
||||
TapHandler {
|
||||
|
@ -404,15 +404,15 @@ Rectangle {
|
|||
root.height :
|
||||
root.height / 3
|
||||
SplitView.preferredWidth: mainColumnLayout.isHorizontal ?
|
||||
JamiTheme.chatViewHeaderMinimumWidth :
|
||||
JamiTheme.mainViewPaneMinWidth :
|
||||
root.width
|
||||
SplitView.minimumWidth: JamiTheme.chatViewHeaderMinimumWidth
|
||||
SplitView.minimumWidth: JamiTheme.mainViewPaneMinWidth
|
||||
visible: false
|
||||
clip: true
|
||||
property bool showDetails: false
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible && root.width < JamiTheme.chatViewHeaderMinimumWidth * 2) {
|
||||
if (visible && root.width < JamiTheme.mainViewPaneMinWidth * 2) {
|
||||
callPageMainRect.visible = false
|
||||
} else {
|
||||
callPageMainRect.visible = true
|
||||
|
|
|
@ -29,7 +29,7 @@ import net.jami.Models 1.1
|
|||
import "../../commoncomponents"
|
||||
import "../../settingsview/components"
|
||||
|
||||
BaseView {
|
||||
SidePanelBase {
|
||||
id: root
|
||||
objectName: "SidePanel"
|
||||
|
||||
|
@ -67,9 +67,9 @@ BaseView {
|
|||
}
|
||||
|
||||
function toggleCreateSwarmView() {
|
||||
if (!viewCoordinator.inNewSwarm) {
|
||||
if (!inNewSwarm) {
|
||||
viewCoordinator.present("NewSwarmPage")
|
||||
const newSwarmPage = viewCoordinator.currentView
|
||||
const newSwarmPage = viewCoordinator.getView("NewSwarmPage")
|
||||
newSwarmPage.removeMember.connect((convId, member) => {
|
||||
removeMember(convId, member)
|
||||
})
|
||||
|
@ -84,7 +84,6 @@ BaseView {
|
|||
let convuid = ConversationsAdapter.createSwarm(title, description, avatar, uris)
|
||||
viewCoordinator.dismiss("NewSwarmPage")
|
||||
LRCInstance.selectConversation(convuid)
|
||||
|
||||
})
|
||||
} else {
|
||||
viewCoordinator.dismiss("NewSwarmPage")
|
||||
|
@ -99,10 +98,12 @@ BaseView {
|
|||
sidePanelTabBar.selectTab(tabIndex)
|
||||
}
|
||||
|
||||
property bool inNewSwarm: viewCoordinator.currentViewName === "NewSwarmPage"
|
||||
|
||||
property var highlighted: []
|
||||
property var highlightedMembers: []
|
||||
onHighlightedMembersChanged: {
|
||||
if (viewCoordinator.inNewSwarm) {
|
||||
if (inNewSwarm) {
|
||||
const newSwarmPage = viewCoordinator.getView("NewSwarmPage")
|
||||
newSwarmPage.members = highlightedMembers
|
||||
}
|
||||
|
@ -180,86 +181,65 @@ BaseView {
|
|||
color: JamiTheme.backgroundColor
|
||||
}
|
||||
|
||||
header: AccountComboBox {
|
||||
width: parent.width
|
||||
height: JamiTheme.accountListItemHeight
|
||||
onSettingBtnClicked: {
|
||||
!viewCoordinator.inSettings ?
|
||||
viewCoordinator.present("SettingsView") :
|
||||
viewCoordinator.dismiss("SettingsView")}
|
||||
}
|
||||
header: AccountComboBox {}
|
||||
|
||||
StackLayout {
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
|
||||
currentIndex: viewCoordinator.inSettings ? 0 : 1
|
||||
RowLayout {
|
||||
id: titleBar
|
||||
|
||||
SettingsMenu {
|
||||
id: settingsMenu
|
||||
objectName: "settingsMenu"
|
||||
visible: swarmMemberSearchList.visible
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
height: 40
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 10
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 15
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 15
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Label {
|
||||
id: title
|
||||
|
||||
RowLayout {
|
||||
id: titleBar
|
||||
height: parent.height
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
visible: swarmMemberSearchList.visible
|
||||
color: JamiTheme.textColor
|
||||
|
||||
height: 40
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 10
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 15
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 15
|
||||
font.bold: true
|
||||
font.pointSize: JamiTheme.contactEventPointSize
|
||||
|
||||
Label {
|
||||
id: title
|
||||
|
||||
height: parent.height
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
color: JamiTheme.textColor
|
||||
|
||||
font.bold: true
|
||||
font.pointSize: JamiTheme.contactEventPointSize
|
||||
|
||||
text: JamiStrings.createSwarm
|
||||
}
|
||||
|
||||
PushButton {
|
||||
radius: JamiTheme.primaryRadius
|
||||
|
||||
imageColor: JamiTheme.textColor
|
||||
imagePadding: 8
|
||||
normalColor: JamiTheme.secondaryBackgroundColor
|
||||
|
||||
preferredSize: titleBar.height
|
||||
|
||||
source: JamiResources.round_close_24dp_svg
|
||||
toolTipText: JamiStrings.cancel
|
||||
|
||||
onClicked: toggleCreateSwarmView()
|
||||
}
|
||||
text: JamiStrings.createSwarm
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: startBar
|
||||
PushButton {
|
||||
radius: JamiTheme.primaryRadius
|
||||
|
||||
height: 40
|
||||
anchors.top: titleBar.visible ? titleBar.bottom : parent.top
|
||||
anchors.topMargin: 10
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 15
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 15
|
||||
imageColor: JamiTheme.textColor
|
||||
imagePadding: 8
|
||||
normalColor: JamiTheme.secondaryBackgroundColor
|
||||
|
||||
preferredSize: titleBar.height
|
||||
|
||||
source: JamiResources.round_close_24dp_svg
|
||||
toolTipText: JamiStrings.cancel
|
||||
|
||||
onClicked: toggleCreateSwarmView()
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: startBar
|
||||
|
||||
height: 40
|
||||
anchors.top: titleBar.visible ? titleBar.bottom : parent.top
|
||||
anchors.topMargin: 10
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 15
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 15
|
||||
|
||||
Shortcut {
|
||||
sequence: "Ctrl+F"
|
||||
|
@ -269,232 +249,230 @@ BaseView {
|
|||
}
|
||||
}
|
||||
|
||||
ContactSearchBar {
|
||||
id: contactSearchBar
|
||||
ContactSearchBar {
|
||||
id: contactSearchBar
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
onContactSearchBarTextChanged: function (text) {
|
||||
print(text)
|
||||
// not calling positionViewAtBeginning will cause
|
||||
// sort animation visual bugs
|
||||
conversationListView.positionViewAtBeginning()
|
||||
ConversationsAdapter.ignoreFiltering(root.highlighted)
|
||||
ConversationsAdapter.setFilter(text)
|
||||
}
|
||||
|
||||
onReturnPressedWhileSearching: {
|
||||
var listView = searchResultsListView.count ?
|
||||
searchResultsListView :
|
||||
conversationListView
|
||||
if (listView.count)
|
||||
listView.model.select(0)
|
||||
}
|
||||
onContactSearchBarTextChanged: function (text) {
|
||||
// not calling positionViewAtBeginning will cause
|
||||
// sort animation visual bugs
|
||||
conversationListView.positionViewAtBeginning()
|
||||
ConversationsAdapter.ignoreFiltering(root.highlighted)
|
||||
ConversationsAdapter.setFilter(text)
|
||||
}
|
||||
|
||||
PushButton {
|
||||
id: startConversation
|
||||
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
radius: JamiTheme.primaryRadius
|
||||
|
||||
imageColor: JamiTheme.textColor
|
||||
imagePadding: 8
|
||||
normalColor: JamiTheme.secondaryBackgroundColor
|
||||
|
||||
preferredSize: startBar.height
|
||||
|
||||
visible: !swarmMemberSearchList.visible && CurrentAccount.type !== Profile.Type.SIP
|
||||
|
||||
source: smartListLayout.visible ? JamiResources.create_swarm_svg : JamiResources.round_close_24dp_svg
|
||||
toolTipText: smartListLayout.visible ? JamiStrings.startSwarm : JamiStrings.cancel
|
||||
|
||||
onClicked: toggleCreateSwarmView()
|
||||
onReturnPressedWhileSearching: {
|
||||
var listView = searchResultsListView.count ?
|
||||
searchResultsListView :
|
||||
conversationListView
|
||||
if (listView.count)
|
||||
listView.model.select(0)
|
||||
}
|
||||
}
|
||||
|
||||
SidePanelTabBar {
|
||||
id: sidePanelTabBar
|
||||
PushButton {
|
||||
id: startConversation
|
||||
|
||||
visible: ConversationsAdapter.pendingRequestCount &&
|
||||
!contactSearchBar.textContent && smartListLayout.visible
|
||||
anchors.top: startBar.bottom
|
||||
anchors.topMargin: visible ? 10 : 0
|
||||
width: page.width
|
||||
height: visible ? 42 : 0
|
||||
contentHeight: visible ? 42 : 0
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
radius: JamiTheme.primaryRadius
|
||||
|
||||
imageColor: JamiTheme.textColor
|
||||
imagePadding: 8
|
||||
normalColor: JamiTheme.secondaryBackgroundColor
|
||||
|
||||
preferredSize: startBar.height
|
||||
|
||||
visible: !swarmMemberSearchList.visible && CurrentAccount.type !== Profile.Type.SIP
|
||||
|
||||
source: smartListLayout.visible ? JamiResources.create_swarm_svg : JamiResources.round_close_24dp_svg
|
||||
toolTipText: smartListLayout.visible ? JamiStrings.startSwarm : JamiStrings.cancel
|
||||
|
||||
onClicked: toggleCreateSwarmView()
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: searchStatusRect
|
||||
SidePanelTabBar {
|
||||
id: sidePanelTabBar
|
||||
|
||||
visible: searchStatusText.text !== "" && smartListLayout.visible
|
||||
visible: ConversationsAdapter.pendingRequestCount &&
|
||||
!contactSearchBar.textContent && smartListLayout.visible
|
||||
anchors.top: startBar.bottom
|
||||
anchors.topMargin: visible ? 10 : 0
|
||||
width: page.width
|
||||
height: visible ? 42 : 0
|
||||
contentHeight: visible ? 42 : 0
|
||||
}
|
||||
|
||||
anchors.top: sidePanelTabBar.bottom
|
||||
anchors.topMargin: visible ? 10 : 0
|
||||
width: parent.width
|
||||
height: visible ? 42 : 0
|
||||
Rectangle {
|
||||
id: searchStatusRect
|
||||
|
||||
color: JamiTheme.backgroundColor
|
||||
visible: searchStatusText.text !== "" && smartListLayout.visible
|
||||
|
||||
Text {
|
||||
id: searchStatusText
|
||||
anchors.top: sidePanelTabBar.bottom
|
||||
anchors.topMargin: visible ? 10 : 0
|
||||
width: parent.width
|
||||
height: visible ? 42 : 0
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 32
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 32
|
||||
color: JamiTheme.textColor
|
||||
wrapMode: Text.WordWrap
|
||||
font.pointSize: JamiTheme.filterItemFontSize
|
||||
}
|
||||
color: JamiTheme.backgroundColor
|
||||
|
||||
Text {
|
||||
id: searchStatusText
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 32
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 32
|
||||
color: JamiTheme.textColor
|
||||
wrapMode: Text.WordWrap
|
||||
font.pointSize: JamiTheme.filterItemFontSize
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: smartListLayout
|
||||
ColumnLayout {
|
||||
id: smartListLayout
|
||||
|
||||
width: parent.width
|
||||
anchors.top: searchStatusRect.bottom
|
||||
anchors.topMargin: (sidePanelTabBar.visible ||
|
||||
searchStatusRect.visible) ? 0 : 12
|
||||
anchors.bottom: parent.bottom
|
||||
width: parent.width
|
||||
anchors.top: searchStatusRect.bottom
|
||||
anchors.topMargin: (sidePanelTabBar.visible ||
|
||||
searchStatusRect.visible) ? 0 : 12
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
spacing: 4
|
||||
spacing: 4
|
||||
|
||||
visible: !swarmMemberSearchList.visible
|
||||
visible: !swarmMemberSearchList.visible
|
||||
|
||||
ConversationListView {
|
||||
id: searchResultsListView
|
||||
ConversationListView {
|
||||
id: searchResultsListView
|
||||
|
||||
visible: count
|
||||
opacity: visible ? 1 : 0
|
||||
visible: count
|
||||
opacity: visible ? 1 : 0
|
||||
|
||||
Layout.topMargin: 10
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: visible ? contentHeight : 0
|
||||
Layout.maximumHeight: {
|
||||
var otherContentHeight = conversationListView.contentHeight + 16
|
||||
if (conversationListView.visible)
|
||||
if (otherContentHeight < parent.height / 2)
|
||||
return parent.height - otherContentHeight
|
||||
else
|
||||
return parent.height / 2
|
||||
Layout.topMargin: 10
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: visible ? contentHeight : 0
|
||||
Layout.maximumHeight: {
|
||||
var otherContentHeight = conversationListView.contentHeight + 16
|
||||
if (conversationListView.visible)
|
||||
if (otherContentHeight < parent.height / 2)
|
||||
return parent.height - otherContentHeight
|
||||
else
|
||||
return parent.height
|
||||
}
|
||||
|
||||
model: SearchResultsListModel
|
||||
headerLabel: JamiStrings.searchResults
|
||||
headerVisible: visible
|
||||
return parent.height / 2
|
||||
else
|
||||
return parent.height
|
||||
}
|
||||
|
||||
ConversationListView {
|
||||
id: conversationListView
|
||||
|
||||
visible: count
|
||||
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.fillHeight: true
|
||||
|
||||
model: ConversationListModel
|
||||
headerLabel: JamiStrings.conversations
|
||||
headerVisible: searchResultsListView.visible
|
||||
}
|
||||
model: SearchResultsListModel
|
||||
headerLabel: JamiStrings.searchResults
|
||||
headerVisible: visible
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: swarmMemberSearchList
|
||||
ConversationListView {
|
||||
id: conversationListView
|
||||
|
||||
visible: viewCoordinator.inNewSwarm
|
||||
visible: count
|
||||
|
||||
width: parent.width
|
||||
anchors.top: searchStatusRect.bottom
|
||||
anchors.topMargin: (sidePanelTabBar.visible ||
|
||||
searchStatusRect.visible) ? 0 : 12
|
||||
anchors.bottom: parent.bottom
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.fillHeight: true
|
||||
|
||||
spacing: 4
|
||||
model: ConversationListModel
|
||||
headerLabel: JamiStrings.conversations
|
||||
headerVisible: searchResultsListView.visible
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
font.bold: true
|
||||
font.pointSize: JamiTheme.contactEventPointSize
|
||||
ColumnLayout {
|
||||
id: swarmMemberSearchList
|
||||
|
||||
Layout.margins: 16
|
||||
Layout.maximumHeight: 24
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
visible: inNewSwarm
|
||||
|
||||
wrapMode: Text.Wrap
|
||||
width: parent.width
|
||||
anchors.top: searchStatusRect.bottom
|
||||
anchors.topMargin: (sidePanelTabBar.visible ||
|
||||
searchStatusRect.visible) ? 0 : 12
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
text: {
|
||||
if (highlightedMembers.length === 0)
|
||||
return JamiStrings.youCanAdd7
|
||||
return JamiStrings.youCanAddMore.arg(7 - Math.min(highlightedMembers.length, 7))
|
||||
}
|
||||
color: JamiTheme.textColor
|
||||
spacing: 4
|
||||
|
||||
Text {
|
||||
font.bold: true
|
||||
font.pointSize: JamiTheme.contactEventPointSize
|
||||
|
||||
Layout.margins: 16
|
||||
Layout.maximumHeight: 24
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
|
||||
wrapMode: Text.Wrap
|
||||
|
||||
text: {
|
||||
if (highlightedMembers.length === 0)
|
||||
return JamiStrings.youCanAdd7
|
||||
return JamiStrings.youCanAddMore.arg(7 - Math.min(highlightedMembers.length, 7))
|
||||
}
|
||||
color: JamiTheme.textColor
|
||||
}
|
||||
|
||||
JamiListView {
|
||||
id: swarmCurrentConversationList
|
||||
JamiListView {
|
||||
id: swarmCurrentConversationList
|
||||
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.fillHeight: true
|
||||
|
||||
model: ConversationListModel
|
||||
delegate: SmartListItemDelegate {
|
||||
interactive: false
|
||||
model: ConversationListModel
|
||||
delegate: SmartListItemDelegate {
|
||||
interactive: false
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!swarmCurrentConversationList.visible) {
|
||||
highlighted = false
|
||||
root.clearHighlighted()
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
// Note: when scrolled down, this delegate will be
|
||||
// destroyed from the memory. So, re-add the highlighted
|
||||
// status if necessary
|
||||
if (Array.from(root.highlighted).find(r => r === UID)) {
|
||||
highlighted = true
|
||||
}
|
||||
}
|
||||
|
||||
onHighlightedChanged: function onHighlightedChanged() {
|
||||
if (highlighted && Array.from(root.highlighted).find(r => r === UID)) {
|
||||
// Due to scrolling destruction/reconstruction
|
||||
return
|
||||
}
|
||||
var currentHighlighted = root.highlighted
|
||||
if (!root.refreshHighlighted(UID, highlighted)) {
|
||||
highlighted = false
|
||||
return
|
||||
}
|
||||
if (highlighted) {
|
||||
root.highlighted.push(UID)
|
||||
} else {
|
||||
root.highlighted = Array.from(root.highlighted).filter(r => r !== UID)
|
||||
}
|
||||
root.clearContactSearchBar()
|
||||
onVisibleChanged: {
|
||||
if (!swarmCurrentConversationList.visible) {
|
||||
highlighted = false
|
||||
root.clearHighlighted()
|
||||
}
|
||||
}
|
||||
currentIndex: model.currentFilteredRow
|
||||
|
||||
Timer {
|
||||
id: locationIconTimer
|
||||
|
||||
property bool showIconArrow: true
|
||||
property bool isSharingPosition: PositionManager.positionShareConvIdsCount !== 0
|
||||
property bool isReceivingPosition: PositionManager.sharingUrisCount !== 0
|
||||
|
||||
interval: 750
|
||||
running: isSharingPosition || isReceivingPosition
|
||||
repeat: true
|
||||
onTriggered: {showIconArrow = !showIconArrow}
|
||||
Component.onCompleted: {
|
||||
// Note: when scrolled down, this delegate will be
|
||||
// destroyed from the memory. So, re-add the highlighted
|
||||
// status if necessary
|
||||
if (Array.from(root.highlighted).find(r => r === UID)) {
|
||||
highlighted = true
|
||||
}
|
||||
}
|
||||
|
||||
onHighlightedChanged: function onHighlightedChanged() {
|
||||
if (highlighted && Array.from(root.highlighted).find(r => r === UID)) {
|
||||
// Due to scrolling destruction/reconstruction
|
||||
return
|
||||
}
|
||||
var currentHighlighted = root.highlighted
|
||||
if (!root.refreshHighlighted(UID, highlighted)) {
|
||||
highlighted = false
|
||||
return
|
||||
}
|
||||
if (highlighted) {
|
||||
root.highlighted.push(UID)
|
||||
} else {
|
||||
root.highlighted = Array.from(root.highlighted).filter(r => r !== UID)
|
||||
}
|
||||
root.clearContactSearchBar()
|
||||
}
|
||||
}
|
||||
currentIndex: model.currentFilteredRow
|
||||
|
||||
Timer {
|
||||
id: locationIconTimer
|
||||
|
||||
property bool showIconArrow: true
|
||||
property bool isSharingPosition: PositionManager.positionShareConvIdsCount !== 0
|
||||
property bool isReceivingPosition: PositionManager.sharingUrisCount !== 0
|
||||
|
||||
interval: 750
|
||||
running: isSharingPosition || isReceivingPosition
|
||||
repeat: true
|
||||
onTriggered: {showIconArrow = !showIconArrow}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,12 +66,6 @@ ItemDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible)
|
||||
return
|
||||
UtilsAdapter.clearInteractionsCache(root.accountId, root.convId)
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: MessagesAdapter
|
||||
function onTimestampUpdated() {
|
||||
|
|
|
@ -27,20 +27,27 @@ import net.jami.Models 1.1
|
|||
import "../../commoncomponents"
|
||||
import "../js/keyboardshortcuttablecreation.js" as KeyboardShortcutTableCreation
|
||||
|
||||
BaseView {
|
||||
id: root
|
||||
ListSelectionView {
|
||||
id: viewNode
|
||||
objectName: "WelcomePage"
|
||||
|
||||
splitViewStateKey: "Main"
|
||||
hideRightPaneInSinglePaneMode: true
|
||||
|
||||
color: JamiTheme.secondaryBackgroundColor
|
||||
|
||||
JamiFlickable {
|
||||
id: welcomeView
|
||||
onPresented: LRCInstance.deselectConversation()
|
||||
leftPaneItem: viewCoordinator.getView("SidePanel")
|
||||
rightPaneItem: JamiFlickable {
|
||||
id: root
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
enabled: visible
|
||||
onClicked: welcomeView.forceActiveFocus()
|
||||
onClicked: root.forceActiveFocus()
|
||||
}
|
||||
|
||||
anchors.fill: root
|
||||
anchors.fill: parent
|
||||
|
||||
contentHeight: Math.max(root.height, welcomePageLayout.implicitHeight)
|
||||
contentWidth: Math.max(300, root.width)
|
||||
|
|
130
src/app/settingsview/SettingsSidePanel.qml
Normal file
130
src/app/settingsview/SettingsSidePanel.qml
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Savoir-faire Linux Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
import net.jami.Enums 1.1
|
||||
import net.jami.Models 1.1
|
||||
|
||||
import "../mainview/components"
|
||||
import "../commoncomponents"
|
||||
import "components"
|
||||
|
||||
SidePanelBase {
|
||||
id: root
|
||||
objectName: "SettingsSidePanel"
|
||||
|
||||
property var select: function(index) {
|
||||
buttonGroup.checkedButton = buttonGroup.buttons[index]
|
||||
}
|
||||
property var deselect: function() { buttonGroup.checkedButton = null }
|
||||
|
||||
color: JamiTheme.backgroundColor
|
||||
|
||||
Page {
|
||||
id: page
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
background: Rectangle {
|
||||
color: JamiTheme.backgroundColor
|
||||
}
|
||||
|
||||
header: AccountComboBox {}
|
||||
|
||||
// Bind to requests for a settings page to be selected via shorcut.
|
||||
Connections {
|
||||
target: JamiQmlUtils
|
||||
function onSettingsPageRequested(index) {
|
||||
viewCoordinator.present("SettingsView")
|
||||
buttonGroup.checkedButton = buttonGroup.buttons[index]
|
||||
}
|
||||
}
|
||||
|
||||
ButtonGroup {
|
||||
id: buttonGroup
|
||||
buttons: settingsButtons.children
|
||||
|
||||
onCheckedButtonChanged: {
|
||||
for (var i = 0; i < buttons.length; i++)
|
||||
if (buttons[i] === checkedButton) {
|
||||
indexSelected(i)
|
||||
return
|
||||
}
|
||||
indexSelected(-1)
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: settingsButtons
|
||||
|
||||
spacing: 0
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: childrenRect.height
|
||||
|
||||
component SMB: PushButton {
|
||||
normalColor: root.color
|
||||
|
||||
preferredHeight: 64
|
||||
preferredMargin: 24
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
buttonTextFont.pointSize: JamiTheme.textFontSize + 2
|
||||
textHAlign: Text.AlignLeft
|
||||
|
||||
imageColor: JamiTheme.textColor
|
||||
imageContainerHeight: 40
|
||||
imageContainerWidth: 40
|
||||
|
||||
pressedColor: Qt.lighter(JamiTheme.pressedButtonColor, 1.25)
|
||||
checkedColor: JamiTheme.smartListSelectedColor
|
||||
hoveredColor: JamiTheme.smartListHoveredColor
|
||||
|
||||
duration: 0
|
||||
checkable: true
|
||||
radius: 0
|
||||
}
|
||||
|
||||
SMB {
|
||||
buttonText: JamiStrings.accountSettingsMenuTitle
|
||||
source: JamiResources.account_24dp_svg
|
||||
}
|
||||
|
||||
SMB {
|
||||
buttonText: JamiStrings.generalSettingsTitle
|
||||
source: JamiResources.gear_black_24dp_svg
|
||||
}
|
||||
|
||||
SMB {
|
||||
buttonText: JamiStrings.avSettingsMenuTitle
|
||||
source: JamiResources.media_black_24dp_svg
|
||||
}
|
||||
|
||||
SMB {
|
||||
buttonText: JamiStrings.pluginSettingsTitle
|
||||
source: JamiResources.plugin_settings_black_24dp_svg
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,19 +29,9 @@ import "components"
|
|||
import "../commoncomponents"
|
||||
import "../mainview/js/contactpickercreation.js" as ContactPickerCreation
|
||||
|
||||
BaseView {
|
||||
id: root
|
||||
ListSelectionView {
|
||||
id: viewNode
|
||||
objectName: "SettingsView"
|
||||
requiresIndex: true
|
||||
|
||||
onDismissed: {
|
||||
settingsViewRect.stopBooth()
|
||||
if (UtilsAdapter.getAccountListSize() === 0) {
|
||||
viewCoordinator.requestAppWindowWizardView()
|
||||
} else {
|
||||
AccountAdapter.changeAccount(0)
|
||||
}
|
||||
}
|
||||
|
||||
enum SettingsMenu {
|
||||
Account,
|
||||
|
@ -50,9 +40,24 @@ BaseView {
|
|||
Plugin
|
||||
}
|
||||
|
||||
onVisibleChanged: if(visible) setSelected(selectedMenu, true)
|
||||
splitViewStateKey: "Main"
|
||||
inhibits: ["ConversationView"]
|
||||
|
||||
property int selectedMenu: SettingsView.Account
|
||||
leftPaneItem: viewCoordinator.getView("SettingsSidePanel")
|
||||
|
||||
onDismissed: {
|
||||
// Trigger an update to messages if needed.
|
||||
CurrentConversation.reloadInteractions()
|
||||
settingsViewRect.stopBooth()
|
||||
if (UtilsAdapter.getAccountListSize() === 0) {
|
||||
viewCoordinator.requestAppWindowWizardView()
|
||||
} else {
|
||||
AccountAdapter.changeAccount(0)
|
||||
}
|
||||
}
|
||||
|
||||
selectionFallback: true
|
||||
property int selectedMenu: index
|
||||
onSelectedMenuChanged: {
|
||||
if (selectedMenu === SettingsView.Account) {
|
||||
pageIdCurrentAccountSettings.updateAccountInfoDisplayed()
|
||||
|
@ -61,15 +66,10 @@ BaseView {
|
|||
}
|
||||
}
|
||||
|
||||
function setSelected(idx, recovery = false) {
|
||||
if (selectedMenu === idx && !recovery) return
|
||||
selectedMenu = idx
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
rightPaneItem: Rectangle {
|
||||
id: settingsViewRect
|
||||
|
||||
anchors.fill: root
|
||||
anchors.fill: parent
|
||||
color: JamiTheme.secondaryBackgroundColor
|
||||
|
||||
signal stopBooth
|
||||
|
@ -98,6 +98,7 @@ BaseView {
|
|||
|
||||
title: {
|
||||
switch(selectedMenu){
|
||||
default:
|
||||
case SettingsView.Account:
|
||||
return JamiStrings.accountSettingsTitle
|
||||
case SettingsView.General:
|
||||
|
@ -109,7 +110,7 @@ BaseView {
|
|||
}
|
||||
}
|
||||
|
||||
onBackArrowClicked: viewCoordinator.hideCurrentView()
|
||||
onBackArrowClicked: viewNode.dismiss()
|
||||
}
|
||||
|
||||
JamiFlickable {
|
||||
|
@ -137,6 +138,7 @@ BaseView {
|
|||
|
||||
currentIndex: {
|
||||
switch(selectedMenu){
|
||||
default:
|
||||
case SettingsView.Account:
|
||||
return pageIdCurrentAccountSettingsPage
|
||||
case SettingsView.General:
|
||||
|
|
|
@ -37,7 +37,7 @@ RowLayout {
|
|||
Layout.preferredWidth: JamiTheme.preferredFieldHeight
|
||||
Layout.preferredHeight: JamiTheme.preferredFieldHeight
|
||||
|
||||
visible: viewCoordinator.singlePane
|
||||
visible: viewNode.isSinglePane
|
||||
|
||||
onClicked: backArrowClicked()
|
||||
}
|
||||
|
|
|
@ -1,103 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2020-2023 Savoir-faire Linux Inc.
|
||||
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
import net.jami.Models 1.1
|
||||
import net.jami.Constants 1.1
|
||||
|
||||
import "../../commoncomponents"
|
||||
import "../../settingsview"
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
color: JamiTheme.backgroundColor
|
||||
|
||||
// The following bindings provide the settings menu selection persistence behavior.
|
||||
property bool singlePane: viewCoordinator.singlePane
|
||||
onSinglePaneChanged: {
|
||||
if (!viewCoordinator.singlePane && viewCoordinator.inSettings) {
|
||||
const idx = viewCoordinator.currentView.selectedMenu
|
||||
buttonGroup.checkedButton = buttonGroup.buttons[idx]
|
||||
}
|
||||
}
|
||||
onVisibleChanged: buttonGroup.checkedButton = visible && !viewCoordinator.singlePane ?
|
||||
buttonGroup.buttons[0] :
|
||||
null
|
||||
|
||||
// Bind to requests for a settings page to be selected via shorcut.
|
||||
Connections {
|
||||
target: JamiQmlUtils
|
||||
function onSettingsPageRequested(index) {
|
||||
buttonGroup.checkedButton = buttonGroup.buttons[index]
|
||||
}
|
||||
}
|
||||
|
||||
ButtonGroup {
|
||||
id: buttonGroup
|
||||
buttons: settingsButtons.children
|
||||
|
||||
// When the selection changes, we present the SettingsView at
|
||||
// the selected index.
|
||||
onCheckedButtonChanged: {
|
||||
for (var i = 0; i < buttons.length; i++)
|
||||
if (buttons[i] === checkedButton) {
|
||||
if (viewCoordinator.singlePane) {
|
||||
viewCoordinator.present("SettingsView").selectedMenu = i
|
||||
} else if (!viewCoordinator.busy) {
|
||||
var settingsView = viewCoordinator.getView("SettingsView")
|
||||
settingsView.selectedMenu = i
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: settingsButtons
|
||||
|
||||
spacing: 0
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: childrenRect.height
|
||||
|
||||
component SMB: SettingsMenuButton { normalColor: root.color }
|
||||
|
||||
SMB {
|
||||
buttonText: JamiStrings.accountSettingsMenuTitle
|
||||
source: JamiResources.account_24dp_svg
|
||||
}
|
||||
|
||||
SMB {
|
||||
buttonText: JamiStrings.generalSettingsTitle
|
||||
source: JamiResources.gear_black_24dp_svg
|
||||
}
|
||||
|
||||
SMB {
|
||||
buttonText: JamiStrings.avSettingsMenuTitle
|
||||
source: JamiResources.media_black_24dp_svg
|
||||
}
|
||||
|
||||
SMB {
|
||||
buttonText: JamiStrings.pluginSettingsTitle
|
||||
source: JamiResources.plugin_settings_black_24dp_svg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -50,6 +50,46 @@ UtilsAdapter::UtilsAdapter(AppSettingsManager* settingsManager,
|
|||
}
|
||||
}
|
||||
|
||||
QVariant
|
||||
UtilsAdapter::getAppValue(const QString& key, const QVariant& defaultValue)
|
||||
{
|
||||
return settingsManager_->getValue(key, defaultValue);
|
||||
}
|
||||
|
||||
void
|
||||
UtilsAdapter::setAppValue(const QString& key, const QVariant& value)
|
||||
{
|
||||
settingsManager_->setValue(key, value);
|
||||
}
|
||||
|
||||
QVariant
|
||||
UtilsAdapter::getAppValue(const Settings::Key key)
|
||||
{
|
||||
return settingsManager_->getValue(key);
|
||||
}
|
||||
|
||||
void
|
||||
UtilsAdapter::setAppValue(const Settings::Key key, const QVariant& value)
|
||||
{
|
||||
if (key == Settings::Key::BaseZoom) {
|
||||
if (value.toDouble() < 0.1 || value.toDouble() > 2.0)
|
||||
return;
|
||||
}
|
||||
settingsManager_->setValue(key, value);
|
||||
// If we change the lang preference, reload the translations
|
||||
if (key == Settings::Key::LANG) {
|
||||
settingsManager_->loadTranslations();
|
||||
Q_EMIT changeLanguage();
|
||||
} else if (key == Settings::Key::BaseZoom)
|
||||
Q_EMIT changeFontSize();
|
||||
else if (key == Settings::Key::EnableExperimentalSwarm)
|
||||
Q_EMIT showExperimentalCallSwarm();
|
||||
else if (key == Settings::Key::ShowChatviewHorizontally)
|
||||
Q_EMIT chatviewPositionChanged();
|
||||
else if (key == Settings::Key::AppTheme)
|
||||
Q_EMIT appThemeChanged();
|
||||
}
|
||||
|
||||
const QString
|
||||
UtilsAdapter::getProjectCredits()
|
||||
{
|
||||
|
@ -352,34 +392,6 @@ UtilsAdapter::setSystemTrayIconVisible(bool visible)
|
|||
systemTray_->setVisible(visible);
|
||||
}
|
||||
|
||||
QVariant
|
||||
UtilsAdapter::getAppValue(const Settings::Key key)
|
||||
{
|
||||
return settingsManager_->getValue(key);
|
||||
}
|
||||
|
||||
void
|
||||
UtilsAdapter::setAppValue(const Settings::Key key, const QVariant& value)
|
||||
{
|
||||
if (key == Settings::Key::BaseZoom) {
|
||||
if (value.toDouble() < 0.1 || value.toDouble() > 2.0)
|
||||
return;
|
||||
}
|
||||
settingsManager_->setValue(key, value);
|
||||
// If we change the lang preference, reload the translations
|
||||
if (key == Settings::Key::LANG) {
|
||||
settingsManager_->loadTranslations();
|
||||
Q_EMIT changeLanguage();
|
||||
} else if (key == Settings::Key::BaseZoom)
|
||||
Q_EMIT changeFontSize();
|
||||
else if (key == Settings::Key::EnableExperimentalSwarm)
|
||||
Q_EMIT showExperimentalCallSwarm();
|
||||
else if (key == Settings::Key::ShowChatviewHorizontally)
|
||||
Q_EMIT chatviewPositionChanged();
|
||||
else if (key == Settings::Key::AppTheme)
|
||||
Q_EMIT appThemeChanged();
|
||||
}
|
||||
|
||||
QString
|
||||
UtilsAdapter::getDirDocument()
|
||||
{
|
||||
|
|
|
@ -36,8 +36,7 @@
|
|||
#if defined(WIN32) && __has_include(<winrt/Windows.Foundation.h>)
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
|
||||
#define WATCHSYSTEMTHEME \
|
||||
__has_include(<winrt/Windows.UI.ViewManagement.h>)
|
||||
#define WATCHSYSTEMTHEME __has_include(<winrt/Windows.UI.ViewManagement.h>)
|
||||
|
||||
#if WATCHSYSTEMTHEME
|
||||
#include <winrt/Windows.UI.ViewManagement.h>
|
||||
|
@ -74,6 +73,11 @@ public:
|
|||
QObject* parent = nullptr);
|
||||
~UtilsAdapter() = default;
|
||||
|
||||
Q_INVOKABLE QVariant getAppValue(const QString& key, const QVariant& defaultValue = {});
|
||||
Q_INVOKABLE void setAppValue(const QString& key, const QVariant& value);
|
||||
Q_INVOKABLE QVariant getAppValue(const Settings::Key key);
|
||||
Q_INVOKABLE void setAppValue(const Settings::Key key, const QVariant& value);
|
||||
|
||||
Q_INVOKABLE const QString getProjectCredits();
|
||||
Q_INVOKABLE const QString getVersionStr();
|
||||
Q_INVOKABLE void setClipboardText(QString text);
|
||||
|
@ -110,8 +114,6 @@ public:
|
|||
Q_INVOKABLE bool isImage(const QString& fileExt);
|
||||
Q_INVOKABLE QString humanFileSize(qint64 fileSize);
|
||||
Q_INVOKABLE void setSystemTrayIconVisible(bool visible);
|
||||
Q_INVOKABLE QVariant getAppValue(const Settings::Key key);
|
||||
Q_INVOKABLE void setAppValue(const Settings::Key key, const QVariant& value);
|
||||
Q_INVOKABLE QString getDirDocument();
|
||||
Q_INVOKABLE QString getDirScreenshot();
|
||||
Q_INVOKABLE QString getDirDownload();
|
||||
|
|
|
@ -33,7 +33,8 @@ import "components"
|
|||
BaseView {
|
||||
id: root
|
||||
objectName: "WizardView"
|
||||
singlePaneOnly: true
|
||||
|
||||
inhibits: ["ConversationView"]
|
||||
|
||||
// signal to redirect the page to main view
|
||||
signal loaderSourceChangeRequested(int sourceToLoad)
|
||||
|
|
Loading…
Add table
Reference in a new issue