Create a new module for the room info drawer QML.
Create a new module for the room info drawer QML. This also requires moving some QML to LibNeoChat common with other modules. Finally all QML in roominfo is modifed to not depend on app.
This commit is contained in:
124
src/libneochat/qml/GroupChatDrawerHeader.qml
Normal file
124
src/libneochat/qml/GroupChatDrawerHeader.qml
Normal file
@@ -0,0 +1,124 @@
|
||||
// SPDX-FileCopyrightText: 2020 Carl Schwan <carl@carlschwan.eu>
|
||||
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls as QQC2
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.kirigamiaddons.labs.components as KirigamiComponents
|
||||
import org.kde.prison
|
||||
|
||||
import org.kde.neochat
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
/**
|
||||
* @brief The current room that user is viewing.
|
||||
*/
|
||||
required property NeoChatRoom room
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: Kirigami.Units.largeSpacing
|
||||
Layout.topMargin: Kirigami.Units.largeSpacing
|
||||
Layout.bottomMargin: Kirigami.Units.largeSpacing
|
||||
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
|
||||
KirigamiComponents.Avatar {
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.large
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.large
|
||||
|
||||
name: root.room ? root.room.displayName : ""
|
||||
source: root.room ? root.room.avatarMediaUrl : ""
|
||||
|
||||
Rectangle {
|
||||
visible: room.usesEncryption
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
|
||||
width: Kirigami.Units.gridUnit
|
||||
height: Kirigami.Units.gridUnit
|
||||
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
right: parent.right
|
||||
}
|
||||
|
||||
radius: Math.round(width / 2)
|
||||
|
||||
Kirigami.Icon {
|
||||
source: "channel-secure-symbolic"
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
spacing: 0
|
||||
|
||||
Kirigami.Heading {
|
||||
Layout.fillWidth: true
|
||||
text: root.room ? root.room.displayName : i18n("No name")
|
||||
textFormat: Text.PlainText
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
Kirigami.SelectableLabel {
|
||||
Layout.fillWidth: true
|
||||
font: Kirigami.Theme.smallFont
|
||||
textFormat: TextEdit.PlainText
|
||||
visible: root.room && root.room.canonicalAlias
|
||||
text: root.room && root.room.canonicalAlias ? root.room.canonicalAlias : ""
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
}
|
||||
}
|
||||
QQC2.AbstractButton {
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.large
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.large
|
||||
Layout.rightMargin: Kirigami.Units.largeSpacing
|
||||
contentItem: Barcode {
|
||||
id: barcode
|
||||
barcodeType: Barcode.QRCode
|
||||
content: "https://matrix.to/#/" + root.room.id
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
let map = Qt.createComponent('org.kde.neochat', 'QrCodeMaximizeComponent').createObject(QQC2.Overlay.overlay, {
|
||||
text: barcode.content,
|
||||
title: root.room ? root.room.displayName : "",
|
||||
subtitle: root.room ? root.room.id : "",
|
||||
avatarSource: root.room ? root.room.avatarMediaUrl : ""
|
||||
});
|
||||
map.open();
|
||||
}
|
||||
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.text: barcode.content
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.SelectableLabel {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: Kirigami.Units.largeSpacing
|
||||
Layout.rightMargin: Kirigami.Units.largeSpacing
|
||||
|
||||
visible: text.length > 0
|
||||
|
||||
text: root.room && root.room.topic ? root.room.topic : ""
|
||||
textFormat: TextEdit.MarkdownText
|
||||
wrapMode: Text.Wrap
|
||||
onLinkActivated: link => UrlHelper.openUrl(link)
|
||||
onHoveredLinkChanged: if (hoveredLink.length > 0 && hoveredLink !== "1") {
|
||||
applicationWindow().hoverLinkIndicator.text = hoveredLink;
|
||||
} else {
|
||||
applicationWindow().hoverLinkIndicator.text = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
76
src/libneochat/qml/LocationMapItem.qml
Normal file
76
src/libneochat/qml/LocationMapItem.qml
Normal file
@@ -0,0 +1,76 @@
|
||||
// SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
|
||||
// SPDX-FileCopyrightText: 2023 Volker Krause <vkrause@kde.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtLocation
|
||||
import QtPositioning
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.kirigamiaddons.labs.components as KirigamiComponents
|
||||
|
||||
import org.kde.neochat
|
||||
|
||||
/** Location marker for any of the shared location maps. */
|
||||
MapQuickItem {
|
||||
id: root
|
||||
required property real latitude
|
||||
required property real longitude
|
||||
|
||||
required property string asset
|
||||
required property var author
|
||||
|
||||
required property bool isLive
|
||||
|
||||
required property real heading
|
||||
|
||||
anchorPoint.x: sourceItem.width / 2
|
||||
anchorPoint.y: sourceItem.height
|
||||
coordinate: QtPositioning.coordinate(root.latitude, root.longitude)
|
||||
autoFadeIn: false
|
||||
sourceItem: Kirigami.Icon {
|
||||
id: mainIcon
|
||||
width: height
|
||||
height: Kirigami.Units.iconSizes.huge
|
||||
source: "gps"
|
||||
isMask: true
|
||||
color: root.isLive ? Kirigami.Theme.highlightColor : Kirigami.Theme.disabledTextColor
|
||||
|
||||
Kirigami.Icon {
|
||||
anchors.centerIn: parent
|
||||
anchors.verticalCenterOffset: -parent.height / 8
|
||||
visible: root.asset === "m.pin"
|
||||
width: height
|
||||
height: parent.height / 3 + 1
|
||||
source: "pin"
|
||||
isMask: true
|
||||
color: parent.color
|
||||
}
|
||||
KirigamiComponents.Avatar {
|
||||
anchors.centerIn: parent
|
||||
anchors.verticalCenterOffset: -parent.height / 8
|
||||
visible: root.asset === "m.self"
|
||||
width: height
|
||||
height: parent.height / 3 + 1
|
||||
name: root.author.displayName
|
||||
source: root.author.avatarUrl
|
||||
color: root.author.color
|
||||
}
|
||||
|
||||
Kirigami.Icon {
|
||||
id: headingIcon
|
||||
source: "go-up-symbolic"
|
||||
color: parent.color
|
||||
visible: !isNaN(root.heading) && root.isLive
|
||||
anchors.bottom: mainIcon.top
|
||||
anchors.horizontalCenter: mainIcon.horizontalCenter
|
||||
transform: Rotation {
|
||||
origin.x: headingIcon.width / 2
|
||||
origin.y: headingIcon.height + mainIcon.height / 2
|
||||
angle: root.heading
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
211
src/libneochat/qml/SearchPage.qml
Normal file
211
src/libneochat/qml/SearchPage.qml
Normal file
@@ -0,0 +1,211 @@
|
||||
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls as QQC2
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
/**
|
||||
* @brief Component for a generic search page.
|
||||
*
|
||||
* This component provides a header with the search field and a ListView to visualise
|
||||
* search results from the given model.
|
||||
*/
|
||||
Kirigami.ScrollablePage {
|
||||
id: root
|
||||
|
||||
/**
|
||||
* @brief Any additional controls after the search button.
|
||||
*/
|
||||
property alias headerTrailing: headerContent.children
|
||||
|
||||
/**
|
||||
* @brief The model that provides the search results.
|
||||
*
|
||||
* The model needs to provide the following properties:
|
||||
* - searchText
|
||||
* - searching
|
||||
* Where searchText is the text from the searchField and is used to match results
|
||||
* and searching is true while the model is finding results.
|
||||
*
|
||||
* The model must also provide a search() function to start the search if
|
||||
* it doesn't do so when the searchText is changed.
|
||||
*/
|
||||
property alias model: listView.model
|
||||
|
||||
/**
|
||||
* @brief The number of delegates currently in the view.
|
||||
*/
|
||||
property alias count: listView.count
|
||||
|
||||
/**
|
||||
* @brief The delegate to use to visualize the model data.
|
||||
*/
|
||||
property alias modelDelegate: listView.delegate
|
||||
|
||||
/**
|
||||
* @brief The delegate to appear as the header of the list.
|
||||
*/
|
||||
property alias listHeaderDelegate: listView.header
|
||||
|
||||
/**
|
||||
* @brief The delegate to appear as the footer of the list.
|
||||
*/
|
||||
property alias listFooterDelegate: listView.footer
|
||||
|
||||
/**
|
||||
* @brief The placeholder text in the search field.
|
||||
*/
|
||||
property alias searchFieldPlaceholder: searchField.placeholderText
|
||||
|
||||
/**
|
||||
* @brief The text to show when no search term has been entered.
|
||||
*/
|
||||
property alias noSearchPlaceholderMessage: noSearchMessage.text
|
||||
|
||||
/**
|
||||
* @brief The text to show when no results have been found.
|
||||
*/
|
||||
property alias noResultPlaceholderMessage: noResultMessage.text
|
||||
|
||||
/**
|
||||
* @brief The verticalLayoutDirection property of the internal ListView.
|
||||
*/
|
||||
property alias listVerticalLayoutDirection: listView.verticalLayoutDirection
|
||||
|
||||
/**
|
||||
* @brief Set the visibility of the search button.
|
||||
*/
|
||||
property bool showSearchButton: true
|
||||
|
||||
/**
|
||||
* @brief Message to be shown in a custom placeholder.
|
||||
* The custom placeholder will be shown if the text is not empty
|
||||
*/
|
||||
property alias customPlaceholderText: customPlaceholder.text
|
||||
|
||||
/**
|
||||
* @brief icon for the custom placeholder
|
||||
*/
|
||||
property string customPlaceholderIcon: ""
|
||||
|
||||
/**
|
||||
* @brief Force the search field to be focussed.
|
||||
*/
|
||||
function focusSearch() {
|
||||
searchField.forceActiveFocus();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Force the search to be updated if the model has a valid search function.
|
||||
*/
|
||||
function updateSearch() {
|
||||
searchTimer.restart();
|
||||
}
|
||||
|
||||
header: QQC2.Control {
|
||||
padding: Kirigami.Units.largeSpacing
|
||||
|
||||
background: Rectangle {
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
||||
Kirigami.Theme.inherit: false
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
|
||||
Kirigami.Separator {
|
||||
anchors {
|
||||
left: parent.left
|
||||
bottom: parent.bottom
|
||||
right: parent.right
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: RowLayout {
|
||||
id: headerContent
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
|
||||
Kirigami.SearchField {
|
||||
id: searchField
|
||||
focus: true
|
||||
Layout.fillWidth: true
|
||||
Keys.onEnterPressed: searchButton.clicked()
|
||||
Keys.onReturnPressed: searchButton.clicked()
|
||||
onTextChanged: {
|
||||
searchTimer.restart();
|
||||
if (model) {
|
||||
model.searchText = text;
|
||||
}
|
||||
}
|
||||
}
|
||||
QQC2.Button {
|
||||
id: searchButton
|
||||
icon.name: "search"
|
||||
display: QQC2.Button.IconOnly
|
||||
visible: root.showSearchButton
|
||||
text: i18nc("@action:button", "Search")
|
||||
|
||||
onClicked: {
|
||||
if (typeof model.search === 'function') {
|
||||
model.search();
|
||||
}
|
||||
}
|
||||
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.text: text
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
}
|
||||
Timer {
|
||||
id: searchTimer
|
||||
interval: 500
|
||||
running: true
|
||||
onTriggered: if (typeof model.search === 'function') {
|
||||
model.search();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
spacing: 0
|
||||
|
||||
section.property: "section"
|
||||
|
||||
Kirigami.PlaceholderMessage {
|
||||
id: noSearchMessage
|
||||
anchors.centerIn: parent
|
||||
visible: searchField.text.length === 0 && listView.count === 0 && customPlaceholder.text.length === 0
|
||||
}
|
||||
|
||||
Kirigami.PlaceholderMessage {
|
||||
id: noResultMessage
|
||||
anchors.centerIn: parent
|
||||
visible: searchField.text.length > 0 && listView.count === 0 && !root.model.searching && customPlaceholder.text.length === 0
|
||||
}
|
||||
|
||||
Kirigami.PlaceholderMessage {
|
||||
id: customPlaceholder
|
||||
anchors.centerIn: parent
|
||||
visible: searchField.text.length > 0 && listView.count === 0 && !root.model.searching && text.length > 0
|
||||
icon.name: root.customPlaceholderIcon
|
||||
}
|
||||
|
||||
Kirigami.LoadingPlaceholder {
|
||||
anchors.centerIn: parent
|
||||
visible: searchField.text.length > 0 && listView.count === 0 && root.model.searching && customPlaceholder.text.length === 0
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
if (listView.currentIndex > 0) {
|
||||
listView.decrementCurrentIndex();
|
||||
} else {
|
||||
listView.currentIndex = -1; // This is so the list view doesn't appear to have two selected items
|
||||
listView.headerItem.forceActiveFocus(Qt.TabFocusReason);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user