Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85595765
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
63 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 76d4f28..4fac282 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,300 +1,301 @@
function(kazv_add_qml_files)
set(options "")
set(oneValueArgs BASE_DIRECTORY)
set(multiValueArgs SOURCES)
cmake_parse_arguments(PARSE_ARGV 0 kazv_add_qml_files "${options}" "${oneValueArgs}" "${multiValueArgs}")
set(target "${kazv_add_qml_files_UNPARSED_ARGUMENTS}")
set(allSources)
foreach(source ${kazv_add_qml_files_SOURCES})
message(STATUS "Adding source: ${kazv_add_qml_files_BASE_DIRECTORY} / ${source}")
set_source_files_properties(
"${kazv_add_qml_files_BASE_DIRECTORY}/${source}"
PROPERTIES
QT_RESOURCE_ALIAS "${source}"
)
list(APPEND allSources "${kazv_add_qml_files_BASE_DIRECTORY}/${source}")
endforeach()
qt_target_qml_sources(
"${target}"
QML_FILES ${allSources}
)
endfunction()
if(WIN32)
set(KAZV_IS_WINDOWS 1)
else()
set(KAZV_IS_WINDOWS 0)
endif()
configure_file(kazv-version.cpp.in kazv-version.cpp)
configure_file(kazv-platform.hpp.in kazv-platform.hpp)
configure_file(kazv-defs.hpp.in kazv-defs.hpp)
set(kazvqmlmodule_SRCS
qt-job-handler.cpp
qt-job.cpp
${CMAKE_CURRENT_BINARY_DIR}/kazv-version.cpp
matrix-sdk.cpp
kazv-session-lock-guard.cpp
matrix-room.cpp
matrix-room-list.cpp
matrix-room-timeline.cpp
matrix-room-pinned-events-timeline.cpp
matrix-room-member.cpp
matrix-room-member-list-model.cpp
matrix-room-state.cpp
matrix-event-reader.cpp
matrix-event-reader-list-model.cpp
matrix-event-reaction-list-model.cpp
matrix-event-reaction.cpp
matrix-event.cpp
matrix-event-list.cpp
matrix-link.cpp
meta-types.cpp
l10n-provider.cpp
qt-rand-adapter.cpp
helper.cpp
matrix-promise.cpp
kazv-util.cpp
matrix-sticker-pack.cpp
matrix-sticker.cpp
matrix-sticker-pack-list.cpp
matrix-sticker-pack-source.cpp
matrix-user-given-attrs-map.cpp
kazv-abstract-list-model.cpp
qt-promise-handler.cpp
device-mgmt/matrix-device.cpp
device-mgmt/matrix-device-list.cpp
kazv-config.cpp
kazv-path-config.cpp
kazv-io-manager.cpp
kazv-io-job.cpp
kazv-file.cpp
upload-job-model.cpp
kazv-markdown.cpp
kazv-clipboard.cpp
db-store.cpp
)
ecm_qt_declare_logging_category(kazvqmlmodule_SRCS
HEADER kazv-log.hpp
IDENTIFIER kazvLog
CATEGORY_NAME moe.kazv.mxc.kazv
)
qt_add_qml_module(kazvqmlmodule
STATIC
URI moe.kazv.mxc.kazv
VERSION 0.0
SOURCES ${kazvqmlmodule_SRCS}
)
target_link_libraries(kazvqmlmodule PUBLIC
libkazv::kazvall
Qt${QT_MAJOR_VERSION}::Core
Qt${QT_MAJOR_VERSION}::Network
Threads::Threads
Qt${QT_MAJOR_VERSION}::Gui
Qt${QT_MAJOR_VERSION}::Qml
Qt${QT_MAJOR_VERSION}::Quick
Qt${QT_MAJOR_VERSION}::QuickControls2
Qt${QT_MAJOR_VERSION}::Svg
Qt${QT_MAJOR_VERSION}::Concurrent
Qt${QT_MAJOR_VERSION}::Widgets
Qt${QT_MAJOR_VERSION}::Sql
KF${KF_MAJOR_VERSION}::ConfigCore KF${KF_MAJOR_VERSION}::KIOCore
KF${KF_MAJOR_VERSION}::Notifications
KF${KF_MAJOR_VERSION}::CoreAddons
QCoro::Core
${CMARK_TARGET_NAME}
)
target_include_directories(kazvqmlmodule PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
target_include_directories(kazvqmlmodule PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/device-mgmt)
qt_add_qml_module(kazvshortcutsqmlmodule
STATIC
URI moe.kazv.mxc.kazvshortcuts
VERSION 0.0
SOURCES
shortcuts/shortcut-util.cpp
)
target_link_libraries(kazvshortcutsqmlmodule PUBLIC
libkazv::kazvall
Qt${QT_MAJOR_VERSION}::Core
Qt${QT_MAJOR_VERSION}::Gui
Qt${QT_MAJOR_VERSION}::Qml
)
target_include_directories(kazvshortcutsqmlmodule
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/shortcuts
)
add_library(kazvprivlib INTERFACE)
target_link_libraries(kazvprivlib
INTERFACE
kazvqmlmodule
kazvqmlmoduleplugin
kazvshortcutsqmlmodule
kazvshortcutsqmlmoduleplugin
)
qt_add_qml_module(kazvqmlqmlmodule
STATIC
URI moe.kazv.mxc.kazvqml
VERSION 0.0
)
kazv_add_qml_files(kazvqmlqmlmodule
BASE_DIRECTORY contents/ui
SOURCES
Main.qml
About.qml
PageManager.qml
LoginPage.qml
MainPage.qml
TabView.qml
Tab.qml
ClosableScrollablePage.qml
+ ClosableScrollableOverlay.qml
SelfDestroyableOverlaySheet.qml
RoomListView.qml
RoomListViewItemDelegate.qml
RoomPage.qml
RoomPinnedEventsPage.qml
RoomTimelineView.qml
SendMessageBox.qml
EventView.qml
EventViewWrapper.qml
EventViewCompact.qml
EventSourceView.qml
EventHistoryView.qml
EventReactions.qml
Bubble.qml
MediaFileMenu.qml
KazvIOMenu.qml
ConfirmUploadPopup.qml
StickerPicker.qml
AddStickerPopup.qml
StickerPackNameProvider.qml
ConfirmationOverlay.qml
event-types/Simple.qml
event-types/Text.qml
event-types/Emote.qml
event-types/Notice.qml
event-types/State.qml
event-types/TextTemplate.qml
event-types/Image.qml
event-types/File.qml
event-types/Video.qml
event-types/Audio.qml
event-types/MediaBubble.qml
event-types/Redacted.qml
event-types/Reaction.qml
event-types/Fallback.qml
TypingIndicator.qml
EventReadIndicator.qml
SelectableText.qml
ReactToEventPopup.qml
FileHandler.qml
ActionSettingsPage.qml
CreateRoomPage.qml
JoinRoomPage.qml
RoomMemberListView.qml
RoomMemberListViewItemDelegate.qml
UserNameProvider.qml
RoomNameProvider.qml
Completion.qml
AsyncHandler.qml
UploadFileHelper.qml
SettingsPage.qml
settings/ProfileSettings.qml
settings/CacheSettings.qml
room-settings/RoomSettingsPage.qml
room-settings/RoomTagHandler.qml
room-settings/RoomMemberListPage.qml
room-settings/RoomInvitePage.qml
room-settings/RoomStickerPacksPage.qml
room-settings/RoomStickerPackItemDelegate.qml
room-settings/RoomStatePage.qml
device-mgmt/Device.qml
device-mgmt/DeviceList.qml
UserPage.qml
shortcuts/ActionCollection.qml
shortcuts/ActionItem.qml
shortcuts/ActionSettings.qml
shortcuts/ShortcutInput.qml
MessageNotification.qml
Notifier.qml
NotificationAction.qml
AvatarAdapter.qml
ImageAdapter.qml
FileDialogAdapter.qml
FolderDialogAdapter.qml
ScrollablePageAdapter.qml
emoji/Activities.qml
emoji/Flags.qml
emoji/Objects.qml
emoji/SmileysAndEmotion.qml
emoji/TravelAndPlaces.qml
emoji/AnimalsAndNature.qml
emoji/FoodAndDrink.qml
emoji/PeopleAndBody.qml
emoji/Symbols.qml
)
kazv_add_qml_files(kazvqmlqmlmodule
BASE_DIRECTORY js
SOURCES
l10n.js
global-this.js
matrix-helpers.js
)
kazv_add_qml_files(kazvqmlqmlmodule
BASE_DIRECTORY js/transformed-libs
SOURCES
fluent-bundle.js
fluent-sequence.js
fluent-langneg.js
bundled-deps.js
)
target_link_libraries(kazvqmlqmlmodule PUBLIC kazvprivlib)
set(kazv_SRCS
main.cpp
l10n/translations.qrc
)
add_executable(kazv ${kazv_SRCS})
target_link_libraries(kazv
PRIVATE
kazvqmlqmlmodule
kazvqmlqmlmoduleplugin
kazvprivlib
)
if(kazv_LINK_BREEZE_ICONS)
target_link_libraries(kazv PRIVATE KF${KF_MAJOR_VERSION}::BreezeIcons)
endif()
set(kazv_INSTALL_ARGS ${KF_INSTALL_TARGETS_DEFAULT_ARGS})
if(NOT kazv_INSTALL_ARGS)
set(kazv_INSTALL_ARGS ${KF${KF_MAJOR_VERSION}_INSTALL_TARGETS_DEFAULT_ARGS})
endif()
install(TARGETS kazv ${kazv_INSTALL_ARGS})
add_subdirectory(tests)
diff --git a/src/contents/ui/ActionSettingsPage.qml b/src/contents/ui/ActionSettingsPage.qml
index 01c9a21..6f5499a 100644
--- a/src/contents/ui/ActionSettingsPage.qml
+++ b/src/contents/ui/ActionSettingsPage.qml
@@ -1,21 +1,21 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2020-2022 Tusooa Zhu <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import org.kde.kirigami 2.13 as Kirigami
import '.' as Kazv
import 'shortcuts' as KazvShortcuts
-Kazv.ClosableScrollablePage {
+Kazv.ClosableScrollableOverlay {
id: page
property alias actionsToConfigure: settings.actions
title: l10n.get('action-settings-page-title')
KazvShortcuts.ActionSettings {
id: settings
shortcutsConfig: kazvConfig
}
}
diff --git a/src/contents/ui/ClosableScrollableOverlay.qml b/src/contents/ui/ClosableScrollableOverlay.qml
new file mode 100644
index 0000000..a91d2be
--- /dev/null
+++ b/src/contents/ui/ClosableScrollableOverlay.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.2
+
+import '.' as Kazv
+
+Kazv.ScrollablePageAdapter {
+ onBackRequested: (event) => {
+ event.accepted = true;
+ applicationWindow().pageStack.layers.pop();
+ }
+}
diff --git a/src/contents/ui/CreateRoomPage.qml b/src/contents/ui/CreateRoomPage.qml
index f4c264a..bb323c4 100644
--- a/src/contents/ui/CreateRoomPage.qml
+++ b/src/contents/ui/CreateRoomPage.qml
@@ -1,201 +1,201 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2022-2024 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.13 as Kirigami
import '.' as Kazv
import './matrix-helpers.js' as Helpers
import moe.kazv.mxc.kazv 0.0 as MK
-Kazv.ClosableScrollablePage {
+Kazv.ClosableScrollableOverlay {
id: createRoomPage
title: l10n.get('create-room-page-title')
property var creatingRoom: false
property var inviteUserIds: []
property var encryptedChangedOnce: false
ButtonGroup {
id: roomTypeButtons
}
Kirigami.FormLayout {
anchors.fill: parent
ColumnLayout {
Kirigami.FormData.label: l10n.get('create-room-page-type-prompt')
RadioButton {
id: typePublic
objectName: 'typePublicRadio'
checked: true
onCheckedChanged: {
if (!createRoomPage.encryptedChangedOnce) {
encrypted.checked = !checked;
}
}
text: l10n.get('create-room-page-type-public')
ButtonGroup.group: roomTypeButtons
}
RadioButton {
id: typePrivate
objectName: 'typePrivateRadio'
text: l10n.get('create-room-page-type-private')
ButtonGroup.group: roomTypeButtons
}
RadioButton {
id: typeDirect
objectName: 'typeDirectRadio'
text: l10n.get('create-room-page-type-direct')
ButtonGroup.group: roomTypeButtons
}
}
TextField {
id: roomName
objectName: 'roomNameInput'
Kirigami.FormData.label: l10n.get('create-room-page-name-prompt')
placeholderText: l10n.get('create-room-page-name-placeholder')
Layout.fillWidth: true
}
TextField {
id: roomAlias
objectName: 'roomAliasInput'
Kirigami.FormData.label: l10n.get('create-room-page-alias-prompt')
placeholderText: l10n.get('create-room-page-alias-placeholder')
Layout.fillWidth: true
}
TextField {
id: roomTopic
objectName: 'roomTopicInput'
Kirigami.FormData.label: l10n.get('create-room-page-topic-prompt')
placeholderText: l10n.get('create-room-page-topic-placeholder')
Layout.fillWidth: true
}
CheckBox {
id: allowFederate
checked: true
text: l10n.get('create-room-page-allow-federate-prompt')
Layout.fillWidth: true
}
CheckBox {
id: encrypted
objectName: 'encryptedInput'
text: l10n.get('create-room-page-encrypted-prompt')
Layout.fillWidth: true
onToggled: createRoomPage.encryptedChangedOnce = true
}
Item {
Kirigami.FormData.isSection: true
Kirigami.FormData.label: l10n.get('create-room-invite-userids-prompt')
}
ColumnLayout {
Repeater {
model: createRoomPage.inviteUserIds.length
delegate: Kirigami.SwipeListItem {
objectName: 'inviteUserItem_' + index
Layout.fillWidth: true
Layout.minimumWidth: Kirigami.Units.gridUnit * 10
contentItem: RowLayout {
Label {
Layout.fillWidth: true
objectName: 'inviteUserIdLabel'
text: createRoomPage.inviteUserIds[index]
}
}
actions: [
Kirigami.Action {
objectName: 'removeInviteAction'
icon.name: 'list-remove-symbolic'
text: l10n.get('create-room-page-action-remove-invite')
onTriggered: {
createRoomPage.inviteUserIds.splice(index, 1);
// trigger reactivity
createRoomPage.inviteUserIds = createRoomPage.inviteUserIds;
}
}
]
}
}
}
TextField {
id: newInviteUserId
Kirigami.FormData.label: l10n.get('create-room-page-add-invite-prompt')
placeholderText: l10n.get('create-room-page-add-invite-placeholder')
objectName: 'newInviteUserInput'
text: ''
Layout.fillWidth: true
}
Button {
id: addInviteUserButton
objectName: 'addInviteUserButton'
text: l10n.get('create-room-page-action-add-invite')
Layout.fillWidth: true
onClicked: {
createRoomPage.inviteUserIds.push(newInviteUserId.text);
// trigger reactivity
createRoomPage.inviteUserIds = createRoomPage.inviteUserIds;
newInviteUserId.text = '';
}
}
Button {
Layout.fillWidth: true
objectName: 'createRoomButton'
text: l10n.get('create-room-page-action-create-room')
onClicked: createRoomPage.createRoom.call()
}
}
property var createRoom: Kazv.AsyncHandler {
trigger: () => matrixSdk.createRoom(
/* isPrivate = */ typePrivate.checked || typeDirect.checked,
roomName.text,
roomAlias.text,
createRoomPage.inviteUserIds,
/* isDirect = */ typeDirect.checked && createRoomPage.inviteUserIds.length === 1,
/* allowFederate = */ allowFederate.checked,
roomTopic.text,
/* powerLevelContentOverride = */ {},
/* preset = */ typeDirect.checked
? MK.MatrixSdk.TrustedPrivateChat
: typePrivate.checked
? MK.MatrixSdk.PrivateChat
: MK.MatrixSdk.PublicChat,
/* encrypted = */ encrypted.checked,
)
onResolved: {
if (success) {
if (typeDirect.checked && createRoomPage.inviteUserIds.length === 1) {
matrixSdk.addDirectRoom(createRoomPage.inviteUserIds[0], data.roomId);
}
showPassiveNotification(l10n.get('create-room-page-success-prompt'));
pageStack.removePage(createRoomPage);
} else {
showPassiveNotification(l10n.get('create-room-page-failed-prompt', { errorCode: data.errorCode, errorMsg: data.error }));
}
}
}
function presetPage(userId) {
typeDirect.checked = true;
newInviteUserId.text = userId;
addInviteUserButton.click();
}
}
diff --git a/src/contents/ui/JoinRoomPage.qml b/src/contents/ui/JoinRoomPage.qml
index a96f1c6..69d58e0 100644
--- a/src/contents/ui/JoinRoomPage.qml
+++ b/src/contents/ui/JoinRoomPage.qml
@@ -1,80 +1,80 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2022-2024 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import QtQuick 2.1
import org.kde.kirigami 2.4 as Kirigami
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.1
import '.' as Kazv
-Kazv.ClosableScrollablePage {
+Kazv.ClosableScrollableOverlay {
id: joinRoomPage
title: l10n.get('join-room-page-title')
ButtonGroup {
id: visibilityButtons
}
ColumnLayout {
width: parent.width
spacing: Kirigami.Units.largeSpacing
GridLayout {
columns: 2
Label {
text: l10n.get('join-room-page-id-or-alias-prompt')
}
TextField {
id: idOrAlias
objectName: 'idOrAliasInput'
placeholderText: l10n.get('join-room-page-id-or-alias-placeholder')
Layout.fillWidth: true
}
Label {
text: l10n.get('join-room-page-servers-prompt')
}
TextArea {
id: servers
objectName: 'serversInput'
placeholderText: l10n.get('join-room-page-servers-placeholder')
Layout.fillWidth: true
}
}
Button {
objectName: 'joinRoomButton'
text: l10n.get('join-room-page-action-join-room')
onClicked: joinRoomPage.joinRoom()
}
}
property var joinRoomHandler: Kazv.AsyncHandler {
property var serverNames: servers.text.split('\n').map(k => k.trim()).filter(k => k)
property var room: idOrAlias.text
trigger: () => matrixSdk.joinRoom(room, serverNames)
onResolved: {
if (success) {
showPassiveNotification(l10n.get('join-room-page-success-prompt', { room }));
pageStack.removePage(joinRoomPage);
} else {
showPassiveNotification(l10n.get('join-room-page-failed-prompt', { room, errorCode: data.errorCode, errorMsg: data.error }));
}
}
}
function joinRoom()
{
joinRoomHandler.call();
}
function presetPage(roomIdOrAlias, routingServers) {
idOrAlias.text = roomIdOrAlias;
servers.text = routingServers.join('\n');
}
}
diff --git a/src/contents/ui/Main.qml b/src/contents/ui/Main.qml
index f5a5ac6..2dceb16 100644
--- a/src/contents/ui/Main.qml
+++ b/src/contents/ui/Main.qml
@@ -1,381 +1,379 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2020-2023 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import QtQuick
import org.kde.kirigami as Kirigami
import QtQuick.Layouts
import QtQuick.Controls
import moe.kazv.mxc.kazv as MK
import '.' as Kazv
import 'shortcuts' as KazvShortcuts
import 'l10n.js' as L10n
Kirigami.ApplicationWindow {
id: root
property var kazvIOManager: MK.KazvIOManager {
cacheDirectory: kazvConfig.cacheDirectory
}
property bool loadingSession: false
property var matrixSdk: MK.MatrixSdk {
onLoginSuccessful: {
switchToMainPage();
recordLastSession();
root.purgeTimer.start();
}
onLoginFailed: {
console.log("Login Failed");
showPassiveNotification(l10n.get('login-page-request-failed-prompt', { errorCode, errorMsg }));
}
onDiscoverFailed: {
console.log("Discover Failed");
showPassiveNotification(l10n.get('login-page-discover-failed-enter-prompt', { errorCode, errorMsg }));
}
onSessionChanged: {
console.log('session changed');
reloadSdkVariables();
root.purgeTimer.start();
}
onLogoutSuccessful: {
root.loggedIn = false;
- root.mainPage = Qt.createComponent("MainPage.qml").createObject(root);
pageStack.clear();
pushLoginPage();
}
onLogoutFailed: {
console.warn('Logout failed');
showPassiveNotification(l10n.get('logout-failed-prompt', { errorCode, errorMsg }));
}
onLoadSessionFinished: (sessionName, res) => {
root.loadingSession = false;
if (res === MK.MatrixSdk.SessionLoadSuccess) {
console.log('load session successful');
switchToMainPage();
recordLastSession();
matrixSdk.getSpecVersions();
} else {
showPassiveNotification(getSessionLoadError(res, sessionName));
}
}
}
property var loggedIn: !!matrixSdk.token
property var sdkVars: QtObject {
property var roomList: matrixSdk.roomList()
property var userGivenNicknameMap: matrixSdk.userGivenNicknameMap()
property string currentRoomId: ''
}
property var purgeTimer: Timer {
interval: 1000 * 60 * 5
repeat: true
triggeredOnStart: true
onTriggered: () => {
matrixSdk.purgeEventsExceptRooms(
sdkVars.currentRoomId ? [sdkVars.currentRoomId] : []);
}
}
property var l10nProvider: MK.L10nProvider {
}
property var kazvConfig: MK.KazvConfig {
}
function initializeL10n () {
const availableLocales = l10nProvider.availableLocaleCodes();
console.log('available locales:', availableLocales);
const desiredLanguages = [Qt.uiLanguage];
console.log('ui language is: ', desiredLanguages);
const defaultLocale = 'en';
const wantedLocales = L10n.negotiateLanguages(desiredLanguages, availableLocales, defaultLocale);
console.log('wanted locales:', wantedLocales);
const bundles = L10n.generateBundles(wantedLocales, l10nProvider.getFtlData(wantedLocales));
const provider = new L10n.FluentProvider(bundles);
return provider;
}
property var l10n: initializeL10n();
property var confirmLogoutPopup: Kirigami.OverlaySheet {
id: confirmLogoutPopup
title: l10n.get('confirm-logout-popup-title')
ColumnLayout {
Label {
Layout.fillWidth: true
text: l10n.get('confirm-logout-popup-prompt')
}
RowLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignCenter
Button {
text: l10n.get('confirm-logout-popup-accept-button')
onClicked: {
hardLogout();
confirmLogoutPopup.close();
}
}
Button {
text: l10n.get('confirm-logout-popup-cancel-button')
onClicked: confirmLogoutPopup.close();
}
}
}
}
title: l10n.get('app-title')
globalDrawer: Kirigami.GlobalDrawer {
title: l10n.get('global-drawer-title')
titleIcon: "applications-graphics"
property var actionGroupName: 'global-drawer-actions'
actions: [
Kirigami.Action {
objectName: 'switch-account'
text: l10n.get('global-drawer-action-switch-account')
icon.name: 'system-switch-user'
onTriggered: switchAccount()
},
Kirigami.Action {
objectName: 'hard-logout'
text: l10n.get('global-drawer-action-hard-logout')
icon.name: 'application-exit'
onTriggered: confirmLogoutPopup.open()
},
Kirigami.Action {
objectName: 'save'
text: l10n.get('global-drawer-action-save-session')
icon.name: 'document-save'
onTriggered: {
recordLastSession()
matrixSdk.serializeToFile()
}
},
Kirigami.Action {
objectName: 'configure-shortcuts'
text: l10n.get('global-drawer-action-configure-shortcuts')
icon.name: 'configure-shortcuts'
onTriggered: {
pushActionSettingsPage();
}
},
Kirigami.Action {
objectName: 'settings'
text: l10n.get('global-drawer-action-settings')
icon.name: 'configure'
onTriggered: {
pushSettingsPage();
}
},
Kirigami.Action {
objectName: 'create-room'
enabled: root.loggedIn
icon.name: 'contact-new'
text: l10n.get('global-drawer-action-create-room')
onTriggered: {
pushCreateRoomPage();
}
},
Kirigami.Action {
objectName: 'join-room'
enabled: root.loggedIn
text: l10n.get('global-drawer-action-join-room')
icon.name: 'list-add-user'
onTriggered: {
pushJoinRoomPage();
}
},
Kirigami.Action {
objectName: 'aboutAction'
text: l10n.get('global-drawer-action-about')
icon.name: 'help-about'
onTriggered: pageStack.pushDialogLayer(Qt.resolvedUrl('About.qml'))
}
]
}
contextDrawer: Kirigami.ContextDrawer {
id: contextDrawer
}
property var actionCollection: KazvShortcuts.ActionCollection {
id: globalActionCollection
children: [
root.globalDrawer,
root.contextDrawer,
]
shortcutsConfig: kazvConfig
}
property var notifier: Kazv.Notifier {
}
pageStack.initialPage: Qt.resolvedUrl("LoginPage.qml")
- property var mainPage: Kazv.MainPage {}
-
property var emptyPage: Kirigami.Page {
title: l10n.get('empty-room-page-title')
Label {
text: l10n.get('empty-room-page-description')
}
}
signal switchToRoomRequested(string roomId)
property var pageManager: Kazv.PageManager {
pageStack: root.pageStack
sdkVars: root.sdkVars
main: root
}
function activateRoomSettingsPage(room) {
- pageStack.push(Qt.resolvedUrl("room-settings/RoomSettingsPage.qml"), {
+ pageStack.layers.push(Qt.resolvedUrl("room-settings/RoomSettingsPage.qml"), {
room
});
}
function activateRoomPinnedEventsPage(room) {
pageStack.push(Qt.resolvedUrl('RoomPinnedEventsPage.qml'), {
room
});
}
function activateRoomInvitePage(room) {
- pageStack.push(Qt.resolvedUrl("room-settings/RoomInvitePage.qml"), {
+ pageStack.layers.push(Qt.resolvedUrl("room-settings/RoomInvitePage.qml"), {
room
});
}
function activateRoomStickerPacksPage(room) {
- pageStack.push(Qt.resolvedUrl("room-settings/RoomStickerPacksPage.qml"), {
+ pageStack.layers.push(Qt.resolvedUrl("room-settings/RoomStickerPacksPage.qml"), {
room
});
}
function activateRoomStatePage(room) {
- pageStack.push(Qt.resolvedUrl("room-settings/RoomStatePage.qml"), {
+ pageStack.layers.push(Qt.resolvedUrl("room-settings/RoomStatePage.qml"), {
room
});
}
function activateUserPage(user, room, userId) {
- pageStack.push(Qt.resolvedUrl("UserPage.qml"), {
+ pageStack.layers.push(Qt.resolvedUrl("UserPage.qml"), {
userId: userId || user.userId,
user,
room
});
}
function switchToMainPage() {
- pageStack.replace([root.mainPage])
- pageStack.currentIndex = 0
+ pageStack.layers.clear();
+ pageStack.replace([Qt.resolvedUrl('MainPage.qml')]);
+ pageStack.currentIndex = 0;
}
function switchToLoginPage() {
pageStack.replace([Qt.resolvedUrl("LoginPage.qml")])
pageStack.currentIndex = 0
}
function pushLoginPage() {
- pageStack.push(Qt.resolvedUrl("LoginPage.qml"), {
+ pageStack.layers.push(Qt.resolvedUrl("LoginPage.qml"), {
isSwitchingAccount: true,
});
}
function pushActionSettingsPage() {
- pageStack.push(Qt.resolvedUrl("ActionSettingsPage.qml"), {
+ pageStack.layers.push(Qt.resolvedUrl("ActionSettingsPage.qml"), {
actionsToConfigure: globalActionCollection.allActions(),
});
}
function pushSettingsPage() {
- pageStack.push(Qt.resolvedUrl("SettingsPage.qml"));
+ pageStack.layers.push(Qt.resolvedUrl("SettingsPage.qml"));
}
function pushCreateRoomPage() {
- pageStack.push(Qt.resolvedUrl("CreateRoomPage.qml"), {});
+ pageStack.layers.push(Qt.resolvedUrl("CreateRoomPage.qml"), {});
}
function pushJoinRoomPage() {
- pageStack.push(Qt.resolvedUrl("JoinRoomPage.qml"), {});
+ pageStack.layers.push(Qt.resolvedUrl("JoinRoomPage.qml"), {});
}
function sessionNameFor(userId, deviceId) {
return userId + '/' + deviceId;
}
function getSessionLoadError(res, sessionName) {
switch (res) {
case MK.MatrixSdk.SessionNotFound:
return l10n.get('session-load-failure-not-found', { sessionName });
case MK.MatrixSdk.SessionFormatUnknown:
return l10n.get('session-load-failure-format-unknown', { sessionName });
case MK.MatrixSdk.SessionCannotBackup:
return l10n.get('session-load-failure-cannot-backup', { sessionName });
case MK.MatrixSdk.SessionLockFailed:
return l10n.get('session-load-failure-lock-failed', { sessionName });
case MK.MatrixSdk.SessionCannotOpenFile:
return l10n.get('session-load-failure-cannot-open-file', { sessionName });
case MK.MatrixSdk.SessionDeserializeFailed:
return l10n.get('session-load-failure-deserialize-failed', { sessionName });
default:
console.error('loadSession: Encountered an unknown error code');
}
}
function loadSession(sessionName) {
root.loadingSession = true;
matrixSdk.loadSession(sessionName);
}
function loadLastSession() {
console.log('last session is:', kazvConfig.lastSession);
return loadSession(kazvConfig.lastSession);
}
function recordLastSession() {
kazvConfig.lastSession = sessionNameFor(matrixSdk.userId, matrixSdk.deviceId);
}
function reloadSdkVariables() {
sdkVars.roomList = matrixSdk.roomList();
sdkVars.userGivenNicknameMap = matrixSdk.userGivenNicknameMap();
sdkVars.currentRoomId = '';
}
function switchAccount() {
pushLoginPage();
}
function hardLogout() {
matrixSdk.logout();
}
Component.onCompleted: {
actionCollection.setupShortcuts();
loadLastSession();
}
onClosing: {
kazvIOManager.clearJobs()
}
}
diff --git a/src/contents/ui/SettingsPage.qml b/src/contents/ui/SettingsPage.qml
index e2c8f92..69fb3a3 100644
--- a/src/contents/ui/SettingsPage.qml
+++ b/src/contents/ui/SettingsPage.qml
@@ -1,43 +1,43 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2023 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import org.kde.kirigami 2.13 as Kirigami
import '.' as Kazv
import 'settings' as Settings
-Kazv.ClosableScrollablePage {
+Kazv.ClosableScrollableOverlay {
id: settingsPage
title: l10n.get('settings-page-title')
contextualActions: [
Kirigami.Action {
icon.name: 'document-save'
text: l10n.get('settings-save')
onTriggered: { settingsPage.saveRecursively() }
}
]
ColumnLayout {
Settings.ProfileSettings {
id: profileSettings
Layout.fillWidth: true
}
Settings.CacheSettings {
id: cacheSettings
Layout.fillWidth: true
}
}
function saveRecursively() {
profileSettings.save();
cacheSettings.save();
}
}
diff --git a/src/contents/ui/UserPage.qml b/src/contents/ui/UserPage.qml
index 3147869..132cc48 100644
--- a/src/contents/ui/UserPage.qml
+++ b/src/contents/ui/UserPage.qml
@@ -1,394 +1,394 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2020-2023 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import org.kde.kirigami as Kirigami
import moe.kazv.mxc.kazv as MK
import '.' as Kazv
import 'device-mgmt' as KazvDM
import 'matrix-helpers.js' as Helpers
-Kazv.ClosableScrollablePage {
+Kazv.ClosableScrollableOverlay {
id: userPage
property string userId: ''
property var user: ({})
property var nameProvider: Kazv.UserNameProvider {
user: userPage.user
}
property var room
property var roomNameProvider: Kazv.RoomNameProvider {
room: userPage.room
}
property var roomName: roomNameProvider.name
property var editingPowerLevel: false
property var submittingPowerLevel: false
property var powerLevelsLoaded: false
property var userPowerLevel: room.userPowerLevel(userId)
property var kickingUser: false
property var canKickUser: !(user.membership === 'ban' || user.membership === 'leave')
property var banningUser: false
property var unbanningUser: false
Connections {
target: room
function onPowerLevelsChanged() {
userPage.userPowerLevel = room.userPowerLevel(userPage.userId);
}
}
title: nameProvider.name
property var ensureMemberEvent: Kazv.AsyncHandler {
trigger: () => room.ensureStateEvent('m.room.member', userId)
}
property var ensurePowerLevels: Kazv.AsyncHandler {
trigger: () => room.ensureStateEvent('m.room.power_levels', '')
onResolved: (success, data) => {
if (success) {
userPage.powerLevelsLoaded = true;
}
}
}
property var updatingNameOverride: false
property var updateNameOverride: Kazv.AsyncHandler {
trigger: () => {
userPage.updatingNameOverride = true;
return sdkVars.userGivenNicknameMap.setAndUpload(
userPage.userId, nameOverrideInput.text || null);
}
onResolved: (success, data) => {
userPage.updatingNameOverride = false;
if (!success) {
showPassiveNotification(l10n.get('user-page-update-name-override-failed-prompt', { errorCode: data.errorCode, errorMsg: data.error }));
}
}
}
property bool updatingSelfName: false
property var updateSelfName: Kazv.AsyncHandler {
trigger: () => {
userPage.updatingSelfName = true;
return userPage.room.setSelfName(selfNameInput.text);
}
onResolved: (success, data) => {
userPage.updatingSelfName = false;
if (!success) {
showPassiveNotification(l10n.get('user-page-update-self-name-failed-prompt', { errorCode: data.errorCode, errorMsg: data.error }));
}
}
}
Component.onCompleted: {
userPage.ensureMemberEvent.call();
userPage.ensurePowerLevels.call();
}
property var setPowerLevel: Kazv.AsyncHandler {
trigger: () => {
userPage.submittingPowerLevel = true;
return room.setUserPowerLevel(userPage.userId, parseInt(newPowerLevel.text));
}
onResolved: (success, data) => {
if (!success) {
showPassiveNotification(l10n.get('user-page-set-power-level-failed-prompt', { errorCode: data.errorCode, errorMsg: data.error }));
} else {
userPage.editingPowerLevel = false;
}
userPage.submittingPowerLevel = false;
}
}
property var kickUser: Kazv.AsyncHandler {
trigger: () => {
userPage.kickingUser = true;
return room.kickUser(userPage.userId, kickUserReasonInput.text);
}
onResolved: {
if (!success) {
showPassiveNotification(l10n.get('user-page-kick-user-failed-prompt', { errorCode: data.errorCode, errorMsg: data.error }));
} else {
kickUserReasonInput.text = '';
}
userPage.kickingUser = false;
}
}
property var banUser: Kazv.AsyncHandler {
trigger: () => {
userPage.banningUser = true;
return room.banUser(userPage.userId, banUserReasonInput.text);
}
onResolved: {
if (!success) {
showPassiveNotification(l10n.get('user-page-ban-user-failed-prompt', { errorCode: data.errorCode, errorMsg: data.error }));
} else {
banUserReasonInput.text = '';
}
userPage.banningUser = false;
}
}
property var unbanUser: Kazv.AsyncHandler {
trigger: () => {
userPage.unbanningUser = true;
return room.unbanUser(userPage.userId);
}
onResolved: {
if (!success) {
showPassiveNotification(l10n.get('user-page-unban-user-failed-prompt', { errorCode: data.errorCode, errorMsg: data.error }));
}
userPage.unbanningUser = false;
}
}
ColumnLayout {
Kazv.AvatarAdapter {
id: avatar
objectName: 'avatar'
Layout.alignment: Qt.AlignHCenter
Layout.preferredHeight: Kirigami.Units.iconSizes.enormous
Layout.preferredWidth: Kirigami.Units.iconSizes.enormous
mxcUri: userPage.user.avatarMxcUri
name: nameProvider.name
}
ColumnLayout {
Layout.preferredWidth: this.parent.width
Label {
objectName: 'userNameLabel'
Layout.alignment: Qt.AlignHCenter
text: !!userPage.user.name ? userPage.user.name : userPage.userId
}
Label {
objectName: 'userIdLabel'
Layout.alignment: Qt.AlignHCenter
font: Kirigami.Theme.smallFont
visible: !!userPage.user.name
text: userPage.userId
}
}
RowLayout {
visible: room.membership === MK.MatrixRoom.Join && userPage.userId === matrixSdk.userId
TextField {
id: selfNameInput
objectName: 'selfNameInput'
placeholderText: l10n.get('user-page-self-name-placeholder')
Layout.fillWidth: true
Accessible.name: l10n.get('user-page-self-name-prompt')
enabled: !userPage.updatingSelfName
text: userPage.user.name
}
Button {
objectName: 'saveSelfNameButton'
text: l10n.get('user-page-save-self-name-action')
enabled: !userPage.updatingSelfName
onClicked: userPage.updateSelfName.call()
}
}
RowLayout {
// Do not allow user to set a name override for themselves
visible: userPage.userId !== matrixSdk.userId
TextField {
id: nameOverrideInput
objectName: 'nameOverrideInput'
placeholderText: l10n.get('user-page-overrided-name-placeholder')
Layout.fillWidth: true
enabled: !userPage.updatingNameOverride
text: nameProvider.overridedName
}
Button {
objectName: 'saveNameOverrideButton'
text: l10n.get('user-page-save-name-override-action')
enabled: !userPage.updatingNameOverride
onClicked: updateNameOverride.call()
}
}
RowLayout {
visible: !userPage.editingPowerLevel
Label {
objectName: 'powerLevelLabel'
Layout.fillWidth: true
text: l10n.get('user-page-power-level', { powerLevel: userPage.userPowerLevel })
}
Button {
objectName: 'editPowerLevelButton'
text: l10n.get('user-page-edit-power-level-action')
enabled: userPage.powerLevelsLoaded
onClicked: {
userPage.editingPowerLevel = true;
}
}
}
RowLayout {
visible: userPage.editingPowerLevel
TextField {
objectName: 'newPowerLevelInput'
id: newPowerLevel
Layout.fillWidth: true
text: `${userPage.userPowerLevel}`
readOnly: userPage.submittingPowerLevel
}
Button {
objectName: 'savePowerLevelButton'
text: l10n.get('user-page-save-power-level-action')
onClicked: {
setPowerLevel.call();
}
enabled: !userPage.submittingPowerLevel
}
Button {
objectName: 'discardPowerLevelButton'
text: l10n.get('user-page-discard-power-level-action')
enabled: !userPage.submittingPowerLevel
onClicked: {
userPage.editingPowerLevel = false;
newPowerLevel.text = `${userPage.userPowerLevel}`;
}
}
}
ColumnLayout {
Kirigami.PromptDialog {
id: kickUserReasonDialog
objectName: 'kickUserReasonDialog'
title: l10n.get('user-page-kick-user-confirm-dialog-title')
standardButtons: Kirigami.Dialog.Ok | Kirigami.Dialog.Cancel
onAccepted: {
userPage.kickUser.call()
}
ColumnLayout {
Label {
Layout.fillWidth: true
text: l10n.get('user-page-kick-user-confirm-dialog-content', {
userId: userPage.user.userId,
name: nameProvider.name,
roomName: userPage.roomName,
})
wrapMode: Text.Wrap
}
ColumnLayout {
Label {
Layout.fillWidth: true
text: l10n.get('user-page-kick-user-confirm-dialog-content', {
userId: userPage.user.userId,
name: userPage.user.name,
roomName: userPage.roomName,
})
wrapMode: Text.Wrap
}
Kirigami.FormLayout {
Layout.fillWidth: true
TextField {
Layout.fillWidth: true
id: kickUserReasonInput
objectName: 'kickUserReasonInput'
readOnly: userPage.kickingUser
Kirigami.FormData.label: l10n.get('user-page-kick-user-reason-prompt')
}
}
}
}
}
Button {
objectName: 'kickUserButton'
icon.name: 'im-kick-user'
Layout.fillWidth: true
enabled: !userPage.kickingUser
text: l10n.get('user-page-kick-user-action')
visible: userPage.canKickUser
onClicked: {
kickUserReasonDialog.open()
}
}
}
RowLayout {
Kirigami.PromptDialog {
id: banUserReasonDialog
objectName: 'banUserReasonDialog'
title: l10n.get('user-page-ban-user-confirm-dialog-title')
standardButtons: Kirigami.Dialog.Ok | Kirigami.Dialog.Cancel
onAccepted: {
userPage.banUser.call()
}
ColumnLayout {
Label {
Layout.fillWidth: true
text: l10n.get('user-page-ban-user-confirm-dialog-content', {
userId: userPage.user.userId,
name: nameProvider.name,
roomName: userPage.roomName,
})
wrapMode: Text.Wrap
}
Kirigami.FormLayout {
Layout.fillWidth: true
TextField {
Layout.fillWidth: true
id: banUserReasonInput
objectName: 'banUserReasonInput'
readOnly: userPage.banningUser
Kirigami.FormData.label: l10n.get('user-page-ban-user-reason-prompt')
}
}
}
}
Button {
objectName: 'banUserButton'
Layout.fillWidth: true
icon.name: 'im-ban-kick-user'
enabled: !userPage.banningUser
text: l10n.get('user-page-ban-user-action')
visible: !unbanUserButton.visible
onClicked: {
banUserReasonDialog.open()
}
}
Button {
id: unbanUserButton
objectName: 'unbanUserButton'
Layout.fillWidth: true
icon.name: 'im-user-online'
enabled: !userPage.unbanningUser
text: l10n.get('user-page-unban-user-action')
visible: user.membership === "ban"
onClicked: {
userPage.unbanUser.call()
}
}
}
KazvDM.DeviceList {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.minimumHeight: childrenRect.height
userId: userPage.userId
devices: matrixSdk.devicesOfUser(userId)
}
}
}
diff --git a/src/contents/ui/room-settings/RoomInvitePage.qml b/src/contents/ui/room-settings/RoomInvitePage.qml
index e01752b..fa70ca2 100644
--- a/src/contents/ui/room-settings/RoomInvitePage.qml
+++ b/src/contents/ui/room-settings/RoomInvitePage.qml
@@ -1,61 +1,61 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2023 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import org.kde.kirigami 2.20 as Kirigami
import '..' as Kazv
import '../matrix-helpers.js' as Helpers
-Kazv.ClosableScrollablePage {
+Kazv.ClosableScrollableOverlay {
id: roomInvitePage
property var room
property var roomNameProvider: Kazv.RoomNameProvider {
room: roomInvitePage.room
}
property var roomDisplayName: roomNameProvider.name
property var inviting: false
title: l10n.get('room-invite-page-title', { room: roomDisplayName })
property var inviteUser: Kazv.AsyncHandler {
trigger: () => {
roomInvitePage.inviting = true;
return room.inviteUser(inviteUserIdInput.text);
}
onResolved: {
roomInvitePage.inviting = false;
if (!success) {
showPassiveNotification(l10n.get('room-invite-page-invite-failed-prompt', { errorCode: data.errorCode, errorMsg: data.error }));
} else {
pageStack.removePage(roomInvitePage);
}
}
}
Kirigami.FormLayout {
TextField {
id: inviteUserIdInput
objectName: 'inviteUserIdInput'
placeholderText: l10n.get('room-invite-invitee-matrix-id-placeholder')
Kirigami.FormData.label: l10n.get('room-invite-invitee-matrix-id-prompt')
}
Button {
objectName: 'inviteUserButton'
text: l10n.get('room-invite-page-invite-button')
enabled: !roomInvitePage.inviting
Layout.fillWidth: true
onClicked: {
roomInvitePage.inviteUser.call();
}
}
}
}
diff --git a/src/contents/ui/room-settings/RoomMemberListPage.qml b/src/contents/ui/room-settings/RoomMemberListPage.qml
index 5e3532c..ad77622 100644
--- a/src/contents/ui/room-settings/RoomMemberListPage.qml
+++ b/src/contents/ui/room-settings/RoomMemberListPage.qml
@@ -1,34 +1,34 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2023 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import org.kde.kirigami 2.13 as Kirigami
import '../matrix-helpers.js' as Helpers
import '..' as Kazv
-Kazv.ClosableScrollablePage {
+Kazv.ClosableScrollableOverlay {
id: roomSettingsPage
property var room
required property var members
property var roomNameProvider: Kazv.RoomNameProvider {
room: roomSettingsPage.room
}
property var roomDisplayName: roomNameProvider.name
title: l10n.get('room-member-list-page-title', { room: roomDisplayName })
Kazv.RoomMemberListView {
room: roomSettingsPage.room
members: roomSettingsPage.members
}
Component.onCompleted: room.refreshState()
}
diff --git a/src/contents/ui/room-settings/RoomSettingsPage.qml b/src/contents/ui/room-settings/RoomSettingsPage.qml
index 7603b3c..9cb4080 100644
--- a/src/contents/ui/room-settings/RoomSettingsPage.qml
+++ b/src/contents/ui/room-settings/RoomSettingsPage.qml
@@ -1,433 +1,433 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2023 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import org.kde.kirigami 2.20 as Kirigami
import moe.kazv.mxc.kazv 0.0 as MK
import '../matrix-helpers.js' as Helpers
import '..' as Kazv
import '.' as RoomSettings
-Kazv.ClosableScrollablePage {
+Kazv.ClosableScrollableOverlay {
id: roomSettingsPage
property var room
property var roomNameProvider: Kazv.RoomNameProvider {
room: roomSettingsPage.room
}
property var roomDisplayName: roomNameProvider.name
property var customTagIds: room.tagIds.filter(k => k.startsWith('u.'))
property var editingName: false
property var submittingName: false
property var submitName: Kazv.AsyncHandler {
trigger: () => {
roomSettingsPage.submittingName = true;
return roomSettingsPage.room.setName(roomNameEdit.text);
}
onResolved: (success, data) => {
roomSettingsPage.submittingName = false;
if (success) {
roomSettingsPage.editingName = false;
} else {
showPassiveNotification(l10n.get('room-settings-set-name-failed-prompt', {
room: room.roomId,
errorCode: data.errorCode,
errorMsg: data.error,
}));
}
}
}
property var editingTopic: false
property var submittingTopic: false
property var submitTopic: Kazv.AsyncHandler {
trigger: () => {
roomSettingsPage.submittingTopic = true;
return roomSettingsPage.room.setTopic(roomTopicEdit.text);
}
onResolved: (success, data) => {
roomSettingsPage.submittingTopic = false;
if (success) {
roomSettingsPage.editingTopic = false;
} else {
showPassiveNotification(l10n.get('room-settings-set-topic-failed-prompt', {
room: room.roomId,
errorCode: data.errorCode,
errorMsg: data.error,
}));
}
}
}
title: l10n.get('room-settings-page-title', { room: roomDisplayName })
function tagIdToName(tagId) {
return tagId.slice(2);
}
property var encryptionPopup: Kirigami.PromptDialog {
parent: roomSettingsPage.overlay
objectName: 'encryptionPopup'
title: l10n.get('room-settings-enable-encryption-prompt-dialog-title')
standardButtons: Kirigami.Dialog.Ok | Kirigami.Dialog.Cancel
ColumnLayout {
Label {
Layout.fillWidth: true
text: l10n.get('room-settings-enable-encryption-prompt-dialog-prompt')
wrapMode: Text.Wrap
}
}
onAccepted: enableEncryption.call()
}
property var enablingEncryption: false
property var enableEncryption: Kazv.AsyncHandler {
trigger: () => {
roomSettingsPage.enablingEncryption = true;
return room.sendStateEvent({
type: 'm.room.encryption',
state_key: '',
content: {
algorithm: 'm.megolm.v1.aes-sha2',
},
});
}
onResolved: (success, data) => {
roomSettingsPage.enablingEncryption = false;
if (success) {
showPassiveNotification(l10n.get('room-settings-encryption-enabled-notification'));
} else {
showPassiveNotification(l10n.get('room-settings-encryption-failed-to-enable-notification', { errorCode: data.errorCode, errorMsg: data.error }));
}
}
}
property var tagHandler: RoomSettings.RoomTagHandler {
room: roomSettingsPage.room
}
property var members: room.members()
property var avatarCount: 4
ColumnLayout {
RowLayout {
Layout.alignment: Qt.AlignHCenter
Repeater {
objectName: 'roomMembersAvatarsRepeater'
model: Math.min(members.count, roomSettingsPage.avatarCount)
Kazv.AvatarAdapter {
property var member: members.at(index)
property var nameProvider: Kazv.UserNameProvider {
user: member
}
Layout.preferredHeight: Kirigami.Units.iconSizes.huge
Layout.preferredWidth: Kirigami.Units.iconSizes.huge
mxcUri: member.avatarMxcUri
name: nameProvider.name
}
}
Kirigami.Icon {
objectName: 'roomMembersAvatarsMore'
Layout.preferredHeight: Kirigami.Units.iconSizes.huge
Layout.preferredWidth: Kirigami.Units.iconSizes.huge
source: 'go-next-skip'
visible: members.count > roomSettingsPage.avatarCount
}
}
ColumnLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
Label {
objectName: 'roomIdLabel'
Layout.alignment: Qt.AlignHCenter
font: Kirigami.Theme.smallFont
text: room.roomId
}
}
RowLayout {
visible: !roomSettingsPage.editingName
Kazv.SelectableText {
objectName: 'roomNameLabel'
text: room.name || l10n.get('room-settings-name-missing')
wrapMode: Text.Wrap
Kirigami.Theme.colorGroup: !!room.name ? Kirigami.Theme.Normal : Kirigami.Theme.Inactive
Layout.fillWidth: true
}
Button {
Layout.alignment: Qt.AlignTop
objectName: 'editNameButton'
text: l10n.get('room-settings-edit-name-action')
onClicked: {
roomNameEdit.text = room.name;
roomSettingsPage.editingName = true;
}
}
}
RowLayout {
visible: roomSettingsPage.editingName
TextArea {
id: roomNameEdit
objectName: 'roomNameEdit'
Layout.fillWidth: true
wrapMode: Text.Wrap
}
Button {
Layout.alignment: Qt.AlignTop
objectName: 'saveNameButton'
enabled: !roomSettingsPage.submittingName
text: l10n.get('room-settings-save-name-action')
onClicked: roomSettingsPage.submitName.call()
}
Button {
Layout.alignment: Qt.AlignTop
objectName: 'discardNameButton'
enabled: !roomSettingsPage.submittingName
text: l10n.get('room-settings-discard-name-action')
onClicked: roomSettingsPage.editingName = false
}
}
RowLayout {
visible: !roomSettingsPage.editingTopic
Kazv.SelectableText {
objectName: 'roomTopicLabel'
text: room.topic || l10n.get('room-settings-topic-missing')
font.italic: !room.topic
wrapMode: Text.Wrap
Kirigami.Theme.colorGroup: !!room.topic ? Kirigami.Theme.Normal : Kirigami.Theme.Inactive
Layout.fillWidth: true
}
Button {
Layout.alignment: Qt.AlignTop
objectName: 'editTopicButton'
text: l10n.get('room-settings-edit-topic-action')
onClicked: {
roomTopicEdit.text = room.topic;
roomSettingsPage.editingTopic = true;
}
}
}
RowLayout {
visible: roomSettingsPage.editingTopic
TextArea {
id: roomTopicEdit
objectName: 'roomTopicEdit'
Layout.fillWidth: true
wrapMode: Text.Wrap
}
Button {
Layout.alignment: Qt.AlignTop
objectName: 'saveTopicButton'
enabled: !roomSettingsPage.submittingTopic
text: l10n.get('room-settings-save-topic-action')
onClicked: roomSettingsPage.submitTopic.call()
}
Button {
Layout.alignment: Qt.AlignTop
objectName: 'discardTopicButton'
enabled: !roomSettingsPage.submittingTopic
text: l10n.get('room-settings-discard-topic-action')
onClicked: roomSettingsPage.editingTopic = false
}
}
Button {
text: l10n.get('room-settings-members-action')
icon.name: 'im-user'
Layout.fillWidth: true
- onClicked: pageStack.push(Qt.resolvedUrl('RoomMemberListPage.qml'), { room: room, members: room.members() })
+ onClicked: pageStack.layers.push(Qt.resolvedUrl('RoomMemberListPage.qml'), { room: room, members: room.members() })
}
Button {
text: l10n.get('room-settings-banned-members-action')
icon.name: 'im-kick-user'
icon.color: Kirigami.Theme.negativeTextColor
Layout.fillWidth: true
- onClicked: pageStack.push(Qt.resolvedUrl('RoomMemberListPage.qml'), { room: room, members: room.bannedMembers() })
+ onClicked: pageStack.layers.push(Qt.resolvedUrl('RoomMemberListPage.qml'), { room: room, members: room.bannedMembers() })
}
Label {
objectName: 'encryptionIndicator'
Layout.fillWidth: true
text: !!room.encrypted ? l10n.get('room-settings-encrypted') : l10n.get('room-settings-not-encrypted')
}
Button {
objectName: 'enableEncryptionButton'
Layout.fillWidth: true
visible: !room.encrypted
enabled: !roomSettingsPage.enablingEncryption
text: l10n.get('room-settings-enable-encryption-action')
onClicked: encryptionPopup.open()
}
RowLayout {
Layout.fillWidth: true
Label {
text: l10n.get('room-settings-tags')
Layout.fillWidth: true
}
CheckBox {
Layout.alignment: Qt.AlignRight
text: l10n.get('room-settings-favourited')
checkable: true
checked: tagHandler.hasTag('m.favourite')
enabled: tagHandler.available
onToggled: tagHandler.toggleTag('m.favourite')
}
}
ListView {
model: customTagIds.length
Layout.fillWidth: true
Layout.fillHeight: true
Layout.minimumHeight: childrenRect.height
delegate: Kirigami.SwipeListItem {
required property var index
contentItem: RowLayout {
Label {
Layout.fillWidth: true
text: tagIdToName(customTagIds[index])
}
}
actions: [
Kirigami.Action {
enabled: tagHandler.available
icon.name: 'list-remove-symbolic'
text: l10n.get('room-settings-remove-tag')
onTriggered: tagHandler.toggleTag(customTagIds[index])
}
]
}
}
RowLayout {
TextField {
id: newTagName
enabled: tagHandler.available
text: ''
Layout.fillWidth: true
}
Button {
enabled: tagHandler.available
text: l10n.get('room-settings-add-tag')
icon.name: 'list-add'
onClicked: {
tagHandler.toggleTag('u.' + newTagName.text)
}
}
Connections {
target: tagHandler
function onTagAdded(tagId) {
if (tagId === 'u.' + newTagName.text) {
newTagName.text = '';
}
}
}
}
Button {
objectName: 'stickerPacksButton'
text: l10n.get('room-sticker-packs-action')
icon.name: 'smiley'
Layout.fillWidth: true
onClicked: {
activateRoomStickerPacksPage(roomSettingsPage.room);
}
}
Button {
text: l10n.get('room-invite-action')
icon.name: 'list-add-user'
Layout.fillWidth: true
onClicked: {
activateRoomInvitePage(roomSettingsPage.room);
}
}
Button {
text: l10n.get('room-explore-state-action')
Layout.fillWidth: true
onClicked: {
activateRoomStatePage(roomSettingsPage.room);
}
}
Button {
objectName: 'leaveRoomButton'
text: l10n.get('room-leave-action')
icon.name: 'im-ban-kick-user'
icon.color: Kirigami.Theme.negativeTextColor
Layout.fillWidth: true
onClicked: {
confirmLeaveOverlay.open();
}
}
Button {
objectName: 'forgetRoomButton'
text: l10n.get('room-forget-action')
Layout.fillWidth: true
visible: room.membership === MK.MatrixRoom.Leave
onClicked: {
confirmForgetOverlay.open();
}
}
}
property var confirmLeaveOverlay: Kazv.ConfirmationOverlay {
objectName: 'confirmLeaveRoomPopup'
parent: roomSettingsPage.overlay
title: l10n.get('room-leave-confirm-popup-title')
message: l10n.get('room-leave-confirm-popup-message')
confirmActionText: l10n.get('room-leave-confirm-popup-confirm-action')
cancelActionText: l10n.get('room-leave-confirm-popup-cancel-action')
onAccepted: leaveRoomHandler.call()
}
property var leaveRoomHandler: Kazv.AsyncHandler {
trigger: () => room.leaveRoom()
onResolved: {
if (success) {
showPassiveNotification(l10n.get('leave-room-success-prompt', { room: room.roomId }));
inviteOverlay.close();
} else {
showPassiveNotification(l10n.get('leave-room-failed-prompt', { room: room.roomId, errorCode: data.errorCode, errorMsg: data.error }));
}
}
}
property var confirmForgetOverlay: Kazv.ConfirmationOverlay {
objectName: 'confirmForgetRoomPopup'
parent: roomSettingsPage.overlay
title: l10n.get('room-forget-confirm-popup-title')
message: l10n.get('room-forget-confirm-popup-message')
confirmActionText: l10n.get('room-forget-confirm-popup-confirm-action')
cancelActionText: l10n.get('room-forget-confirm-popup-cancel-action')
onAccepted: forgetRoomHandler.call()
}
property var forgetRoomHandler: Kazv.AsyncHandler {
trigger: () => room.forgetRoom()
onResolved: (success, data) => {
if (success) {
showPassiveNotification(l10n.get('forget-room-success-prompt', { room: room.roomId }));
} else {
showPassiveNotification(l10n.get('forget-room-failed-prompt', { room: room.roomId, errorCode: data.errorCode, errorMsg: data.error }));
}
}
}
}
diff --git a/src/contents/ui/room-settings/RoomStatePage.qml b/src/contents/ui/room-settings/RoomStatePage.qml
index 9beca93..cfba1fe 100644
--- a/src/contents/ui/room-settings/RoomStatePage.qml
+++ b/src/contents/ui/room-settings/RoomStatePage.qml
@@ -1,71 +1,71 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2025 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import org.kde.kirigami as Kirigami
import moe.kazv.mxc.kazv 0.0 as MK
import '../matrix-helpers.js' as Helpers
import '..' as Kazv
-Kazv.ClosableScrollablePage {
+Kazv.ClosableScrollableOverlay {
id: roomStatePage
property var room
property var roomNameProvider: Kazv.RoomNameProvider {
room: roomStatePage.room
}
property var roomDisplayName: roomNameProvider.name
property var allState: room.allState()
property string selectedType: ''
title: l10n.get('room-state-page-title', { room: roomDisplayName })
ColumnLayout {
Flow {
id: typeChooser
Layout.fillWidth: true
Repeater {
model: allState.types
Kirigami.Chip {
required property string modelData
objectName: `chip_${modelData}`
closable: false
text: modelData
checkable: true
checked: roomStatePage.selectedType === modelData
onClicked: {
roomStatePage.selectedType = modelData
}
}
}
}
ListView {
id: lv
objectName: 'stateEventList'
model: allState.eventsForType(roomStatePage.selectedType)
Layout.fillWidth: true
Layout.fillHeight: true
Layout.minimumHeight: childrenRect.height
delegate: ColumnLayout {
id: viewItem
property var event: lv.model.at(index)
width: ListView.view.width
Label {
Layout.fillWidth: true
textFormat: Qt.RichText
text: l10n.get('room-state-page-state-key', { stateKey: MK.KazvUtil.escapeHtml(viewItem.event.stateKey) })
}
Kazv.EventViewWrapper {
event: viewItem.event
Layout.fillWidth: true
compactMode: false
displayTime: false
}
}
}
}
}
diff --git a/src/contents/ui/room-settings/RoomStickerPacksPage.qml b/src/contents/ui/room-settings/RoomStickerPacksPage.qml
index b3a4b1f..847707f 100644
--- a/src/contents/ui/room-settings/RoomStickerPacksPage.qml
+++ b/src/contents/ui/room-settings/RoomStickerPacksPage.qml
@@ -1,90 +1,90 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2024 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import org.kde.kirigami as Kirigami
import moe.kazv.mxc.kazv as MK
import '..' as Kazv
import '.' as RoomSettings
import '../matrix-helpers.js' as Helpers
-Kazv.ClosableScrollablePage {
+Kazv.ClosableScrollableOverlay {
id: roomStickerPacksPage
property var room
property var stickerPackList: room.stickerPackList()
property var roomNameProvider: Kazv.RoomNameProvider {
room: roomStickerPacksPage.room
}
title: l10n.get('room-sticker-packs-page-title', {
room: roomNameProvider.name,
})
ListView {
model: roomStickerPacksPage.stickerPackList
delegate: RoomSettings.RoomStickerPackItemDelegate {
required property int index
stickerRoomsEvent: matrixSdk.stickerRoomsEvent()
stickerPack: stickerPackList.at(index)
}
}
actions: [
Kirigami.Action {
objectName: 'addStickerPackAction'
text: l10n.get('room-sticker-packs-page-add-action')
icon.name: 'list-add'
onTriggered: addStickerPackPopup.open()
}
]
property var addStickerPack: Kazv.AsyncHandler {
id: addStickerPack
trigger: () => {
const type = Helpers.roomImagePackEventType;
const stateKey = stickerPackStateKey.text;
const state = room.state(type, stateKey);
const content = state.content;
content.pack = content.pack || {};
content.pack.display_name = stickerPackName.text;
return roomStickerPacksPage.room.sendStateEvent({
type,
state_key: stateKey,
content,
});
}
onResolved: (success, data) => {
if (success) {
showPassiveNotification(l10n.get('room-sticker-packs-page-add-success'));
} else {
showPassiveNotification(l10n.get('room-sticker-packs-page-add-failed', { errorMsg: data.error, errorCode: data.errorCode }));
}
}
}
property var addStickerPackPopup: Kirigami.PromptDialog {
id: addStickerPackPopup
title: l10n.get('room-sticker-packs-page-add-popup-title')
standardButtons: Kirigami.Dialog.Ok | Kirigami.Dialog.Cancel
onAccepted: addStickerPack.call()
Kirigami.FormLayout {
TextField {
id: stickerPackName
objectName: 'stickerPackName'
Kirigami.FormData.label: l10n.get('room-sticker-packs-page-add-popup-name-prompt')
}
TextField {
id: stickerPackStateKey
objectName: 'stickerPackStateKey'
Kirigami.FormData.label: l10n.get('room-sticker-packs-page-add-popup-state-key-prompt')
}
}
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Jul 20, 2:20 AM (1 d, 13 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1695416
Default Alt Text
(63 KB)
Attached To
Mode
rK kazv
Attached
Detach File
Event Timeline
Log In to Comment