Compare commits

...

28 Commits

Author SHA1 Message Date
Joshua Goins
a4e6f0c4c2 Add spell-checking suggestions to the chat bar context menu
This is natively integrated into the existing chat document handler, and
emulates normal Sonnet behavior.
2023-09-13 13:06:05 +00:00
Tobias Fella
6439fa48f9 Adapt to QML api changes 2023-09-13 12:57:27 +00:00
Tobias Fella
823f3cdd4e Remove QML Qt5/Qt6 compatibility hacks 2023-09-13 12:57:27 +00:00
Tobias Fella
f542d0b9fd Change rowStride in runner to qsizetype 2023-09-13 14:53:07 +02:00
Tobias Fella
a43990559b Rename source property of MessageDelegateContextMenu
Starting with Qt6.6, this collides with a FINAL property of Loader and thus doesn't run
2023-09-13 14:16:48 +02:00
Tobias Fella
feb2dbc9fb Don't try finding KStatusNotifierItem on android 2023-09-13 12:05:40 +00:00
Tobias Fella
f299d5a245 Fix KF6 crash in emoji completion 2023-09-13 13:41:08 +02:00
Tobias Fella
d69b8fbf8c Fix compilation on FreeBSD 2023-09-13 13:27:33 +02:00
Tobias Fella
234e5c49c4 Re-enable FreeBSD CI
Was accidentally disabled during a merge
2023-09-13 13:23:45 +02:00
Tobias Fella
cee72b6d48 Remove Qt5 compatibility ifdefs 2023-09-13 11:16:02 +00:00
Tobias Fella
539fdcaf2e Remove compatibility with Qt5 in CMake 2023-09-13 11:09:41 +00:00
Joshua Goins
32b3861c3e Only show the "View Source" message action when dev tools are enabled
This is a very developer-oriented action, and other uses of this dialog
(such as interacting with room state events under a room debug page) is
also locked behind this option.
2023-09-13 07:12:18 +00:00
l10n daemon script
f1076a5ced GIT_SILENT Sync po/docbooks with svn 2023-09-13 02:24:16 +00:00
Joshua Goins
bf8f5705d0 Fix message event source dialog not showing any data 2023-09-12 17:10:23 -04:00
Tobias Fella
2656a93ee7 Disable Qt5 CI 2023-09-12 15:39:25 +00:00
l10n daemon script
cbab810a2e GIT_SILENT Sync po/docbooks with svn 2023-09-12 01:47:54 +00:00
Tobias Fella
e78dfaec34 Use view background color for SpaceDrawer 2023-09-11 20:20:49 +00:00
ivan tkachenko
3cfa773820 Settings: Port to AvatarButton and fix OpenFileDialog lifespan
The dialog won't show again after being closed first time, so we need
to dynamically destroy it on both accept and reject. It helps clear out
any state on its way.
2023-09-11 22:47:33 +03:00
Tobias Fella
94c0e8b6cd Port ChatBar actions to Button
Cleans up the code and improves accessibility
2023-09-11 19:23:13 +00:00
Tobias Fella
35b1f24cb7 Fix roomlist when switching accounts
Fixes #605
2023-09-11 19:03:30 +00:00
Tobias Fella
de3072125e Change all remaining QML file ids to "root" 2023-09-11 20:47:32 +02:00
Tobias Fella
f7d2ffac66 Move Controller::createRoom and Controller::createSpace to NeoChatConnection 2023-09-11 17:55:52 +00:00
James Graham
ff0990bb7c Emit Room Selected from JoinRoomPage
Change the `JoinRoomPage` so that it emits a `roomSelected` signal with the selected delegate's info instead of calling the functions to join or enter the room itself. This is so that the `JoinRoomPage` can be used for other purposes like selecting an existing child to add to a space.
2023-09-11 17:16:12 +00:00
James Graham
8285961c42 Restore compact mode background
Restore compact mode using the darker/lighter depending on color scheme background (i.e. the same as the bubble background) it broke somewhere in the refactor of roompage
2023-09-11 07:19:32 +00:00
James Graham
cd39d5b129 Shutup LinkPreviewDelegate
Make sure that the console isn't spammed having `linkpreviewer` undefined in `LinkPreviewDelegate`, even though it shouldn't ever be and I couldn't find any case where it was but my console was still intermittently getting spammed.
2023-09-11 06:27:13 +00:00
l10n daemon script
83b3fefbf5 GIT_SILENT Sync po/docbooks with svn 2023-09-11 01:48:45 +00:00
l10n daemon script
3718bd716a GIT_SILENT made messages (after extraction) 2023-09-11 00:46:51 +00:00
Akseli Lahtinen
a18257ee17 Taskbar badge highlight counter
Instead of the taskbar badge showing count for all notifications, only show the count for total highlights.
2023-09-10 20:57:39 +00:00
117 changed files with 9250 additions and 8941 deletions

View File

@@ -3,12 +3,8 @@
include:
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/reuse-lint.yml
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/android.yml
# - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/android-qt6.yml
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux.yml
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux-qt6.yml
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/windows.yml
# - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/windows-qt6.yml
# - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd.yml
# - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd-qt6.yml
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/flatpak.yml
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd-qt6.yml
# - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/flatpak.yml

View File

@@ -2,35 +2,7 @@
# SPDX-License-Identifier: BSD-2-Clause
Dependencies:
- 'on': ['Linux/Qt5', 'Android/Qt5', 'FreeBSD/Qt5', 'Windows/Qt5']
'require':
'frameworks/extra-cmake-modules': '@stable'
'frameworks/kcoreaddons': '@stable'
'frameworks/kirigami': '@stable'
'frameworks/ki18n': '@stable'
'frameworks/kconfig': '@stable'
'frameworks/syntax-highlighting': '@stable'
'frameworks/kitemmodels': '@stable'
'frameworks/kquickcharts': '@stable'
'frameworks/knotifications': '@stable'
'libraries/kquickimageeditor': '@stable'
'frameworks/sonnet': '@stable'
'libraries/kirigami-addons': '@latest'
'third-party/libquotient': '@latest'
'third-party/qtkeychain': '@latest'
'third-party/cmark': '@latest'
'third-party/qcoro': '@latest'
- 'on': ['Windows/Qt5', 'Linux/Qt5', 'FreeBSD/Qt5']
'require':
'frameworks/qqc2-desktop-style': '@stable'
'frameworks/kio': '@stable'
'frameworks/kwindowsystem': '@stable'
'frameworks/kconfigwidgets': '@stable'
- 'on': ['Linux/Qt5', 'FreeBSD/Qt5']
'require':
'frameworks/kdbusaddons': '@stable'
- 'on': ['Linux/Qt6', 'Android/Qt6', 'FreeBSD/Qt6', 'Windows/Qt6']
- 'on': ['Linux', 'Android', 'FreeBSD', 'Windows']
'require':
'frameworks/extra-cmake-modules': '@latest-kf6'
'frameworks/kcoreaddons': '@latest-kf6'
@@ -48,21 +20,21 @@ Dependencies:
'third-party/qtkeychain': '@latest'
'third-party/cmark': '@latest'
'third-party/qcoro': '@latest'
- 'on': ['Windows/Qt6', 'Linux/Qt6', 'FreeBSD/Qt6']
- 'on': ['Windows', 'Linux', 'FreeBSD']
'require':
'frameworks/qqc2-desktop-style': '@latest-kf6'
'frameworks/kio': '@latest-kf6'
'frameworks/kwindowsystem': '@latest-kf6'
'frameworks/kconfigwidgets': '@latest-kf6'
- 'on': ['Linux/Qt6', 'FreeBSD/Qt6']
- 'on': ['Linux', 'FreeBSD']
'require':
'frameworks/kdbusaddons': '@latest-kf6'
'frameworks/kstatusnotifieritem': '@latest-kf6'
- 'on': ['Linux/Qt6', 'Linux/Qt5']
- 'on': ['Linux']
'require':
'sdk/selenium-webdriver-at-spi': '@latest-kf6'
Options:
per-test-timeout: 90
require-passing-tests-on: [ 'Linux/Qt5', 'FreeBSD', 'Windows' ]
require-passing-tests-on: [ 'FreeBSD', 'Windows' ]

View File

@@ -14,11 +14,8 @@ set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
set(KF_MIN_VERSION "5.105.0")
set(QT_MIN_VERSION "5.15.2")
if (ANDROID)
set(QT_MIN_VERSION "5.15.10")
endif()
set(KF_MIN_VERSION "5.240.0")
set(QT_MIN_VERSION "6.5")
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)
@@ -48,28 +45,6 @@ if(NEOCHAT_FLATPAK)
include(cmake/Flatpak.cmake)
endif()
if(QT_MAJOR_VERSION STREQUAL "6")
set(BASICLISTITEM_BOLD "font.bold")
set(OVERLAYSHEET_OPEN "onOpened")
set(QTQUICK_MODULE_QML_VERSION "")
set(QTLOCATION_MODULE_QML_VERSION "")
set(QTMULTIMEDIA_MODULE_QML_VERSION "")
set(QTMULTIMEDIA_AUDIO "MediaPlayer")
# in Audio qt6 we don't have it but we disable it in qt5 => it seems ok
set(QTMULTIMEDIA_AUDIO_AUTOLOAD "")
# In Video qml qt6 we don't have it.
set(QTMULTIMEDIA_VIDEO_FLUSHMODE "")
else()
set(BASICLISTITEM_BOLD "bold")
set(OVERLAYSHEET_OPEN "onSheetOpenChanged")
set(QTQUICK_MODULE_QML_VERSION "2.15")
set(QTLOCATION_MODULE_QML_VERSION "5.15")
set(QTMULTIMEDIA_MODULE_QML_VERSION "5.15")
set(QTMULTIMEDIA_AUDIO "Audio")
set(QTMULTIMEDIA_AUDIO_AUTOLOAD "autoLoad: false")
set(QTMULTIMEDIA_VIDEO_FLUSHMODE "flushMode: VideoOutput.FirstFrame")
endif()
set(QUOTIENT_FORCE_NAMESPACED_INCLUDES TRUE)
ecm_setup_version(${PROJECT_VERSION}
@@ -77,25 +52,21 @@ ecm_setup_version(${PROJECT_VERSION}
VERSION_HEADER ${CMAKE_CURRENT_BINARY_DIR}/neochat-version.h
)
find_package(Qt${QT_MAJOR_VERSION} ${QT_MIN_VERSION} NO_MODULE COMPONENTS Core Quick Gui QuickControls2 Multimedia Svg WebView)
set_package_properties(Qt${QT_MAJOR_VERSION} PROPERTIES
find_package(Qt6 ${QT_MIN_VERSION} NO_MODULE COMPONENTS Core Quick Gui QuickControls2 Multimedia Svg WebView)
set_package_properties(Qt6 PROPERTIES
TYPE REQUIRED
PURPOSE "Basic application components"
)
find_package(KF${QT_MAJOR_VERSION} ${KF_MIN_VERSION} COMPONENTS Kirigami2 I18n Notifications Config CoreAddons Sonnet ItemModels)
set_package_properties(KF${QT_MAJOR_VERSION} PROPERTIES
find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami2 I18n Notifications Config CoreAddons Sonnet ItemModels)
set_package_properties(KF6 PROPERTIES
TYPE REQUIRED
PURPOSE "Basic application components"
)
set_package_properties(KF${QT_MAJOR_VERSION}Kirigami2 PROPERTIES
set_package_properties(KF6Kirigami2 PROPERTIES
TYPE REQUIRED
PURPOSE "Kirigami application UI framework"
)
find_package(KF${QT_MAJOR_VERSION}KirigamiAddons 0.7.2 REQUIRED)
if(QT_MAJOR_VERSION STREQUAL "6")
find_package(KF6StatusNotifierItem ${KF_MIN_VERSION} REQUIRED)
endif()
find_package(KF6KirigamiAddons 0.7.2 REQUIRED)
if(ANDROID)
find_package(OpenSSL)
@@ -104,24 +75,20 @@ if(ANDROID)
PURPOSE "Encrypted communications"
)
else()
find_package(Qt${QT_MAJOR_VERSION} ${QT_MIN_VERSION} COMPONENTS Widgets)
find_package(KF${QT_MAJOR_VERSION} ${KF_MIN_VERSION} REQUIRED COMPONENTS QQC2DesktopStyle ConfigWidgets KIO WindowSystem)
set_package_properties(KF${QT_MAJOR_VERSION}QQC2DesktopStyle PROPERTIES
find_package(Qt6 ${QT_MIN_VERSION} COMPONENTS Widgets)
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS QQC2DesktopStyle ConfigWidgets KIO WindowSystem StatusNotifierItem)
set_package_properties(KF6QQC2DesktopStyle PROPERTIES
TYPE RUNTIME
)
ecm_find_qmlmodule(org.kde.syntaxhighlighting 1.0)
endif()
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE)
find_package(KF${QT_MAJOR_VERSION}DBusAddons ${KF_MIN_VERSION} REQUIRED)
find_package(KF6DBusAddons ${KF_MIN_VERSION} REQUIRED)
endif()
if(QT_MAJOR_VERSION STREQUAL "6" AND NOT ANDROID AND NOT WIN32)
set(QUOTIENT_SUFFIX "Qt6")
endif()
find_package(Quotient${QUOTIENT_SUFFIX} 0.7)
set_package_properties(Quotient${QUOTIENT_SUFFIX} PROPERTIES
find_package(QuotientQt6 0.7)
set_package_properties(QuotientQt6 PROPERTIES
TYPE REQUIRED
DESCRIPTION "Qt wrapper around Matrix API"
URL "https://github.com/quotient-im/libQuotient/"
@@ -154,12 +121,12 @@ set_package_properties(KQuickImageEditor PROPERTIES
PURPOSE "Add image editing capability to image attachments"
)
find_package(QCoro${QT_MAJOR_VERSION} 0.4 COMPONENTS Core REQUIRED)
find_package(QCoro6 0.4 COMPONENTS Core REQUIRED)
qcoro_enable_coroutines()
find_package(KF${QT_MAJOR_VERSION}DocTools ${KF_MIN_VERSION})
set_package_properties(KF${QT_MAJOR_VERSION}DocTools PROPERTIES DESCRIPTION
find_package(KF6DocTools ${KF_MIN_VERSION})
set_package_properties(KF6DocTools PROPERTIES DESCRIPTION
"Tools to generate documentation"
TYPE OPTIONAL
)
@@ -181,12 +148,12 @@ add_definitions(-DQT_NO_FOREACH)
add_subdirectory(src)
if (BUILD_TESTING)
find_package(Qt${QT_MAJOR_VERSION} ${QT_MIN_VERSION} NO_MODULE COMPONENTS Test)
find_package(Qt6 ${QT_MIN_VERSION} NO_MODULE COMPONENTS Test)
add_subdirectory(autotests)
add_subdirectory(appiumtests)
endif()
if(KF${QT_MAJOR_VERSION}DocTools_FOUND)
if(KF6DocTools_FOUND)
kdoctools_install(po)
add_subdirectory(doc)
endif()

View File

@@ -159,6 +159,7 @@ to provide a convergent experience across multiple platforms.</p>
<li xml:lang="ko">투표 - MSC3381</li>
<li xml:lang="nl">Polls - MSC3381</li>
<li xml:lang="nn">Avstemmingar  MSC3381</li>
<li xml:lang="pl">Ankiety - MSC3381</li>
<li xml:lang="pt">Inquéritos - MSC3381</li>
<li xml:lang="sl">Polls - MSC3381</li>
<li xml:lang="sv">Polls - MSC3381</li>
@@ -183,6 +184,7 @@ to provide a convergent experience across multiple platforms.</p>
<li xml:lang="ko">스티커 팩 - MSC2545</li>
<li xml:lang="nl">Sticker Packs - MSC2545</li>
<li xml:lang="nn">Klistremerke-pakkar  MSC2545</li>
<li xml:lang="pl">Paczki naklejek - MSC2545</li>
<li xml:lang="pt">Pacotes de Autocolantes - MSC2545</li>
<li xml:lang="sl">Sticker Packs - MSC2545</li>
<li xml:lang="sv">Sticker Packs - MSC2545</li>
@@ -207,6 +209,7 @@ to provide a convergent experience across multiple platforms.</p>
<li xml:lang="ko">위치 이벤트 - MSC3488</li>
<li xml:lang="nl">Locatie gebeurtenissen - MSC3488</li>
<li xml:lang="nn">Posisjonshendingar  MSC3488</li>
<li xml:lang="pl">Wydarzenia w miejscach - MSC3488</li>
<li xml:lang="pt">Eventos com Localizações - MSC3488</li>
<li xml:lang="sl">Location Events - MSC3488</li>
<li xml:lang="sv">Location Events - MSC3488</li>
@@ -294,6 +297,7 @@ to provide a convergent experience across multiple platforms.</p>
<caption xml:lang="ko">대화방 목록, 채팅, 대화방 정보가 표시된 주 보기</caption>
<caption xml:lang="nl">Hoofdweergave met lijst met rooms, chat en roominformatie</caption>
<caption xml:lang="nn">Hovudvising med romliste, pratevindauge og rominformasjon</caption>
<caption xml:lang="pl">Główny widok z wykazem pokojów, rozmowami i szczegółami pokojów</caption>
<caption xml:lang="pt">A área principal com a lista de salas e com informações sobre a conversa e a sala</caption>
<caption xml:lang="sl">Glavni pogled s seznamom sob, klepetom in informacijami o sobah</caption>
<caption xml:lang="sv">Huvudvy med rumslista, chatt, och rumsinformation</caption>
@@ -319,6 +323,7 @@ to provide a convergent experience across multiple platforms.</p>
<caption xml:lang="ko">로그인 화면</caption>
<caption xml:lang="nl">Aanmeldscherm</caption>
<caption xml:lang="nn">Innloggingsbilete</caption>
<caption xml:lang="pl">Ekran logowania</caption>
<caption xml:lang="pt">Ecrã de autenticação</caption>
<caption xml:lang="sl">Prijavni zaslon</caption>
<caption xml:lang="sv">Inloggningsfönster</caption>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -3,15 +3,6 @@
# SPDX-FileCopyrightText: 2020-2021 Tobias Fella <tobias.fella@kde.org>
# SPDX-License-Identifier: BSD-2-Clause
configure_file(qml/Page/RoomList/RoomDelegate.qml ${CMAKE_CURRENT_BINARY_DIR}/qml/Page/RoomList/RoomDelegate.qml)
configure_file(qml/Component/QuickSwitcher.qml ${CMAKE_CURRENT_BINARY_DIR}/qml/Component/QuickSwitcher.qml)
configure_file(qml/Dialog/PowerLevelDialog.qml ${CMAKE_CURRENT_BINARY_DIR}/qml/Dialog/PowerLevelDialog.qml)
configure_file(qml/Component/Timeline/AudioDelegate.qml ${CMAKE_CURRENT_BINARY_DIR}/qml/Component/Timeline/AudioDelegate.qml)
configure_file(qml/Component/Timeline/VideoDelegate.qml ${CMAKE_CURRENT_BINARY_DIR}/qml/Component/Timeline/VideoDelegate.qml)
configure_file(qml/Component/Timeline/OsmLocationPlugin.qml ${CMAKE_CURRENT_BINARY_DIR}/qml/Component/Timeline/OsmLocationPlugin.qml)
configure_file(res.qrc ${CMAKE_CURRENT_SOURCE_DIR}/res.generated.qrc)
add_library(neochat STATIC
controller.cpp
controller.h
@@ -156,7 +147,7 @@ ecm_qt_declare_logging_category(neochat
add_executable(neochat-app
main.cpp
${CMAKE_CURRENT_SOURCE_DIR}/res.generated.qrc
res.qrc
)
if(TARGET Qt::WebView)
@@ -178,13 +169,11 @@ if(NOT ANDROID)
target_sources(neochat PRIVATE colorschemer.cpp colorschemer.h)
if (NOT WIN32 AND NOT APPLE)
target_sources(neochat PRIVATE trayicon_sni.cpp trayicon_sni.h)
if(QT_MAJOR_VERSION STREQUAL "6")
target_link_libraries(neochat PRIVATE KF6::StatusNotifierItem)
endif()
target_link_libraries(neochat PRIVATE KF6::StatusNotifierItem)
else()
target_sources(neochat PRIVATE trayicon.cpp trayicon.h)
endif()
target_link_libraries(neochat PUBLIC KF${QT_MAJOR_VERSION}::ConfigWidgets KF${QT_MAJOR_VERSION}::WindowSystem)
target_link_libraries(neochat PUBLIC KF6::ConfigWidgets KF6::WindowSystem)
target_compile_definitions(neochat PUBLIC -DHAVE_COLORSCHEME)
target_compile_definitions(neochat PUBLIC -DHAVE_WINDOWSYSTEM)
endif()
@@ -199,7 +188,7 @@ else()
endif()
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR})
target_link_libraries(neochat PUBLIC Qt::Core Qt::Quick Qt::Qml Qt::Gui Qt::Multimedia Qt::Network Qt::QuickControls2 KF${QT_MAJOR_VERSION}::I18n KF${QT_MAJOR_VERSION}::Kirigami2 KF${QT_MAJOR_VERSION}::Notifications KF${QT_MAJOR_VERSION}::ConfigCore KF${QT_MAJOR_VERSION}::ConfigGui KF${QT_MAJOR_VERSION}::CoreAddons KF${QT_MAJOR_VERSION}::SonnetCore KF${QT_MAJOR_VERSION}::ItemModels Quotient${QUOTIENT_SUFFIX} cmark::cmark QCoro::Core)
target_link_libraries(neochat PUBLIC Qt::Core Qt::Quick Qt::Qml Qt::Gui Qt::Multimedia Qt::Network Qt::QuickControls2 KF6::I18n KF6::Kirigami2 KF6::Notifications KF6::ConfigCore KF6::ConfigGui KF6::CoreAddons KF6::SonnetCore KF6::ItemModels QuotientQt6 cmark::cmark QCoro::Core)
kconfig_add_kcfg_files(neochat GENERATE_MOC neochatconfig.kcfgc)
@@ -287,7 +276,7 @@ if(ANDROID)
"gps"
)
else()
target_link_libraries(neochat PUBLIC Qt::Widgets KF${QT_MAJOR_VERSION}::KIOWidgets)
target_link_libraries(neochat PUBLIC Qt::Widgets KF6::KIOWidgets)
install(FILES neochat.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFYRCDIR})
endif()
@@ -295,12 +284,12 @@ if(NOT ANDROID)
set_target_properties(neochat-app PROPERTIES OUTPUT_NAME "neochat")
endif()
if(TARGET KF${QT_MAJOR_VERSION}::DBusAddons)
target_link_libraries(neochat PUBLIC KF${QT_MAJOR_VERSION}::DBusAddons)
if(TARGET KF6::DBusAddons)
target_link_libraries(neochat PUBLIC KF6::DBusAddons)
target_compile_definitions(neochat PUBLIC -DHAVE_KDBUSADDONS)
endif()
if (TARGET KF${QT_MAJOR_VERSION}::KIOWidgets)
if (TARGET KF6::KIOWidgets)
target_compile_definitions(neochat PUBLIC -DHAVE_KIO)
endif()

View File

@@ -90,6 +90,11 @@ public:
}),
mentions->end());
}
QStringList suggestions(const QString &word) const
{
return checker->suggest(word);
}
};
ChatDocumentHandler::ChatDocumentHandler(QObject *parent)
@@ -134,7 +139,7 @@ int ChatDocumentHandler::completionStartIndex() const
return 0;
}
#if !defined(Q_OS_ANDROID) && QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
#if !defined(Q_OS_ANDROID)
const long long cursor = cursorPosition();
#else
const auto cursor = cursorPosition();
@@ -263,6 +268,47 @@ void ChatDocumentHandler::complete(int index)
}
}
QStringList ChatDocumentHandler::getSuggestions(int mousePosition)
{
QTextCursor cursorAtMouse(document()->textDocument());
cursorAtMouse.setPosition(mousePosition);
// Get the word under the (mouse-)cursor and see if it is misspelled.
// Don't include apostrophes at the start/end of the word in the selection.
QTextCursor wordSelectCursor(cursorAtMouse);
wordSelectCursor.clearSelection();
wordSelectCursor.select(QTextCursor::WordUnderCursor);
m_selectedWord = wordSelectCursor.selectedText();
return m_highlighter->suggestions(m_selectedWord);
}
bool ChatDocumentHandler::getActive() const
{
return m_highlighter->settings.checkerEnabledByDefault();
}
bool ChatDocumentHandler::getIsWordIsMisspelled() const
{
return !m_highlighter->errors.isEmpty();
}
QString ChatDocumentHandler::getWordUnderMouse() const
{
return m_selectedWord;
}
void ChatDocumentHandler::replaceWord(const QString &word)
{
QTextCursor cursor(document()->textDocument());
const auto &text = m_room->chatBoxText();
auto at = text.indexOf(m_highlighter->previousText);
cursor.setPosition(at);
cursor.setPosition(at + m_highlighter->previousText.length(), QTextCursor::KeepAnchor);
cursor.insertText(word);
}
CompletionModel *ChatDocumentHandler::completionModel() const
{
return m_completionModel;

View File

@@ -87,6 +87,10 @@ class ChatDocumentHandler : public QObject
*/
Q_PROPERTY(int selectionEnd READ selectionEnd WRITE setSelectionEnd NOTIFY selectionEndChanged)
Q_PROPERTY(bool active READ getActive NOTIFY cursorPositionChanged)
Q_PROPERTY(bool wordIsMisspelled READ getIsWordIsMisspelled NOTIFY cursorPositionChanged)
Q_PROPERTY(QString wordUnderMouse READ getWordUnderMouse NOTIFY cursorPositionChanged)
/**
* @brief The current CompletionModel.
*
@@ -133,6 +137,12 @@ public:
Q_INVOKABLE void complete(int index);
Q_INVOKABLE void replaceWord(const QString &word);
Q_INVOKABLE QStringList getSuggestions(int mousePosition);
bool getActive() const;
bool getIsWordIsMisspelled() const;
QString getWordUnderMouse() const;
void updateCompletions();
CompletionModel *completionModel() const;
@@ -178,4 +188,6 @@ private:
CompletionModel::AutoCompletionType m_completionType = CompletionModel::None;
CompletionModel *m_completionModel = nullptr;
QString m_selectedWord;
};

View File

@@ -4,11 +4,7 @@
#include "controller.h"
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
#include <qt5keychain/keychain.h>
#else
#include <qt6keychain/keychain.h>
#endif
#include <KConfig>
#include <KConfigGroup>
@@ -371,36 +367,6 @@ void Controller::saveWindowGeometry()
WindowController::instance().saveGeometry();
}
void Controller::createRoom(const QString &name, const QString &topic)
{
auto createRoomJob = m_connection->createRoom(Connection::PublishRoom, QString(), name, topic, QStringList());
connect(createRoomJob, &CreateRoomJob::failure, this, [this, createRoomJob] {
Q_EMIT errorOccured(i18n("Room creation failed: %1", createRoomJob->errorString()));
});
connectSingleShot(this, &Controller::roomAdded, &RoomManager::instance(), &RoomManager::enterRoom, Qt::QueuedConnection);
}
void Controller::createSpace(const QString &name, const QString &topic)
{
auto createRoomJob = m_connection->createRoom(Connection::UnpublishRoom,
{},
name,
topic,
QStringList(),
{},
{},
false,
{},
{},
QJsonObject{
{"type"_ls, "m.space"_ls},
});
connect(createRoomJob, &CreateRoomJob::failure, this, [this, createRoomJob] {
Q_EMIT errorOccured(i18n("Space creation failed: %1", createRoomJob->errorString()));
});
connectSingleShot(this, &Controller::roomAdded, &RoomManager::instance(), &RoomManager::enterRoom, Qt::QueuedConnection);
}
bool Controller::isOnline() const
{
return m_isOnline;

View File

@@ -113,16 +113,6 @@ public:
*/
bool saveAccessTokenToKeyChain(const Quotient::AccountSettings &account, const QByteArray &accessToken);
/**
* @brief Create new room for a group chat.
*/
Q_INVOKABLE void createRoom(const QString &name, const QString &topic);
/**
* @brief Create new space.
*/
Q_INVOKABLE void createSpace(const QString &name, const QString &topic);
/**
* @brief Join a room.
*/
@@ -216,7 +206,6 @@ Q_SIGNALS:
void userConsentRequired(QUrl url);
void isOnlineChanged(bool isOnline);
void activeConnectionIndexChanged();
void roomAdded(NeoChatRoom *room);
public Q_SLOTS:
void saveWindowGeometry();

View File

@@ -93,4 +93,9 @@ void LinkPreviewer::loadUrlPreview()
}
}
bool LinkPreviewer::empty() const
{
return m_url.isEmpty();
}
#include "moc_linkpreviewer.cpp"

View File

@@ -44,6 +44,13 @@ class LinkPreviewer : public QObject
*/
Q_PROPERTY(QUrl imageSource READ imageSource NOTIFY imageSourceChanged)
/**
* @brief Whether the there is a link to preview.
*
* A linkPreviwer is empty if the URL is empty.
*/
Q_PROPERTY(bool empty READ empty NOTIFY emptyChanged)
public:
explicit LinkPreviewer(QObject *parent = nullptr, const NeoChatRoom *room = nullptr, const QUrl &url = {});
@@ -53,6 +60,7 @@ public:
[[nodiscard]] QString title() const;
[[nodiscard]] QString description() const;
[[nodiscard]] QUrl imageSource() const;
[[nodiscard]] bool empty() const;
private:
const NeoChatRoom *m_currentRoom = nullptr;
@@ -71,5 +79,6 @@ Q_SIGNALS:
void descriptionChanged();
void imageSourceChanged();
void urlChanged();
void emptyChanged();
};
Q_DECLARE_METATYPE(LinkPreviewer *)

View File

@@ -140,19 +140,13 @@ Q_DECL_EXPORT
#endif
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QNetworkProxyFactory::setUseSystemConfiguration(true);
#ifdef HAVE_WEBVIEW
QtWebView::initialize();
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGLRhi);
#endif
#endif
#ifdef Q_OS_ANDROID
QGuiApplication app(argc, argv);
@@ -291,6 +285,7 @@ int main(int argc, char *argv[])
qmlRegisterUncreatableType<NeoChatRoom>("org.kde.neochat", 1, 0, "NeoChatRoom", {});
qmlRegisterUncreatableType<NeoChatConnection>("org.kde.neochat", 1, 0, "NeoChatConnection", {});
qmlRegisterSingletonType(QUrl("qrc:/ContextMenu.qml"), "org.kde.neochat", 1, 0, "ContextMenu");
qRegisterMetaType<User *>("User*");
qRegisterMetaType<User *>("const User*");
qRegisterMetaType<User *>("const Quotient::User*");
@@ -311,10 +306,6 @@ int main(int argc, char *argv[])
return engine->toScriptValue(LocationHelper());
});
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
qRegisterMetaTypeStreamOperators<Emoji>();
#endif
QQmlApplicationEngine engine;
#ifdef HAVE_KDBUSADDONS

View File

@@ -145,7 +145,7 @@ void CompletionModel::updateCompletion()
m_filterModel->setFullText(m_fullText);
m_filterModel->setFilterText(m_text);
m_filterModel->invalidate();
} else if (text().startsWith(QLatin1Char(':')) && !text()[1].isUpper()
} else if (text().startsWith(QLatin1Char(':')) && text().size() > 1 && !text()[1].isUpper()
&& (m_fullText.indexOf(QLatin1Char(':'), 1) == -1
|| (m_fullText.indexOf(QLatin1Char(' ')) != -1 && m_fullText.indexOf(QLatin1Char(':'), 1) > m_fullText.indexOf(QLatin1Char(' '), 1)))) {
m_filterModel->setSourceModel(m_emojiModel);

View File

@@ -22,11 +22,7 @@ bool CompletionProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &so
&& sourceModel()
->data(sourceModel()->index(sourceRow, 0), secondaryFilterRole())
.toString()
#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
.startsWith(QStringView(m_filterText).sliced(1), Qt::CaseInsensitive));
#else
.startsWith(m_filterText.midRef(1), Qt::CaseInsensitive));
#endif
}
bool CompletionProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const

View File

@@ -36,13 +36,13 @@ RoomListModel::RoomListModel(QObject *parent)
m_categoryVisibility[collapsedSection] = false;
}
connect(this, &RoomListModel::notificationCountChanged, this, [this]() {
connect(this, &RoomListModel::highlightCountChanged, this, [this]() {
#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
#ifndef Q_OS_ANDROID
// copied from Telegram desktop
const auto launcherUrl = "application://org.kde.neochat.desktop"_ls;
// Gnome requires that count is a 64bit integer
const qint64 counterSlice = std::min(m_notificationCount, 9999);
const qint64 counterSlice = std::min(m_highlightCount, 9999);
QVariantMap dbusUnityProperties;
if (counterSlice > 0) {
@@ -59,7 +59,7 @@ RoomListModel::RoomListModel(QObject *parent)
QDBusConnection::sessionBus().send(signal);
#endif // Q_OS_ANDROID
#else
qGuiApp->setBadgeNumber(m_notificationCount);
qGuiApp->setBadgeNumber(m_highlightCount);
#endif // QT_VERSION_CHECK(6, 6, 0)
});
connect(&SpaceHierarchyCache::instance(), &SpaceHierarchyCache::spaceHierarchyChanged, this, [this]() {
@@ -144,7 +144,6 @@ void RoomListModel::doAddRoom(Room *r)
m_rooms.append(room);
connectRoomSignals(room);
Q_EMIT roomAdded(room);
Q_EMIT Controller::instance().roomAdded(room);
} else {
qCritical() << "Attempt to add nullptr to the room list";
Q_ASSERT(false);
@@ -162,6 +161,9 @@ void RoomListModel::connectRoomSignals(NeoChatRoom *room)
connect(room, &Room::notificationCountChanged, this, [this, room] {
refresh(room);
});
connect(room, &Room::highlightCountChanged, this, [this, room] {
refresh(room);
});
connect(room, &Room::avatarChanged, this, [this, room] {
refresh(room, {AvatarRole});
});
@@ -178,6 +180,7 @@ void RoomListModel::connectRoomSignals(NeoChatRoom *room)
refresh(room, {LastEventRole, SubtitleTextRole});
});
connect(room, &Room::unreadStatsChanged, this, &RoomListModel::refreshNotificationCount);
connect(room, &Room::highlightCountChanged, this, &RoomListModel::refreshHighlightCount);
}
int RoomListModel::notificationCount() const
@@ -185,6 +188,11 @@ int RoomListModel::notificationCount() const
return m_notificationCount;
}
int RoomListModel::highlightCount() const
{
return m_highlightCount;
}
void RoomListModel::refreshNotificationCount()
{
int count = 0;
@@ -198,6 +206,19 @@ void RoomListModel::refreshNotificationCount()
Q_EMIT notificationCountChanged();
}
void RoomListModel::refreshHighlightCount()
{
int count = 0;
for (auto room : std::as_const(m_rooms)) {
count += room->highlightCount();
}
if (m_highlightCount == count) {
return;
}
m_highlightCount = count;
Q_EMIT highlightCountChanged();
}
void RoomListModel::updateRoom(Room *room, Room *prev)
{
// There are two cases when this method is called:

View File

@@ -85,6 +85,7 @@ public:
void setConnection(Quotient::Connection *connection);
[[nodiscard]] int notificationCount() const;
[[nodiscard]] int highlightCount() const;
/**
* @brief Get the given role value at the given index.
@@ -155,6 +156,7 @@ private Q_SLOTS:
void deleteRoom(Quotient::Room *room);
void refresh(NeoChatRoom *room, const QVector<int> &roles = {});
void refreshNotificationCount();
void refreshHighlightCount();
private:
Quotient::Connection *m_connection = nullptr;
@@ -163,6 +165,7 @@ private:
QMap<int, bool> m_categoryVisibility;
int m_notificationCount = 0;
int m_highlightCount = 0;
QString m_activeSpaceId;
void connectRoomSignals(NeoChatRoom *room);
@@ -170,6 +173,7 @@ private:
Q_SIGNALS:
void connectionChanged();
void notificationCountChanged();
void highlightCountChanged();
void roomAdded(NeoChatRoom *_t1);
};

View File

@@ -8,15 +8,15 @@
#include "controller.h"
#include "jobs/neochatchangepasswordjob.h"
#include "jobs/neochatdeactivateaccountjob.h"
#include "roommanager.h"
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
#include <qt5keychain/keychain.h>
#else
#include <qt6keychain/keychain.h>
#endif
#include <KLocalizedString>
#include <Quotient/csapi/content-repo.h>
#include <Quotient/csapi/profile.h>
#include <Quotient/qt_connection_util.h>
#include <Quotient/settings.h>
#include <Quotient/user.h>
@@ -156,4 +156,26 @@ void NeoChatConnection::deactivateAccount(const QString &password)
});
}
void NeoChatConnection::createRoom(const QString &name, const QString &topic)
{
const auto job = Connection::createRoom(Connection::PublishRoom, {}, name, topic, {});
connect(job, &CreateRoomJob::failure, this, [this, job] {
Q_EMIT Controller::instance().errorOccured(i18n("Room creation failed: %1", job->errorString()));
});
connectSingleShot(this, &Connection::newRoom, this, [](Room *room) {
RoomManager::instance().enterRoom(dynamic_cast<NeoChatRoom *>(room));
});
}
void NeoChatConnection::createSpace(const QString &name, const QString &topic)
{
const auto job = Connection::createRoom(Connection::UnpublishRoom, {}, name, topic, {}, {}, {}, false, {}, {}, QJsonObject{{"type"_ls, "m.space"_ls}});
connect(job, &CreateRoomJob::failure, this, [this, job] {
Q_EMIT Controller::instance().errorOccured(i18n("Space creation failed: %1", job->errorString()));
});
connectSingleShot(this, &Connection::newRoom, this, [](Room *room) {
RoomManager::instance().enterRoom(dynamic_cast<NeoChatRoom *>(room));
});
}
#include "moc_neochatconnection.cpp"

View File

@@ -48,6 +48,16 @@ public:
Q_INVOKABLE void deactivateAccount(const QString &password);
/**
* @brief Create new room for a group chat.
*/
Q_INVOKABLE void createRoom(const QString &name, const QString &topic);
/**
* @brief Create new space.
*/
Q_INVOKABLE void createSpace(const QString &name, const QString &topic);
Q_SIGNALS:
void labelChanged();
};

View File

@@ -178,17 +178,9 @@ QCoro::Task<void> NeoChatRoom::doUploadFile(QUrl url, QString body)
content = new EventContent::AudioContent(url, fileInfo.size(), mime, fileInfo.fileName());
} else if (mime.name().startsWith("video/"_ls)) {
QMediaPlayer player;
#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
player.setSource(url);
#else
player.setMedia(url);
#endif
co_await qCoro(&player, &QMediaPlayer::mediaStatusChanged);
#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
auto resolution = player.metaData().value(QMediaMetaData::Resolution).toSize();
#else
auto resolution = player.metaData(QMediaMetaData::Resolution).toSize();
#endif
content = new EventContent::VideoContent(url, fileInfo.size(), mime, resolution, fileInfo.fileName());
} else {
content = new EventContent::FileContent(url, fileInfo.size(), mime, fileInfo.fileName());

View File

@@ -177,6 +177,18 @@ QQC2.Control {
interval: 5000
}
TapHandler {
enabled: true
acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus
acceptedButtons: Qt.LeftButton | Qt.RightButton
// unfortunately, taphandler's pressed event only triggers when the press is lifted
// we need to use the longpress signal since it triggers when the button is first pressed
longPressThreshold: 0
onLongPressed: ContextMenu.targetClick(point, textField, documentHandler, textField.positionAt(point.position.x, point.position.y));
}
onTextChanged: {
if (!repeatTimer.running && Config.typingNotifications) {
var textExists = text.length > 0
@@ -357,38 +369,26 @@ QQC2.Control {
QQC2.ToolTip.text: text
QQC2.ToolTip.visible: hovered
}
Row {
RowLayout {
id: actionsRow
padding: Kirigami.Units.smallSpacing
spacing: Kirigami.Units.smallSpacing
anchors.right: parent.right
property var requiredMargin: (root.width - chatBarSizeHelper.currentWidth) / 2 + Kirigami.Units.largeSpacing + (chatBarScrollView.QQC2.ScrollBar.vertical.visible && !(root.width > chatBarSizeHelper.currentWidth) ? Kirigami.Units.largeSpacing * 2.5 : 0)
anchors.bottom: parent.bottom
anchors.leftMargin: layoutDirection === Qt.RightToLeft ? requiredMargin : 0
anchors.rightMargin: layoutDirection === Qt.RightToLeft ? 0 : requiredMargin
anchors.bottom: parent.bottom
anchors.bottomMargin: Kirigami.Units.largeSpacing - 2
anchors.bottomMargin: Kirigami.Units.smallSpacing
spacing: 0
property var requiredMargin: (root.width - chatBarSizeHelper.currentWidth) / 2 + Kirigami.Units.largeSpacing + (chatBarScrollView.QQC2.ScrollBar.vertical.visible && !(root.width > chatBarSizeHelper.currentWidth) ? Kirigami.Units.largeSpacing * 2.5 : 0)
Repeater {
model: root.actions
Kirigami.Icon {
implicitWidth: Kirigami.Units.iconSizes.smallMedium
implicitHeight: Kirigami.Units.iconSizes.smallMedium
delegate: QQC2.ToolButton {
Layout.alignment: Qt.AlignVCenter
icon.name: modelData.isBusy ? "" : (modelData.icon.name.length > 0 ? modelData.icon.name : modelData.icon.source)
onClicked: modelData.trigger()
source: modelData.isBusy ? "" : (modelData.icon.name.length > 0 ? modelData.icon.name : modelData.icon.source)
active: actionArea.containsPress
visible: modelData.visible
enabled: modelData.enabled
MouseArea {
id: actionArea
anchors.fill: parent
onClicked: modelData.trigger()
cursorShape: Qt.PointingHandCursor
}
QQC2.ToolTip.visible: modelData.tooltip !== "" && hoverHandler.hovered
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.text: modelData.tooltip
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
HoverHandler { id: hoverHandler }
PieProgressBar {
visible: modelData.isBusy

View File

@@ -14,7 +14,7 @@ import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.neochat 1.0
QQC2.Popup {
id: completionMenu
id: root
width: parent.width
visible: completions.count > 0
@@ -38,7 +38,7 @@ QQC2.Popup {
}
function complete() {
completionMenu.chatDocumentHandler.complete(completions.currentIndex)
root.chatDocumentHandler.complete(completions.currentIndex)
}
leftPadding: 0
@@ -52,7 +52,7 @@ QQC2.Popup {
id: completions
anchors.fill: parent
model: completionMenu.chatDocumentHandler.completionModel
model: root.chatDocumentHandler.completionModel
currentIndex: 0
keyNavigationWraps: true
highlightMoveDuration: 100
@@ -81,7 +81,7 @@ QQC2.Popup {
subtitleItem.textFormat: Text.PlainText
}
}
onClicked: completionMenu.chatDocumentHandler.complete(completionDelegate.index)
onClicked: root.chatDocumentHandler.complete(completionDelegate.index)
}
}

View File

@@ -0,0 +1,245 @@
pragma Singleton
import QtQuick 2.6
import QtQml 2.2
import QtQuick.Controls 2.15
import org.kde.kirigami 2.5 as Kirigami
Menu {
id: contextMenu
property Item target
property bool deselectWhenMenuClosed: true
property int restoredCursorPosition: 0
property int restoredSelectionStart
property int restoredSelectionEnd
property bool persistentSelectionSetting
property var chatdocumenthandler: null
property var suggestions: []
Component.onCompleted: persistentSelectionSetting = persistentSelectionSetting // break binding
property var runOnMenuClose: () => {}
parent: Overlay.overlay
function storeCursorAndSelection() {
contextMenu.restoredCursorPosition = target.cursorPosition;
contextMenu.restoredSelectionStart = target.selectionStart;
contextMenu.restoredSelectionEnd = target.selectionEnd;
}
// target is pressed with mouse
function targetClick(handlerPoint, newTarget, chatdocumenthandler, mousePosition) {
if (handlerPoint.pressedButtons === Qt.RightButton) { // only accept just right click
if (contextMenu.visible) {
deselectWhenMenuClosed = false; // don't deselect text if menu closed by right click on textfield
dismiss();
} else {
contextMenu.target = newTarget;
contextMenu.target.persistentSelection = true; // persist selection when menu is opened
contextMenu.chatdocumenthandler = chatdocumenthandler;
contextMenu.suggestions = mousePosition ? chatdocumenthandler.getSuggestions(mousePosition) : [];
storeCursorAndSelection();
popup(contextMenu.target);
// slightly locate context menu away from mouse so no item is selected when menu is opened
x += 1
y += 1
}
} else {
dismiss();
}
}
// context menu keyboard key
function targetKeyPressed(event, newTarget) {
if (event.modifiers === Qt.NoModifier && event.key === Qt.Key_Menu) {
contextMenu.target = newTarget;
target.persistentSelection = true; // persist selection when menu is opened
storeCursorAndSelection();
popup(contextMenu.target);
}
}
readonly property bool targetIsPassword: target !== null && (target.echoMode === TextInput.PasswordEchoOnEdit || target.echoMode === TextInput.Password)
onAboutToShow: {
if (Overlay.overlay) {
let tempZ = 0
for (let i in Overlay.overlay.visibleChildren) {
tempZ = Math.max(tempZ, Overlay.overlay.visibleChildren[i].z)
}
z = tempZ + 1
}
}
// deal with whether or not text should be deselected
onClosed: {
// restore text field's original persistent selection setting
target.persistentSelection = persistentSelectionSetting
// deselect text field text if menu is closed not because of a right click on the text field
if (deselectWhenMenuClosed) {
target.deselect();
}
deselectWhenMenuClosed = true;
// restore cursor position
target.forceActiveFocus();
target.cursorPosition = restoredCursorPosition;
target.select(restoredSelectionStart, restoredSelectionEnd);
// run action, and free memory
runOnMenuClose();
runOnMenuClose = () => {};
}
onOpened: {
runOnMenuClose = () => {};
}
Instantiator {
active: target !== null && !target.readOnly && chatdocumenthandler !== null && chatdocumenthandler.active && chatdocumenthandler.wordIsMisspelled
model: suggestions
delegate: MenuItem {
text: modelData
onClicked: {
deselectWhenMenuClosed = false;
runOnMenuClose = () => chatdocumenthandler.replaceWord(modelData);
}
}
onObjectAdded: {
contextMenu.insertItem(0, object)
}
onObjectRemoved: contextMenu.removeItem(0)
}
MenuItem {
visible: target !== null && !target.readOnly && chatdocumenthandler !== null && chatdocumenthandler.active && chatdocumenthandler.wordIsMisspelled && suggestions.length === 0
action: Action {
text: chatdocumenthandler ? qsTr("No suggestions for \"%1\"").arg(chatdocumenthandler.wordUnderMouse) : ''
enabled: false
}
}
MenuItem {
visible: target !== null && !target.readOnly && chatdocumenthandler !== null && chatdocumenthandler.active && chatdocumenthandler.wordIsMisspelled
action: Action {
text: chatdocumenthandler ? qsTr("Add \"%1\" to dictionary").arg(chatdocumenthandler.wordUnderMouse) : ''
onTriggered: {
deselectWhenMenuClosed = false;
runOnMenuClose = () => chatdocumenthandler.addWordToDictionary(chatdocumenthandler.wordUnderMouse);
}
}
}
MenuItem {
visible: target !== null && !target.readOnly && chatdocumenthandler !== null && chatdocumenthandler.active && chatdocumenthandler.wordIsMisspelled
action: Action {
text: qsTr("Ignore")
onTriggered: {
deselectWhenMenuClosed = false;
runOnMenuClose = () => chatdocumenthandler.ignoreWord(chatdocumenthandler.wordUnderMouse);
}
}
}
MenuSeparator {
visible: target !== null && !target.readOnly && ((chatdocumenthandler !== null && chatdocumenthandler.active && chatdocumenthandler.wordIsMisspelled))
}
MenuItem {
visible: target !== null && !target.readOnly && !targetIsPassword
action: Action {
icon.name: "edit-undo-symbolic"
text: qsTr("Undo")
shortcut: StandardKey.Undo
}
enabled: target !== null && target.canUndo
onTriggered: {
deselectWhenMenuClosed = false;
runOnMenuClose = () => target.undo();
}
}
MenuItem {
visible: target !== null && !target.readOnly && !targetIsPassword
action: Action {
icon.name: "edit-redo-symbolic"
text: qsTr("Redo")
shortcut: StandardKey.Redo
}
enabled: target !== null && target.canRedo
onTriggered: {
deselectWhenMenuClosed = false;
runOnMenuClose = () => target.redo();
}
}
MenuSeparator {
visible: target !== null && !target.readOnly && !targetIsPassword
}
MenuItem {
visible: target !== null && !target.readOnly && !targetIsPassword
action: Action {
icon.name: "edit-cut-symbolic"
text: qsTr("Cut")
shortcut: StandardKey.Cut
}
enabled: target !== null && target.selectedText
onTriggered: {
deselectWhenMenuClosed = false;
runOnMenuClose = () => target.cut();
}
}
MenuItem {
action: Action {
icon.name: "edit-copy-symbolic"
text: qsTr("Copy")
shortcut: StandardKey.Copy
}
enabled: target !== null && target.selectedText
visible: !targetIsPassword
onTriggered: {
deselectWhenMenuClosed = false;
runOnMenuClose = () => target.copy();
}
}
MenuItem {
visible: target !== null && !target.readOnly
action: Action {
icon.name: "edit-paste-symbolic"
text: qsTr("Paste")
shortcut: StandardKey.Paste
}
enabled: target !== null && target.canPaste
onTriggered: {
deselectWhenMenuClosed = false;
runOnMenuClose = () => target.paste();
}
}
MenuItem {
visible: target !== null && !target.readOnly
action: Action {
icon.name: "edit-delete-symbolic"
text: qsTr("Delete")
shortcut: StandardKey.Delete
}
enabled: target !== null && target.selectedText
onTriggered: {
deselectWhenMenuClosed = false;
runOnMenuClose = () => target.remove(target.selectionStart, target.selectionEnd);
}
}
MenuSeparator {
visible: !targetIsPassword
}
MenuItem {
action: Action {
icon.name: "edit-select-all-symbolic"
text: qsTr("Select All")
shortcut: StandardKey.SelectAll
}
visible: !targetIsPassword
onTriggered: {
deselectWhenMenuClosed = false;
runOnMenuClose = () => target.selectAll();
}
}
}

View File

@@ -6,15 +6,15 @@ import QtQuick.Controls 2.15 as QQC2
import org.kde.kirigami 2.20 as Kirigami
QQC2.ItemDelegate {
id: emojiDelegate
id: root
property string name
property string emoji
property bool showTones: false
property bool isImage: false
QQC2.ToolTip.text: emojiDelegate.name
QQC2.ToolTip.visible: hovered && emojiDelegate.name !== ""
QQC2.ToolTip.text: root.name
QQC2.ToolTip.visible: hovered && root.name !== ""
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
leftInset: Kirigami.Units.smallSpacing
topInset: Kirigami.Units.smallSpacing
@@ -24,8 +24,8 @@ QQC2.ItemDelegate {
contentItem: Item {
Kirigami.Heading {
anchors.fill: parent
visible: !emojiDelegate.emoji.startsWith("image") && !emojiDelegate.isImage
text: emojiDelegate.emoji
visible: !root.emoji.startsWith("image") && !root.isImage
text: root.emoji
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.family: "emoji"
@@ -36,25 +36,25 @@ QQC2.ItemDelegate {
source: "arrow-down"
anchors.bottom: parent.bottom
anchors.right: parent.right
visible: emojiDelegate.showTones
visible: root.showTones
}
}
Image {
anchors.fill: parent
visible: emojiDelegate.emoji.startsWith("image") || emojiDelegate.isImage
source: visible ? emojiDelegate.emoji : ""
visible: root.emoji.startsWith("image") || root.isImage
source: visible ? root.emoji : ""
}
}
background: Rectangle {
color: emojiDelegate.checked ? Kirigami.Theme.highlightColor : Kirigami.Theme.backgroundColor
color: root.checked ? Kirigami.Theme.highlightColor : Kirigami.Theme.backgroundColor
radius: Kirigami.Units.smallSpacing
Rectangle {
radius: Kirigami.Units.smallSpacing
anchors.fill: parent
color: Kirigami.Theme.highlightColor
opacity: emojiDelegate.hovered && !emojiDelegate.pressed ? 0.2 : 0
opacity: root.hovered && !root.pressed ? 0.2 : 0
}
}
}

View File

@@ -7,7 +7,7 @@ import org.kde.kirigami 2.20 as Kirigami
import org.kde.neochat 1.0
QQC2.ScrollView {
id: emojiGrid
id: root
property alias model: emojis.model
property alias count: emojis.count
@@ -40,10 +40,10 @@ QQC2.ScrollView {
}
onModelChanged: currentIndex = -1
cellWidth: emojis.width / emojiGrid.emojisPerRow
cellHeight: emojiGrid.targetIconSize
cellWidth: emojis.width / root.emojisPerRow
cellHeight: root.targetIconSize
KeyNavigation.up: emojiGrid.header
KeyNavigation.up: root.header
clip: true
@@ -56,14 +56,14 @@ QQC2.ScrollView {
width: emojis.cellWidth
height: emojis.cellHeight
isImage: emojiGrid.stickers
isImage: root.stickers
Keys.onEnterPressed: clicked()
Keys.onReturnPressed: clicked()
onClicked: {
if (emojiGrid.stickers) {
emojiGrid.stickerChosen(model.index)
if (root.stickers) {
root.stickerChosen(model.index)
}
emojiGrid.chosen(modelData.isCustom ? modelData.shortName : modelData.unicode)
root.chosen(modelData.isCustom ? modelData.shortName : modelData.unicode)
EmojiModel.emojiUsed(modelData)
}
Keys.onSpacePressed: pressAndHold()
@@ -71,7 +71,7 @@ QQC2.ScrollView {
if (EmojiModel.tones(modelData.shortName).length === 0) {
return;
}
let tones = tonesPopupComponent.createObject(emojiDelegate, {shortName: modelData.shortName, unicode: modelData.unicode, categoryIconSize: emojiGrid.targetIconSize})
let tones = tonesPopupComponent.createObject(emojiDelegate, {shortName: modelData.shortName, unicode: modelData.unicode, categoryIconSize: root.targetIconSize})
tones.open()
tones.forceActiveFocus()
}
@@ -80,14 +80,14 @@ QQC2.ScrollView {
Kirigami.PlaceholderMessage {
anchors.centerIn: parent
text: emojiGrid.stickers ? i18n("No stickers") : i18n("No emojis")
text: root.stickers ? i18n("No stickers") : i18n("No emojis")
visible: emojis.count === 0
}
}
Component {
id: tonesPopupComponent
EmojiTonesPicker {
onChosen: emojiGrid.chosen(emoji)
onChosen: root.chosen(emoji)
}
}
}

View File

@@ -8,7 +8,7 @@ import org.kde.kirigami 2.20 as Kirigami
import org.kde.neochat 1.0
QQC2.Popup {
id: tones
id: root
signal chosen(string emoji)
@@ -20,14 +20,14 @@ QQC2.Popup {
required property string shortName
required property string unicode
required property int categoryIconSize
width: tones.categoryIconSize * tonesList.count + 2 * padding
height: tones.categoryIconSize + 2 * padding
width: root.categoryIconSize * tonesList.count + 2 * padding
height: root.categoryIconSize + 2 * padding
y: -height
padding: 2
modal: true
dim: true
clip: false
onOpened: x = Math.min(parent.mapFromGlobal(QQC2.Overlay.overlay.width - tones.width, 0).x, -(width - parent.width) / 2)
onOpened: x = Math.min(parent.mapFromGlobal(QQC2.Overlay.overlay.width - root.width, 0).x, -(width - parent.width) / 2)
background: Kirigami.ShadowedRectangle {
color: Kirigami.Theme.backgroundColor
radius: Kirigami.Units.mediumSpacing
@@ -47,7 +47,7 @@ QQC2.Popup {
width: parent.width
height: parent.height
orientation: Qt.Horizontal
model: EmojiModel.tones(tones.shortName)
model: EmojiModel.tones(root.shortName)
keyNavigationEnabled: true
keyNavigationWraps: true
@@ -57,15 +57,15 @@ QQC2.Popup {
emoji: modelData.unicode
name: modelData.shortName
width: tones.categoryIconSize
width: root.categoryIconSize
height: width
Keys.onEnterPressed: clicked()
Keys.onReturnPressed: clicked()
onClicked: {
tones.chosen(modelData.unicode)
root.chosen(modelData.unicode)
EmojiModel.emojiUsed(modelData)
tones.close()
root.close()
}
}
}

View File

@@ -8,7 +8,7 @@ import QtQuick.Particles 2.15
import org.kde.kirigami 2.15 as Kirigami
Item {
id: item
id: root
property bool enabled: false
property int effectInterval: Kirigami.Units.veryLongDuration*10;
property color darkSnowColor: "grey"
@@ -30,12 +30,12 @@ Item {
Timer {
id: confettiTimer
interval: item.effectInterval;
interval: root.effectInterval;
running: false;
repeat: false;
triggeredOnStart: true;
onTriggered: {
if (item.enabled) {
if (root.enabled) {
confettiSystem.running = !confettiSystem.running
}
}
@@ -92,12 +92,12 @@ Item {
Timer {
id: snowTimer
interval: item.effectInterval;
interval: root.effectInterval;
running: false;
repeat: false;
triggeredOnStart: true;
onTriggered: {
if (item.enabled) {
if (root.enabled) {
snowSystem.running = !snowSystem.running
}
}
@@ -127,7 +127,7 @@ Item {
width: 10
height: width
radius: width
color: item.isThemeDark ? "white" : darkSnowColor
color: root.isThemeDark ? "white" : darkSnowColor
scale: Math.random()
opacity: Math.random()
}
@@ -157,12 +157,12 @@ Item {
Timer {
id: fireworksTimer
interval: item.effectInterval;
interval: root.effectInterval;
running: false;
repeat: false;
triggeredOnStart: true;
onTriggered: {
if (item.enabled) {
if (root.enabled) {
fireworksInternalTimer.running = !fireworksInternalTimer.running
}
}
@@ -206,8 +206,8 @@ Item {
id: fireworksParticleA
system: fireworksSystem
source: "qrc:/glowdot.png"
alphaVariation: item.isThemeDark ? 0.1 : 0.1
alpha: item.isThemeDark ? 0.5 : 1
alphaVariation: root.isThemeDark ? 0.1 : 0.1
alpha: root.isThemeDark ? 0.5 : 1
groups: ["a"]
opacity: fireworksSystem.opacity
entryEffect: ImageParticle.Scale
@@ -217,9 +217,9 @@ Item {
ImageParticle {
system: fireworksSystem
source: "qrc:/glowdot.png"
color: item.isThemeDark ? "white" : "gold"
alphaVariation: item.isThemeDark ? 0.1 : 0.1
alpha: item.isThemeDark ? 0.5 : 1
color: root.isThemeDark ? "white" : "gold"
alphaVariation: root.isThemeDark ? 0.1 : 0.1
alpha: root.isThemeDark ? 0.5 : 1
groups: ["light"]
opacity: fireworksSystem.opacity
entryEffect: ImageParticle.Scale
@@ -230,8 +230,8 @@ Item {
id: fireworksParticleB
system: fireworksSystem
source: "qrc:/glowdot.png"
alphaVariation: item.isThemeDark ? 0.1 : 0.1
alpha: item.isThemeDark ? 0.5 : 1
alphaVariation: root.isThemeDark ? 0.1 : 0.1
alpha: root.isThemeDark ? 0.5 : 1
groups: ["b"]
opacity: fireworksSystem.opacity
entryEffect: ImageParticle.Scale
@@ -257,7 +257,7 @@ Item {
onTriggered: {
container.destroy();
var randomHue = Math.random()
var lightness = item.isThemeDark ? 0.8 : 0.7
var lightness = root.isThemeDark ? 0.8 : 0.7
fireworksParticleA.color = Qt.hsla(randomHue, 0.8, lightness, 1)
fireworksParticleB.color = Qt.hsla(1-randomHue, 0.8, lightness, 1)
}

View File

@@ -9,7 +9,7 @@ import org.kde.kirigami 2.20 as Kirigami
import org.kde.neochat 1.0
Kirigami.Page {
id: locationsPage
id: root
required property var room
@@ -31,7 +31,7 @@ Kirigami.Page {
MapItemView {
model: LocationsModel {
id: locationsModel
room: locationsPage.room
room: root.room
}
delegate: LocationMapItem {
isLive: true
@@ -42,7 +42,7 @@ Kirigami.Page {
MapItemView {
model: LiveLocationsModel {
id: liveLocationsModel
room: locationsPage.room
room: root.room
}
delegate: LocationMapItem {}
}

View File

@@ -8,7 +8,7 @@ import QtQuick 2.15
import org.kde.kirigami 2.15 as Kirigami
Gradient {
id: gradient
id: root
orientation: Gradient.Horizontal
@@ -25,7 +25,7 @@ Gradient {
from: -2.0
to: 2.0
duration: 700
target: gradient
target: root
properties: "pos"
}
PauseAnimation {
@@ -33,7 +33,7 @@ Gradient {
}
}
GradientStop { position: gradient.pos-gradient.offset; color: gradient.translucent }
GradientStop { position: gradient.pos; color: gradient.bright }
GradientStop { position: gradient.pos+gradient.offset; color: gradient.translucent }
}
GradientStop { position: root.pos-root.offset; color: root.translucent }
GradientStop { position: root.pos; color: root.bright }
GradientStop { position: root.pos+root.offset; color: root.translucent }
}

View File

@@ -4,7 +4,7 @@
import QtQuick 2.15
import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import QtMultimedia @QTMULTIMEDIA_MODULE_QML_VERSION@
import QtMultimedia
import org.kde.kirigami 2.15 as Kirigami
@@ -42,10 +42,9 @@ TimelineContainer {
Layout.fillWidth: true
Layout.maximumWidth: root.contentMaxWidth
@QTMULTIMEDIA_AUDIO@ {
MediaPlayer {
id: audio
source: root.progressInfo.localPath
@QTMULTIMEDIA_AUDIO_AUTOLOAD@
}
states: [

View File

@@ -23,7 +23,7 @@ Loader {
* - description - the description of the URL preview.
* - imageSource - a source URL for the preview image.
*/
property var linkPreviewer
required property var linkPreviewer
/**
* @brief Standard height for the link preview.
@@ -39,7 +39,7 @@ Loader {
property bool indicatorEnabled: false
visible: active
sourceComponent: linkPreviewer.loaded ? linkPreviewComponent : loadingComponent
sourceComponent: linkPreviewer && linkPreviewer.loaded ? linkPreviewComponent : loadingComponent
Component {
id: linkPreviewComponent
@@ -61,10 +61,10 @@ Loader {
color: Kirigami.Theme.highlightColor
}
Image {
visible: linkPreviewer.imageSource
visible: root.linkPreviewer.imageSource
Layout.maximumHeight: root.defaultHeight
Layout.maximumWidth: root.defaultHeight
source: linkPreviewer.imageSource
source: root.linkPreviewer.imageSource
fillMode: Image.PreserveAspectFit
}
ColumnLayout {

View File

@@ -68,7 +68,7 @@ TimelineContainer {
}
LinkPreviewDelegate {
Layout.fillWidth: true
active: !currentRoom.usesEncryption && currentRoom.urlPreviewEnabled && Config.showLinkPreview && root.showLinkPreview
active: !currentRoom.usesEncryption && currentRoom.urlPreviewEnabled && Config.showLinkPreview && root.showLinkPreview && !root.linkPreview.empty
linkPreviewer: root.linkPreview
indicatorEnabled: root.isVisibleInTimeline()
}

View File

@@ -3,8 +3,8 @@
pragma Singleton
import QtQuick @QTQUICK_MODULE_QML_VERSION@
import QtLocation @QTLOCATION_MODULE_QML_VERSION@
import QtQuick
import QtLocation
QtObject {
property var plugin: Plugin {

View File

@@ -11,7 +11,8 @@ import org.kde.kirigami 2.15 as Kirigami
import org.kde.neochat 1.0
QQC2.ItemDelegate {
id: readMarkerDelegate
id: root
padding: Kirigami.Units.largeSpacing
topInset: Kirigami.Units.largeSpacing
topPadding: Kirigami.Units.largeSpacing * 2
@@ -41,7 +42,7 @@ QQC2.ItemDelegate {
State {
name: "alignLeft"
AnchorChanges {
target: readMarkerDelegate
target: root
anchors.horizontalCenter: undefined
anchors.left: parent ? parent.left : undefined
}
@@ -49,7 +50,7 @@ QQC2.ItemDelegate {
State {
name: "alignCenter"
AnchorChanges {
target: readMarkerDelegate
target: root
anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined
anchors.left: undefined
}
@@ -72,7 +73,7 @@ QQC2.ItemDelegate {
background: Kirigami.ShadowedRectangle {
id: readMarkerBackground
color: {
if (readMarkerDelegate.isTemporaryHighlighted) {
if (root.isTemporaryHighlighted) {
return Kirigami.Theme.positiveBackgroundColor
} else {
return Kirigami.Theme.backgroundColor
@@ -80,7 +81,7 @@ QQC2.ItemDelegate {
}
Kirigami.Theme.inherit: false
Kirigami.Theme.colorSet: Kirigami.Theme.View
opacity: readMarkerDelegate.isTemporaryHighlighted ? 1 : 0.6
opacity: root.isTemporaryHighlighted ? 1 : 0.6
radius: Kirigami.Units.smallSpacing
shadow.size: Kirigami.Units.smallSpacing
shadow.color: Qt.rgba(0.0, 0.0, 0.0, 0.10)

View File

@@ -11,7 +11,7 @@ import org.kde.kirigami 2.15 as Kirigami
import org.kde.neochat 1.0
QQC2.ItemDelegate {
id: sectionDelegate
id: root
property alias labelText: sectionLabel.text
property var maxWidth: Number.POSITIVE_INFINITY
@@ -44,6 +44,6 @@ QQC2.ItemDelegate {
background: Rectangle {
color: Config.blur ? "transparent" : Kirigami.Theme.backgroundColor
Kirigami.Theme.inherit: false
Kirigami.Theme.colorSet: sectionDelegate.colorSet
Kirigami.Theme.colorSet: root.colorSet
}
}

View File

@@ -11,7 +11,7 @@ import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.neochat 1.0
QQC2.Control {
id: stateDelegate
id: root
readonly property bool sectionVisible: model.showSection
@@ -23,7 +23,7 @@ QQC2.Control {
State {
name: "alignLeft"
AnchorChanges {
target: stateDelegate
target: root
anchors.horizontalCenter: undefined
anchors.left: parent ? parent.left : undefined
}
@@ -31,7 +31,7 @@ QQC2.Control {
State {
name: "alignCenter"
AnchorChanges {
target: stateDelegate
target: root
anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined
anchors.left: undefined
}
@@ -62,6 +62,7 @@ QQC2.Control {
Layout.fillWidth: true
visible: sectionVisible
labelText: sectionVisible ? section : ""
colorSet: Config.compactLayout ? Kirigami.Theme.View : Kirigami.Theme.Window
}
RowLayout {
Layout.fillWidth: true
@@ -203,6 +204,6 @@ QQC2.Control {
endPercentWidth: Config.compactLayout ? 100 : 85
maxWidth: Config.compactLayout ? -1 : Kirigami.Units.gridUnit * 60
parentWidth: stateDelegate.parent ? stateDelegate.parent.width : 0
parentWidth: root.parent ? root.parent.width : 0
}
}

View File

@@ -622,7 +622,7 @@ ColumnLayout {
selectedText: selectedText,
author: root.author,
eventId: root.eventId,
source: root.jsonSource,
eventSource: root.jsonSource,
eventType: root.delegateType,
plainText: root.plainText,
htmlText: root.display,

View File

@@ -4,7 +4,7 @@
import QtQuick 2.15
import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import QtMultimedia @QTMULTIMEDIA_MODULE_QML_VERSION@
import QtMultimedia
import Qt.labs.platform 1.1 as Platform
import org.kde.kirigami 2.13 as Kirigami
@@ -73,7 +73,6 @@ TimelineContainer {
Layout.preferredHeight: mediaSizeHelper.currentSize.height
fillMode: VideoOutput.PreserveAspectFit
@QTMULTIMEDIA_VIDEO_FLUSHMODE@
states: [
State {

View File

@@ -116,6 +116,7 @@ QQC2.ScrollView {
z: 3
visible: !!messageListView.sectionBannerItem && messageListView.sectionBannerItem.ListView.section !== "" && !Config.blur
labelText: messageListView.sectionBannerItem ? messageListView.sectionBannerItem.ListView.section : ""
colorSet: Config.compactLayout ? Kirigami.Theme.View : Kirigami.Theme.Window
}
footerPositioning: ListView.OverlayHeader

View File

@@ -10,7 +10,7 @@ import org.kde.kirigami 2.15 as Kirigami
import org.kde.neochat 1.0
QQC2.Dialog {
id: confirmEncryptionDialog
id: root
property NeoChatRoom room
@@ -31,15 +31,15 @@ QQC2.Dialog {
QQC2.Button {
text: i18n("Cancel")
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.RejectRole
onClicked: confirmEncryptionDialog.close()
onClicked: root.close()
}
QQC2.Button {
text: i18n("Activate Encryption")
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.AcceptRole
onClicked: {
confirmEncryptionDialog.room.activateEncryption()
confirmEncryptionDialog.close();
root.room.activateEncryption()
root.close();
}
}
}

View File

@@ -12,6 +12,8 @@ FormCard.FormCardPage {
title: i18nc("@title", "Create a Room")
required property NeoChatConnection connection
Component.onCompleted: roomNameField.forceActiveFocus()
FormCard.FormHeader {
@@ -35,7 +37,7 @@ FormCard.FormCardPage {
text: i18nc("@action:button", "Ok")
enabled: roomNameField.text.length > 0
onClicked: {
Controller.createRoom(roomNameField.text, roomTopicField.text);
root.connection.createRoom(roomNameField.text, roomTopicField.text);
root.closeDialog()
}
}

View File

@@ -11,6 +11,8 @@ import org.kde.kirigamiaddons.formcard 1.0 as FormCard
FormCard.FormCardPage {
id: root
required property NeoChatConnection connection
title: i18n("Create a Space")
Kirigami.Theme.colorSet: Kirigami.Theme.Window
@@ -30,7 +32,7 @@ FormCard.FormCardPage {
FormCard.FormButtonDelegate {
text: i18n("Create space")
onClicked: {
Controller.createSpace(nameDelegate.text, topicDelegate.text)
root.connection.createSpace(nameDelegate.text, topicDelegate.text)
root.close()
root.destroy()
}

View File

@@ -9,7 +9,7 @@ import org.kde.kirigami 2.15 as Kirigami
import org.kde.neochat 1.0
QQC2.Popup {
id: emojiPopup
id: root
/**
* @brief The current room that user is viewing.
@@ -25,7 +25,7 @@ QQC2.Popup {
Connections {
target: RoomManager
function onCurrentRoomChanged() {
emojiPopup.close()
root.close()
}
}
@@ -64,11 +64,11 @@ QQC2.Popup {
id: emojiPicker
height: 400
currentRoom: root.currentRoom
includeCustom: emojiPopup.includeCustom
showQuickReaction: emojiPopup.showQuickReaction
includeCustom: root.includeCustom
showQuickReaction: root.showQuickReaction
onChosen: emoji => {
emojiPopup.chosen(emoji)
if (emojiPopup.closeOnChosen) emojiPopup.close()
root.chosen(emoji)
if (root.closeOnChosen) root.close()
}
}
}

View File

@@ -9,7 +9,7 @@ import org.kde.kirigami 2.19 as Kirigami
import org.kde.neochat 1.0
Column {
id: emojiItem
id: root
property string emoji
property string description
@@ -23,7 +23,7 @@ Column {
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: emojiItem.emoji
text: root.emoji
font.family: "emoji"
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 4
}
@@ -32,7 +32,7 @@ Column {
y: parent.height * 0.75
width: parent.width
height: parent.height * 0.25
text: emojiItem.description
text: root.description
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}

View File

@@ -7,7 +7,7 @@ import QtQml 2.15
import org.kde.neochat 1.0
Row {
id: emojiRow
id: root
property alias model: repeater.model
anchors.horizontalCenter: parent.horizontalCenter
@@ -16,7 +16,7 @@ Row {
delegate: EmojiItem {
emoji: modelData.emoji
description: modelData.description
width: emojiRow.height
width: root.height
height: width
}
}

View File

@@ -9,7 +9,7 @@ import org.kde.kirigami 2.19 as Kirigami
import org.kde.neochat 1.0
Column {
id: emojiSas
id: root
required property var model
@@ -25,12 +25,12 @@ Column {
EmojiRow {
anchors.horizontalCenter: parent.horizontalCenter
height: Kirigami.Units.gridUnit * 4
model: emojiSas.model.slice(0, 4)
model: root.model.slice(0, 4)
}
EmojiRow {
anchors.horizontalCenter: parent.horizontalCenter
height: Kirigami.Units.gridUnit * 4
model: emojiSas.model.slice(4, 7)
model: root.model.slice(4, 7)
}
Row {
anchors.horizontalCenter: parent.horizontalCenter
@@ -38,13 +38,13 @@ Column {
anchors.bottom: parent.bottom
text: i18n("They match")
icon.name: "dialog-ok"
onClicked: emojiSas.accept()
onClicked: root.accept()
}
QQC2.Button {
anchors.bottom: parent.bottom
text: i18n("They don't match")
icon.name: "dialog-cancel"
onClicked: emojiSas.reject()
onClicked: root.reject()
}
}
}

View File

@@ -10,7 +10,8 @@ import org.kde.kirigami 2.19 as Kirigami
import org.kde.neochat 1.0
Kirigami.Page {
id: dialog
id: root
title: i18n("Session Verification")
required property var session
@@ -18,31 +19,31 @@ Kirigami.Page {
Item {
anchors.fill: parent
VerificationCanceled {
visible: dialog.session.state === KeyVerificationSession.CANCELED
visible: root.session.state === KeyVerificationSession.CANCELED
anchors.centerIn: parent
reason: dialog.session.error
reason: root.session.error
}
EmojiSas {
anchors.centerIn: parent
visible: dialog.session.state === KeyVerificationSession.WAITINGFORVERIFICATION
model: dialog.session.sasEmojis
onReject: dialog.session.cancelVerification(KeyVerificationSession.MISMATCHED_SAS)
onAccept: dialog.session.sendMac()
visible: root.session.state === KeyVerificationSession.WAITINGFORVERIFICATION
model: root.session.sasEmojis
onReject: root.session.cancelVerification(KeyVerificationSession.MISMATCHED_SAS)
onAccept: root.session.sendMac()
}
Message {
visible: dialog.session.state === KeyVerificationSession.WAITINGFORREADY
visible: root.session.state === KeyVerificationSession.WAITINGFORREADY
anchors.centerIn: parent
icon: "security-medium-symbolic"
text: i18n("Waiting for device to accept verification.")
}
Message {
visible: dialog.session.state === KeyVerificationSession.INCOMING
visible: root.session.state === KeyVerificationSession.INCOMING
anchors.centerIn: parent
icon: "security-medium-symbolic"
text: i18n("Incoming key verification request from device **%1**", dialog.session.remoteDeviceId)
text: i18n("Incoming key verification request from device **%1**", root.session.remoteDeviceId)
}
Message {
visible: dialog.session.state === KeyVerificationSession.WAITINGFORMAC
visible: root.session.state === KeyVerificationSession.WAITINGFORMAC
anchors.centerIn: parent
icon: "security-medium-symbolic"
text: i18n("Waiting for other party to verify.")
@@ -50,35 +51,35 @@ Kirigami.Page {
Kirigami.BasicListItem {
id: emojiVerification
text: "Emoji Verification"
visible: dialog.session.state === KeyVerificationSession.READY
visible: root.session.state === KeyVerificationSession.READY
subtitle: i18n("Compare a set of emoji on both devices")
onClicked: {
dialog.session.sendStartSas()
root.session.sendStartSas()
}
}
Message {
visible: dialog.session.state === KeyVerificationSession.DONE
visible: root.session.state === KeyVerificationSession.DONE
anchors.centerIn: parent
text: i18n("Successfully verified device **%1**", dialog.session.remoteDeviceId)
text: i18n("Successfully verified device **%1**", root.session.remoteDeviceId)
icon: "security-high"
}
}
footer: QQC2.ToolBar {
visible: dialog.session.state === KeyVerificationSession.INCOMING
visible: root.session.state === KeyVerificationSession.INCOMING
QQC2.DialogButtonBox {
anchors.fill: parent
Item { Layout.fillWidth: true }
QQC2.Button {
text: i18n("Accept")
icon.name: "dialog-ok"
onClicked: dialog.session.sendReady()
onClicked: root.session.sendReady()
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.AcceptRole
}
QQC2.Button {
text: i18n("Decline")
icon.name: "dialog-cancel"
onClicked: dialog.session.cancelVerification("m.user", "Declined")
onClicked: root.session.cancelVerification("m.user", "Declined")
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.RejectRole
}
}

View File

@@ -9,7 +9,8 @@ import org.kde.kirigami 2.19 as Kirigami
import org.kde.neochat 1.0
Column {
id: message
id: root
required property string icon
required property string text
@@ -18,10 +19,10 @@ Column {
width: Kirigami.Units.iconSizes.enormous
height: width
anchors.horizontalCenter: parent.horizontalCenter
source: message.icon
source: root.icon
}
QQC2.Label {
text: message.text
text: root.text
textFormat: Text.MarkdownText
}
}

View File

@@ -7,14 +7,14 @@ import QtQml 2.15
import org.kde.neochat 1.0
Message {
id: verificationCanceled
id: root
required property int reason
anchors.centerIn: parent
icon: "security-low"
text: {
switch(verificationCanceled.reason) {
switch(root.reason) {
case KeyVerificationSession.NONE:
return i18n("The session verification was canceled for unknown reason.");
case KeyVerificationSession.TIMEOUT:

View File

@@ -17,7 +17,7 @@ Kirigami.OverlaySheet {
property var userId
property int powerLevel
@OVERLAYSHEET_OPEN@: {
onOpened: {
if (sheetOpen) {
powerLevelComboBox.currentIndex = powerLevelComboBox.indexOfValue(root.powerLevel)
}

View File

@@ -6,27 +6,27 @@ import QtQuick 2.15
import QtQuick.Layouts 1.10
Labs.Menu {
id: editMenu
id: root
required property Item field
Labs.MenuItem {
enabled: editMenu.field !== null && editMenu.field.canUndo
enabled: root.field !== null && root.field.canUndo
text: i18nc("text editing menu action", "Undo")
shortcut: StandardKey.Undo
onTriggered: {
editMenu.field.undo()
editMenu.close()
root.field.undo()
root.close()
}
}
Labs.MenuItem {
enabled: editMenu.field !== null && editMenu.field.canRedo
enabled: root.field !== null && root.field.canRedo
text: i18nc("text editing menu action", "Redo")
shortcut: StandardKey.Redo
onTriggered: {
editMenu.field.undo()
editMenu.close()
root.field.undo()
root.close()
}
}
@@ -34,42 +34,42 @@ Labs.Menu {
}
Labs.MenuItem {
enabled: editMenu.field !== null && editMenu.field.selectedText
enabled: root.field !== null && root.field.selectedText
text: i18nc("text editing menu action", "Cut")
shortcut: StandardKey.Cut
onTriggered: {
editMenu.field.cut()
editMenu.close()
root.field.cut()
root.close()
}
}
Labs.MenuItem {
enabled: editMenu.field !== null && editMenu.field.selectedText
enabled: root.field !== null && root.field.selectedText
text: i18nc("text editing menu action", "Copy")
shortcut: StandardKey.Copy
onTriggered: {
editMenu.field.copy()
editMenu.close()
root.field.copy()
root.close()
}
}
Labs.MenuItem {
enabled: editMenu.field !== null && editMenu.field.canPaste
enabled: root.field !== null && root.field.canPaste
text: i18nc("text editing menu action", "Paste")
shortcut: StandardKey.Paste
onTriggered: {
editMenu.field.paste()
editMenu.close()
root.field.paste()
root.close()
}
}
Labs.MenuItem {
enabled: editMenu.field !== null && editMenu.field.selectedText !== ""
enabled: root.field !== null && root.field.selectedText !== ""
text: i18nc("text editing menu action", "Delete")
shortcut: ""
onTriggered: {
editMenu.field.remove(editMenu.field.selectionStart, editMenu.field.selectionEnd)
editMenu.close()
root.field.remove(root.field.selectionStart, root.field.selectionEnd)
root.close()
}
}
@@ -77,12 +77,12 @@ Labs.Menu {
}
Labs.MenuItem {
enabled: editMenu.field !== null
enabled: root.field !== null
text: i18nc("text editing menu action", "Select All")
shortcut: StandardKey.SelectAll
onTriggered: {
editMenu.field.selectAll()
editMenu.close()
root.field.selectAll()
root.close()
}
}
}

View File

@@ -54,7 +54,16 @@ Labs.MenuBar {
}
Labs.MenuItem {
text: i18nc("menu", "Browse Chats…")
onTriggered: pushReplaceLayer("qrc:/JoinRoomPage.qml", {connection: Controller.activeConnection})
onTriggered: {
let dialog = pageStack.pushDialogLayer("qrc:/JoinRoomPage.qml", {connection: Controller.activeConnection}, {title: i18nc("@title", "Explore Rooms")})
dialog.roomSelected.connect((roomId, displayName, avatarUrl, alias, topic, memberCount, isJoined) => {
if (isJoined) {
RoomManager.enterRoom(Controller.activeConnection.room(roomId))
} else {
Controller.joinRoom(roomId)
}
})
}
}
}
EditMenu {

View File

@@ -13,7 +13,8 @@ import org.kde.kirigami 2.14 as Kirigami
* TODO add Android support
*/
Kirigami.Action {
id: shareAction
id: root
icon.name: "emblem-shared-symbolic"
text: i18n("Share")
tooltip: i18n("Share the selected media")
@@ -40,12 +41,12 @@ Kirigami.Action {
const purposeModel = Qt.createQmlObject('import org.kde.purpose 1.0 as Purpose;
Purpose.PurposeAlternativesModel {
pluginType: "Export"
}', shareAction._instantiator);
}', root._instantiator);
purposeModel.inputData = Qt.binding(function() {
return shareAction.inputData;
return root.inputData;
});
_instantiator.model = purposeModel;
shareAction.visible = true;
root.visible = true;
}
delegate: Kirigami.Action {
@@ -55,16 +56,16 @@ Purpose.PurposeAlternativesModel {
onTriggered: {
doBeforeSharing();
applicationWindow().pageStack.pushDialogLayer('qrc:/ShareDialog.qml', {
title: shareAction.tooltip,
title: root.tooltip,
index: index,
model: shareAction._instantiator.model
model: root._instantiator.model
})
}
}
onObjectAdded: (index, object) => {
object.index = index;
shareAction.children.push(object)
root.children.push(object)
}
onObjectRemoved: (index, object) => shareAction.children = Array.from(shareAction.children).filter(obj => obj.pluginId !== object.pluginId)
onObjectRemoved: (index, object) => root.children = Array.from(root.children).filter(obj => obj.pluginId !== object.pluginId)
}
}

View File

@@ -13,7 +13,7 @@ import org.kde.notification 1.0
import org.kde.kirigami 2.14 as Kirigami
Kirigami.Page {
id: window
id: root
leftPadding: 0
rightPadding: 0
@@ -25,7 +25,7 @@ Kirigami.Page {
QQC2.Action {
shortcut: 'Escape'
onTriggered: window.closeDialog()
onTriggered: root.closeDialog()
}
Notification {
@@ -54,15 +54,15 @@ Kirigami.Page {
sharingSuccess.sendEvent();
Clipboard.saveText(jobView.output.url);
}
window.closeDialog()
root.closeDialog()
} else if (state === Purpose.PurposeJobController.Error) {
// Show failure notification
sharingFailed.sendEvent();
window.closeDialog()
root.closeDialog()
} else if (state === Purpose.PurposeJobController.Cancelled) {
// Do nothing
window.closeDialog()
root.closeDialog()
}
}
}

View File

@@ -10,7 +10,7 @@ import org.kde.kirigami 2.20 as Kirigami
import org.kde.neochat 1.0
Kirigami.Page {
id: banSheet
id: root
property NeoChatRoom room
property string userId
@@ -35,14 +35,14 @@ Kirigami.Page {
icon.name: "im-ban-user"
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.AcceptRole
onClicked: {
banSheet.room.ban(banSheet.userId, reason.text)
banSheet.closeDialog()
root.room.ban(root.userId, reason.text)
root.closeDialog()
}
}
QQC2.Button {
text: i18nc("@action", "Cancel")
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.RejectRole
onClicked: banSheet.closeDialog()
onClicked: root.closeDialog()
}
}
}

View File

@@ -92,7 +92,7 @@ MessageDelegateContextMenu {
icon.name: "code-context"
onTriggered: {
applicationWindow().pageStack.pushDialogLayer('qrc:/MessageSourceSheet.qml', {
sourceText: root.source
sourceText: root.eventSource
}, {
title: i18n("Message Source"),
width: Kirigami.Units.gridUnit * 25

View File

@@ -11,12 +11,12 @@ import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.neochat 1.0
Loader {
id: loadRoot
id: root
required property var author
required property string eventId
property var eventType
required property string source
required property string eventSource
property string selectedText: ""
required property string plainText
property string htmlText: undefined
@@ -31,7 +31,7 @@ Loader {
currentRoom.chatBoxEditId = eventId;
currentRoom.chatBoxReplyId = "";
}
visible: author.id === Controller.activeConnection.localUserId && (loadRoot.eventType === DelegateType.Emote || loadRoot.eventType === DelegateType.Message)
visible: author.id === Controller.activeConnection.localUserId && (root.eventType === DelegateType.Emote || root.eventType === DelegateType.Message)
},
Kirigami.Action {
text: i18n("Reply")
@@ -50,7 +50,7 @@ Loader {
width: Kirigami.Units.gridUnit * 25
})
page.chosen.connect(function(targetRoomId) {
Controller.activeConnection.room(targetRoomId).postHtmlMessage(loadRoot.plainText, loadRoot.htmlText ? loadRoot.htmlText : loadRoot.plainText)
Controller.activeConnection.room(targetRoomId).postHtmlMessage(root.plainText, root.htmlText ? root.htmlText : root.plainText)
page.closeDialog()
})
}
@@ -68,7 +68,7 @@ Loader {
Kirigami.Action {
text: i18n("Copy")
icon.name: "edit-copy"
onTriggered: Clipboard.saveText(loadRoot.selectedText === "" ? loadRoot.plainText : loadRoot.selectedText)
onTriggered: Clipboard.saveText(root.selectedText === "" ? root.plainText : root.selectedText)
},
Kirigami.Action {
text: i18nc("@action:button 'Report' as in 'Report this event to the administrators'", "Report")
@@ -80,11 +80,12 @@ Loader {
})
},
Kirigami.Action {
visible: Config.developerTools
text: i18n("View Source")
icon.name: "code-context"
onTriggered: {
applicationWindow().pageStack.pushDialogLayer('qrc:/MessageSourceSheet.qml', {
sourceText: loadRoot.source
sourceText: root.eventSource
}, {
title: i18n("Message Source"),
width: Kirigami.Units.gridUnit * 25
@@ -95,7 +96,7 @@ Loader {
text: i18n("Copy Link")
icon.name: "edit-copy"
onTriggered: {
Clipboard.saveText("https://matrix.to/#/" + currentRoom.id + "/" + loadRoot.eventId)
Clipboard.saveText("https://matrix.to/#/" + currentRoom.id + "/" + root.eventId)
}
}
]
@@ -106,7 +107,7 @@ Loader {
QQC2.Menu {
id: menu
Instantiator {
model: loadRoot.nestedActions
model: root.nestedActions
delegate: QQC2.Menu {
id: menuItem
visible: modelData.visible
@@ -131,12 +132,12 @@ Loader {
}
Repeater {
model: loadRoot.actions
model: root.actions
QQC2.MenuItem {
id: menuItem
visible: modelData.visible
action: modelData
onClicked: loadRoot.item.close();
onClicked: root.item.close();
}
}
QQC2.Menu {
@@ -150,7 +151,7 @@ Loader {
Instantiator {
model: WebShortcutModel {
id: webshortcutmodel
selectedText: loadRoot.selectedText ? loadRoot.selectedText : loadRoot.plainText
selectedText: root.selectedText ? root.selectedText : root.plainText
onOpenUrl: RoomManager.visitNonMatrix(url)
}
delegate: QQC2.MenuItem {
@@ -222,7 +223,7 @@ Loader {
text: modelData.text
onClicked: {
modelData.triggered()
loadRoot.item.close();
root.item.close();
}
implicitHeight: visible ? Kirigami.Units.gridUnit * 3 : 0
}
@@ -285,7 +286,7 @@ Loader {
onClicked: {
currentRoom.toggleReaction(eventId, modelData);
loadRoot.item.close();
root.item.close();
}
}
}
@@ -295,7 +296,7 @@ Loader {
}
Repeater {
id: listViewAction
model: loadRoot.actions
model: root.actions
Kirigami.BasicListItem {
icon: modelData.icon.name
@@ -305,14 +306,14 @@ Loader {
text: modelData.text
onClicked: {
modelData.triggered()
loadRoot.item.close();
root.item.close();
}
implicitHeight: visible ? Kirigami.Units.gridUnit * 3 : 0
}
}
Repeater {
model: loadRoot.nestedActions
model: root.nestedActions
Kirigami.BasicListItem {
action: modelData

View File

@@ -10,7 +10,7 @@ import org.kde.kirigami 2.20 as Kirigami
import org.kde.neochat 1.0
Kirigami.Page {
id: deleteSheet
id: root
property NeoChatRoom room
property string eventId
@@ -37,18 +37,18 @@ Kirigami.Page {
icon.name: "delete"
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.AcceptRole
onClicked: {
if (deleteSheet.userId.length > 0) {
deleteSheet.room.deleteMessagesByUser(deleteSheet.userId, reason.text)
if (root.userId.length > 0) {
root.room.deleteMessagesByUser(root.userId, reason.text)
} else {
deleteSheet.room.redactEvent(deleteSheet.eventId, reason.text);
root.room.redactEvent(root.eventId, reason.text);
}
deleteSheet.closeDialog()
root.closeDialog()
}
}
QQC2.Button {
text: i18nc("@action", "Cancel")
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.RejectRole
onClicked: deleteSheet.closeDialog()
onClicked: root.closeDialog()
}
}
}

View File

@@ -10,7 +10,7 @@ import org.kde.kirigami 2.20 as Kirigami
import org.kde.neochat 1.0
Kirigami.Page {
id: reportSheet
id: root
property NeoChatRoom room
property string eventId
@@ -35,14 +35,14 @@ Kirigami.Page {
icon.name: "dialog-warning-symbolic"
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.AcceptRole
onClicked: {
reportSheet.room.reportEvent(eventId, reason.text)
reportSheet.closeDialog()
root.room.reportEvent(eventId, reason.text)
root.closeDialog()
}
}
QQC2.Button {
text: i18nc("@action", "Cancel")
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.RejectRole
onClicked: reportSheet.closeDialog()
onClicked: root.closeDialog()
}
}
}

View File

@@ -14,7 +14,6 @@ import org.kde.neochat 1.0
Delegates.RoundedItemDelegate {
id: root
required property NeoChatConnection connection
required property string roomId
required property string displayName
required property url avatarUrl
@@ -24,16 +23,32 @@ Delegates.RoundedItemDelegate {
required property bool isJoined
property bool justJoined: false
signal roomSelected()
/**
* @brief Signal emitted when a room delegate is selected.
*
* The signal contains all the delegate's model info so that it can be acted
* upon as required, e.g. joining or entering the room or adding the room as
* the child of a space.
*/
signal roomSelected(string roomId,
string displayName,
url avatarUrl,
string alias,
string topic,
int memberCount,
bool isJoined)
onClicked: {
if (!isJoined) {
Controller.joinRoom(root.roomId)
justJoined = true;
} else {
RoomManager.enterRoom(root.connection.room(root.roomId))
}
root.roomSelected()
root.roomSelected(root.roomId,
root.displayName,
root.avatarUrl,
root.alias,
root.topic,
root.memberCount,
root.isJoined)
}
contentItem: RowLayout {

View File

@@ -31,15 +31,15 @@ Kirigami.Page {
imageDoc.crop(selectionTool.selectionX / ratioX, selectionTool.selectionY / ratioY, selectionTool.selectionWidth / ratioX, selectionTool.selectionHeight / ratioY);
}
actions {
left: Kirigami.Action {
actions: [
Kirigami.Action {
id: undoAction
text: i18nc("@action:button Undo modification", "Undo")
icon.name: "edit-undo"
onTriggered: imageDoc.undo();
visible: imageDoc.edited
}
main: Kirigami.Action {
},
Kirigami.Action {
id: okAction
text: i18nc("@action:button Accept image modification", "Accept")
icon.name: "dialog-ok"
@@ -54,7 +54,7 @@ Kirigami.Page {
}
}
}
}
]

View File

@@ -20,6 +20,21 @@ Kirigami.ScrollablePage {
property alias keyword: identifierField.text
property string server
/**
* @brief Signal emitted when a room is selected.
*
* The signal contains all the room's info so that it can be acted
* upon as required, e.g. joinng or entering the room or adding the room as
* the child of a space.
*/
signal roomSelected(string roomId,
string displayName,
url avatarUrl,
string alias,
string topic,
int memberCount,
bool isJoined)
title: i18n("Explore Rooms")
Component.onCompleted: identifierField.forceActiveFocus()
@@ -123,10 +138,10 @@ Kirigami.ScrollablePage {
title: i18nc("@title:window", "Add server")
onSheetOpenChanged: if (!serverUrlField.isValidServer && !sheetOpen) {
onOpened: if (!serverUrlField.isValidServer && !opened) {
serverField.currentIndex = 0
server = serverField.currentValue
} else if (sheetOpen) {
} else if (opened) {
serverUrlField.forceActiveFocus()
}
@@ -211,7 +226,10 @@ Kirigami.ScrollablePage {
}
delegate: ExplorerDelegate {
connection: root.connection
onRoomSelected: root.closeDialog()
onRoomSelected: (roomId, displayName, avatarUrl, alias, topic, memberCount, isJoined) => {
root.roomSelected(roomId, displayName, avatarUrl, alias, topic, memberCount, isJoined);
root.closeDialog();
}
}
footer: RowLayout {

View File

@@ -14,12 +14,20 @@ RowLayout {
property var desiredWidth
property bool collapsed: false
required property NeoChatConnection connection
property Kirigami.Action exploreAction: Kirigami.Action {
text: i18n("Explore rooms")
icon.name: "compass"
onTriggered: {
pageStack.pushDialogLayer("qrc:/JoinRoomPage.qml", {connection: Controller.activeConnection}, {title: i18nc("@title", "Explore Rooms")})
let dialog = pageStack.pushDialogLayer("qrc:/JoinRoomPage.qml", {connection: Controller.activeConnection}, {title: i18nc("@title", "Explore Rooms")})
dialog.roomSelected.connect((roomId, displayName, avatarUrl, alias, topic, memberCount, isJoined) => {
if (isJoined) {
RoomManager.enterRoom(Controller.activeConnection.room(roomId))
} else {
Controller.joinRoom(roomId)
}
})
}
}
property Kirigami.Action chatAction: Kirigami.Action {
@@ -31,7 +39,7 @@ RowLayout {
text: i18n("Create a Room")
icon.name: "system-users"
onTriggered: {
pageStack.pushDialogLayer("qrc:/CreateRoomDialog.qml", {}, {title: i18nc("@title", "Create a Room")})
pageStack.pushDialogLayer("qrc:/CreateRoomDialog.qml", {connection: root.connection}, {title: i18nc("@title", "Create a Room")})
}
shortcut: StandardKey.New
}
@@ -39,7 +47,7 @@ RowLayout {
text: i18n("Create a Space")
icon.name: "list-add"
onTriggered: {
pageStack.pushDialogLayer("qrc:/CreateSpaceDialog.qml", {}, {title: i18nc("@title", "Create a Space")})
pageStack.pushDialogLayer("qrc:/CreateSpaceDialog.qml", {connection: root.connection}, {title: i18nc("@title", "Create a Space")})
}
}

Some files were not shown because too many files have changed in this diff Show More