Compare commits
24 Commits
work/carlo
...
v25.12.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13042d9ba6 | ||
|
|
0e4b52ee62 | ||
|
|
4c32280343 | ||
|
|
a2e540d6ef | ||
|
|
573c8925d2 | ||
|
|
6c0bd850b0 | ||
|
|
1da9719314 | ||
|
|
3cd5f3a1c6 | ||
|
|
b4108f2eef | ||
|
|
bb7de18341 | ||
|
|
7b8328fce6 | ||
|
|
aeee6570c0 | ||
|
|
780b9a6f9b | ||
|
|
0ba06882d1 | ||
|
|
ce131a53e5 | ||
|
|
e9421e28dd | ||
|
|
1c64a6b5f0 | ||
|
|
9b5200c344 | ||
|
|
5baf4ab823 | ||
|
|
58a72a08f2 | ||
|
|
c9b97d4d0d | ||
|
|
2a7d61c73b | ||
|
|
f55bd28e10 | ||
|
|
2a67861099 |
@@ -2,7 +2,7 @@
|
||||
"id": "org.kde.neochat",
|
||||
"branch": "master",
|
||||
"runtime": "org.kde.Platform",
|
||||
"runtime-version": "6.10",
|
||||
"runtime-version": "6.9",
|
||||
"sdk": "org.kde.Sdk",
|
||||
"command": "neochat",
|
||||
"tags": [
|
||||
@@ -31,6 +31,19 @@
|
||||
"/share/ndk-modules"
|
||||
],
|
||||
"modules": [
|
||||
{
|
||||
"name": "kirigamiaddons",
|
||||
"config-opts": [
|
||||
"-DBUILD_TESTING=OFF"
|
||||
],
|
||||
"buildsystem": "cmake-ninja",
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://invent.kde.org/libraries/kirigami-addons.git"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "opencv",
|
||||
"config-opts": [
|
||||
@@ -65,7 +78,6 @@
|
||||
"name": "olm",
|
||||
"buildsystem": "cmake-ninja",
|
||||
"config-opts": [
|
||||
"-DCMAKE_POLICY_VERSION_MINIMUM=3.5",
|
||||
"-DOLM_TESTS=OFF"
|
||||
],
|
||||
"sources": [
|
||||
@@ -172,8 +184,8 @@
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://download.kde.org/stable/release-service/25.08.3/src/kunifiedpush-25.08.3.tar.xz",
|
||||
"sha256": "e8c924438d5359f0fa0930ab35111012076e3a0ff4e959d6929595571383320a",
|
||||
"url": "https://download.kde.org/stable/release-service/25.08.0/src/kunifiedpush-25.08.0.tar.xz",
|
||||
"sha256": "846db6ffc7d93f6afea7ce0d5a9f10b52792157ceb593856542279f4197f3518",
|
||||
"x-checker-data": {
|
||||
"type": "anitya",
|
||||
"project-id": 8763,
|
||||
|
||||
@@ -4,18 +4,18 @@
|
||||
include:
|
||||
- project: sysadmin/ci-utilities
|
||||
file:
|
||||
#- /gitlab-templates/reuse-lint.yml
|
||||
#- /gitlab-templates/json-validation.yml
|
||||
#- /gitlab-templates/xml-lint.yml
|
||||
#- /gitlab-templates/yaml-lint.yml
|
||||
#- /gitlab-templates/android-qt6.yml
|
||||
#- /gitlab-templates/linux-qt6.yml
|
||||
#- /gitlab-templates/linux-qt6-next.yml
|
||||
#- /gitlab-templates/windows-qt6.yml
|
||||
#- /gitlab-templates/freebsd-qt6.yml
|
||||
#- /gitlab-templates/flatpak.yml
|
||||
- /gitlab-templates/reuse-lint.yml
|
||||
- /gitlab-templates/json-validation.yml
|
||||
- /gitlab-templates/xml-lint.yml
|
||||
- /gitlab-templates/yaml-lint.yml
|
||||
- /gitlab-templates/android-qt6.yml
|
||||
- /gitlab-templates/linux-qt6.yml
|
||||
- /gitlab-templates/linux-qt6-next.yml
|
||||
- /gitlab-templates/windows-qt6.yml
|
||||
- /gitlab-templates/freebsd-qt6.yml
|
||||
- /gitlab-templates/flatpak.yml
|
||||
- /gitlab-templates/snap-snapcraft-lxd.yml
|
||||
#- /gitlab-templates/craft-android-qt6-apks.yml
|
||||
#- /gitlab-templates/craft-appimage-qt6.yml
|
||||
#- /gitlab-templates/craft-windows-x86-64-qt6.yml
|
||||
#- /gitlab-templates/craft-windows-appx-qt6.yml
|
||||
- /gitlab-templates/craft-android-qt6-apks.yml
|
||||
- /gitlab-templates/craft-appimage-qt6.yml
|
||||
- /gitlab-templates/craft-windows-x86-64-qt6.yml
|
||||
- /gitlab-templates/craft-windows-appx-qt6.yml
|
||||
|
||||
@@ -10,7 +10,6 @@ Dependencies:
|
||||
'frameworks/ki18n': '@latest-kf6'
|
||||
'frameworks/kconfig': '@latest-kf6'
|
||||
'frameworks/syntax-highlighting': '@latest-kf6'
|
||||
'frameworks/kiconthemes': '@latest-kf6'
|
||||
'frameworks/kitemmodels': '@latest-kf6'
|
||||
'frameworks/kquickcharts': '@latest-kf6'
|
||||
'frameworks/knotifications': '@latest-kf6'
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# KDE Applications version, managed by release script.
|
||||
set(RELEASE_SERVICE_VERSION_MAJOR "26")
|
||||
set(RELEASE_SERVICE_VERSION_MINOR "03")
|
||||
set(RELEASE_SERVICE_VERSION_MICRO "70")
|
||||
set(RELEASE_SERVICE_VERSION_MAJOR "25")
|
||||
set(RELEASE_SERVICE_VERSION_MINOR "12")
|
||||
set(RELEASE_SERVICE_VERSION_MICRO "0")
|
||||
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
|
||||
|
||||
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
|
||||
@@ -46,6 +46,10 @@ if (NOT ANDROID)
|
||||
include(KDEClangFormat)
|
||||
endif()
|
||||
|
||||
if(NEOCHAT_FLATPAK)
|
||||
include(cmake/Flatpak.cmake)
|
||||
endif()
|
||||
|
||||
set(QUOTIENT_FORCE_NAMESPACED_INCLUDES TRUE)
|
||||
|
||||
ecm_set_disabled_deprecation_versions(Qt 6.9.0 KF 6.17.0)
|
||||
@@ -65,7 +69,7 @@ if (QT_KNOWN_POLICY_QTP0004)
|
||||
qt_policy(SET QTP0004 NEW)
|
||||
endif ()
|
||||
|
||||
find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami I18n Notifications Config CoreAddons Sonnet ItemModels ColorScheme IconThemes)
|
||||
find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami I18n Notifications Config CoreAddons Sonnet ItemModels ColorScheme)
|
||||
set_package_properties(KF6 PROPERTIES
|
||||
TYPE REQUIRED
|
||||
PURPOSE "Basic application components"
|
||||
|
||||
@@ -63,7 +63,7 @@ void ActionsTest::testActions_data()
|
||||
QTest::addColumn<std::optional<QString>>("resultText");
|
||||
QTest::addColumn<std::optional<Quotient::RoomMessageEvent::MsgType>>("type");
|
||||
|
||||
QTest::newRow("shrug") << u"/shrug Hello"_s << std::make_optional(u"¯\\\\\\_(ツ)\\_/¯ Hello"_s)
|
||||
QTest::newRow("shrug") << u"/shrug Hello"_s << std::make_optional(u"¯\\\\_(ツ)_/¯ Hello"_s)
|
||||
<< std::make_optional(Quotient::RoomMessageEvent::MsgType::Text);
|
||||
QTest::newRow("lenny") << u"/lenny Hello"_s << std::make_optional(u"( ͡° ͜ʖ ͡°) Hello"_s) << std::make_optional(Quotient::RoomMessageEvent::MsgType::Text);
|
||||
QTest::newRow("tableflip") << u"/tableflip Hello"_s << std::make_optional(u"(╯°□°)╯︵ ┻━┻ Hello"_s)
|
||||
|
||||
14
cmake/Flatpak.cmake
Normal file
14
cmake/Flatpak.cmake
Normal file
@@ -0,0 +1,14 @@
|
||||
# SPDX-FileCopyrightText: 2020 Carl Schwan <carl@carlschwan.eu>
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Include FontConfig config which uses the Emoji One font from the
|
||||
# KDE Flatpak SDK.
|
||||
install(
|
||||
FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/cmake/Flatpak/99-noto-mono-color-emoji.conf
|
||||
DESTINATION
|
||||
${CMAKE_INSTALL_SYSCONFDIR}/fonts/local.conf
|
||||
)
|
||||
|
||||
23
cmake/Flatpak/99-noto-mono-color-emoji.conf
Normal file
23
cmake/Flatpak/99-noto-mono-color-emoji.conf
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
|
||||
<fontconfig>
|
||||
<alias>
|
||||
<family>serif</family>
|
||||
<prefer>
|
||||
<family>Noto Color Emoji</family>
|
||||
</prefer>
|
||||
</alias>
|
||||
<alias>
|
||||
<family>sans-serif</family>
|
||||
<prefer>
|
||||
<family>Noto Color Emoji</family>
|
||||
</prefer>
|
||||
</alias>
|
||||
<alias>
|
||||
<family>monospace</family>
|
||||
<prefer>
|
||||
<family>Noto Color Emoji</family>
|
||||
</prefer>
|
||||
</alias>
|
||||
</fontconfig>
|
||||
|
||||
@@ -320,6 +320,7 @@
|
||||
<value key="KDE::windows_store::StoreLogoSquare">https://invent.kde.org/network/neochat/-/raw/master/icons/windows/storelogo-1080x1080.png</value>
|
||||
<value key="KDE::windows_store::Icon">https://invent.kde.org/network/neochat/-/raw/master/icons/300-apps-neochat.png</value>
|
||||
<value key="KDE::windows_store::PromotionalArt16x9">https://invent.kde.org/network/neochat/-/raw/master/icons/windows/promoimage-1920x1080.png</value>
|
||||
<value key="KDE::supporters">Anonymous donor, Akseli</value>
|
||||
</custom>
|
||||
<launchable type="desktop-id">org.kde.neochat.desktop</launchable>
|
||||
<screenshots>
|
||||
@@ -487,7 +488,6 @@
|
||||
<content_attribute id="social-chat">intense</content_attribute>
|
||||
</content_rating>
|
||||
<releases>
|
||||
<release version="25.12.1" date="2026-01-08"/>
|
||||
<release version="25.12.0" date="2025-12-11"/>
|
||||
<release version="25.08.3" date="2025-11-06"/>
|
||||
<release version="25.08.2" date="2025-10-09"/>
|
||||
|
||||
@@ -108,7 +108,6 @@ Comment[ia]=Conversation en ditecto sur Matrix
|
||||
Comment[it]= su Matrix
|
||||
Comment[ka]=ჩატი Matrix-ზე
|
||||
Comment[ko]=Matrix에서 대화하기
|
||||
Comment[lt]=Pokalbiai per Matrix
|
||||
Comment[lv]=Tērzējiet „Matrix“ tīklā
|
||||
Comment[nl]=Chat op Matrix
|
||||
Comment[pl]=Rozmawiaj na Matriksie
|
||||
|
||||
939
po/ar/neochat.po
939
po/ar/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
979
po/az/neochat.po
979
po/az/neochat.po
File diff suppressed because it is too large
Load Diff
1074
po/ca/neochat.po
1074
po/ca/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
932
po/cs/neochat.po
932
po/cs/neochat.po
File diff suppressed because it is too large
Load Diff
913
po/da/neochat.po
913
po/da/neochat.po
File diff suppressed because it is too large
Load Diff
1993
po/de/neochat.po
1993
po/de/neochat.po
File diff suppressed because it is too large
Load Diff
1022
po/el/neochat.po
1022
po/el/neochat.po
File diff suppressed because it is too large
Load Diff
1060
po/en_GB/neochat.po
1060
po/en_GB/neochat.po
File diff suppressed because it is too large
Load Diff
1055
po/eo/neochat.po
1055
po/eo/neochat.po
File diff suppressed because it is too large
Load Diff
812
po/es/neochat.po
812
po/es/neochat.po
File diff suppressed because it is too large
Load Diff
1210
po/eu/neochat.po
1210
po/eu/neochat.po
File diff suppressed because it is too large
Load Diff
1255
po/fi/neochat.po
1255
po/fi/neochat.po
File diff suppressed because it is too large
Load Diff
932
po/fr/neochat.po
932
po/fr/neochat.po
File diff suppressed because it is too large
Load Diff
7082
po/ga/neochat.po
7082
po/ga/neochat.po
File diff suppressed because it is too large
Load Diff
1059
po/gl/neochat.po
1059
po/gl/neochat.po
File diff suppressed because it is too large
Load Diff
908
po/he/neochat.po
908
po/he/neochat.po
File diff suppressed because it is too large
Load Diff
1040
po/hi/neochat.po
1040
po/hi/neochat.po
File diff suppressed because it is too large
Load Diff
1090
po/hu/neochat.po
1090
po/hu/neochat.po
File diff suppressed because it is too large
Load Diff
1034
po/ia/neochat.po
1034
po/ia/neochat.po
File diff suppressed because it is too large
Load Diff
1026
po/id/neochat.po
1026
po/id/neochat.po
File diff suppressed because it is too large
Load Diff
982
po/ie/neochat.po
982
po/ie/neochat.po
File diff suppressed because it is too large
Load Diff
947
po/it/neochat.po
947
po/it/neochat.po
File diff suppressed because it is too large
Load Diff
735
po/ja/neochat.po
735
po/ja/neochat.po
File diff suppressed because it is too large
Load Diff
913
po/ka/neochat.po
913
po/ka/neochat.po
File diff suppressed because it is too large
Load Diff
1035
po/ko/neochat.po
1035
po/ko/neochat.po
File diff suppressed because it is too large
Load Diff
1034
po/lt/neochat.po
1034
po/lt/neochat.po
File diff suppressed because it is too large
Load Diff
1275
po/lv/neochat.po
1275
po/lv/neochat.po
File diff suppressed because it is too large
Load Diff
927
po/nl/neochat.po
927
po/nl/neochat.po
File diff suppressed because it is too large
Load Diff
901
po/nn/neochat.po
901
po/nn/neochat.po
File diff suppressed because it is too large
Load Diff
976
po/pa/neochat.po
976
po/pa/neochat.po
File diff suppressed because it is too large
Load Diff
966
po/pl/neochat.po
966
po/pl/neochat.po
File diff suppressed because it is too large
Load Diff
1020
po/pt/neochat.po
1020
po/pt/neochat.po
File diff suppressed because it is too large
Load Diff
@@ -1,122 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.5-Based Variant V1.1//EN" "dtd/kdedbx45.dtd" [
|
||||
<!ENTITY % Brazilian-Portuguese "INCLUDE">
|
||||
]>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
|
||||
SPDX-License-Identifier: CC-BY-SA-4.0
|
||||
-->
|
||||
|
||||
<refentry lang="&language;">
|
||||
<refentryinfo>
|
||||
<title
|
||||
>Manual do Usuário do NeoChat</title>
|
||||
<author
|
||||
><firstname
|
||||
>Carl</firstname
|
||||
><surname
|
||||
>Schwan</surname
|
||||
> <contrib
|
||||
>NeoChat man page.</contrib
|
||||
> <email
|
||||
>carl@carlschwan.eu</email
|
||||
></author>
|
||||
<date
|
||||
>01/11/2022</date>
|
||||
<releaseinfo
|
||||
>22.09</releaseinfo>
|
||||
<productname
|
||||
>NeoChat</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>
|
||||
<command
|
||||
>neochat</command>
|
||||
</refentrytitle>
|
||||
<manvolnum
|
||||
>1</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname
|
||||
>neochat</refname>
|
||||
<refpurpose
|
||||
>Cliente para interação com o protocolo de mensagens Matrix.</refpurpose>
|
||||
</refnamediv>
|
||||
<!-- body begins here -->
|
||||
<refsynopsisdiv id='synopsis'>
|
||||
<cmdsynopsis
|
||||
><command
|
||||
>neochat</command
|
||||
> <arg choice="opt"
|
||||
><replaceable
|
||||
>URI</replaceable
|
||||
></arg
|
||||
> </cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
|
||||
<refsect1 id="description">
|
||||
<title
|
||||
>Descrição</title>
|
||||
<para
|
||||
>O <command
|
||||
>neochat</command
|
||||
> é um aplicativo de bate-papo para o protocolo Matrix. Ele funciona tanto em computadores quanto em dispositivos móveis. </para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="options"
|
||||
><title
|
||||
>Opções</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term
|
||||
><option
|
||||
>URI</option
|
||||
></term>
|
||||
<listitem>
|
||||
<para
|
||||
>O URI da matriz para um usuário ou uma sala. Por exemplo, matrix:u/usuário:exemplo.org e matrix:r/root:exemplo.org. Isso fará com que o NeoChat tente abrir a sala ou conversa especificada. </para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="bug">
|
||||
<title
|
||||
>Relatar bugs</title>
|
||||
<para
|
||||
>Você pode reportar erros e solicitar novas funcionalidades em <ulink url="https://bugs.kde.org/enter_bug.cgi?product=NeoChat&component=General"
|
||||
>https://bugs.kde.org/enter_bug.cgi?product=NeoChat&component=General</ulink
|
||||
></para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title
|
||||
>Veja também</title>
|
||||
<simplelist>
|
||||
<member
|
||||
>Lista de perguntas frequentes sobre o Matrix <ulink url="https://matrix.org/faq/"
|
||||
>https://matrix.org/faq/</ulink
|
||||
> </member>
|
||||
<member
|
||||
>kf5options(7)</member>
|
||||
<member
|
||||
>qt5options(7)</member>
|
||||
</simplelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="copyright"
|
||||
><title
|
||||
>Direitos autorais</title>
|
||||
<para
|
||||
>Direitos autorais © 2020-2022 Tobias Fella </para>
|
||||
<para
|
||||
>Direitos autorais © 2020-2022 Carl Schwan </para>
|
||||
<para
|
||||
>Licença: GNU General Public Versão 3 ou posterior <ulink url="https://www.gnu.org/licenses/gpl-3.0.html"
|
||||
>https://www.gnu.org/licenses/gpl-3.0.html</ulink
|
||||
>></para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
File diff suppressed because it is too large
Load Diff
913
po/ro/neochat.po
913
po/ro/neochat.po
File diff suppressed because it is too large
Load Diff
1071
po/ru/neochat.po
1071
po/ru/neochat.po
File diff suppressed because it is too large
Load Diff
1046
po/sa/neochat.po
1046
po/sa/neochat.po
File diff suppressed because it is too large
Load Diff
1005
po/sk/neochat.po
1005
po/sk/neochat.po
File diff suppressed because it is too large
Load Diff
917
po/sl/neochat.po
917
po/sl/neochat.po
File diff suppressed because it is too large
Load Diff
1217
po/sv/neochat.po
1217
po/sv/neochat.po
File diff suppressed because it is too large
Load Diff
1216
po/ta/neochat.po
1216
po/ta/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -22,7 +22,7 @@ SPDX-License-Identifier: CC-BY-SA-4.0
|
||||
>carl@carlschwan.eu</email
|
||||
></author>
|
||||
<date
|
||||
>2022‒11‒01</date>
|
||||
>2022-11-01</date>
|
||||
<releaseinfo
|
||||
>22.09</releaseinfo>
|
||||
<productname
|
||||
@@ -111,9 +111,9 @@ SPDX-License-Identifier: CC-BY-SA-4.0
|
||||
><title
|
||||
>Telif Hakkı</title>
|
||||
<para
|
||||
>Telif hakkı © 2020–2022 Tobias Fella </para>
|
||||
>Telif hakkı © 2020-2022 Tobias Fella </para>
|
||||
<para
|
||||
>Telif hakkı © 2020–2022 Carl Schwan </para>
|
||||
>Telif hakkı © 2020-2022 Carl Schwan </para>
|
||||
<para
|
||||
>Lisans: GNU Genel Kamu Lisansa, 3. sürüm veya sonrası <<ulink url="https://www.gnu.org/licenses/gpl-3.0.html"
|
||||
>https://www.gnu.org/licenses/gpl-3.0.html</ulink
|
||||
|
||||
908
po/tr/neochat.po
908
po/tr/neochat.po
File diff suppressed because it is too large
Load Diff
930
po/uk/neochat.po
930
po/uk/neochat.po
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
110
snapcraft.yaml
110
snapcraft.yaml
@@ -10,7 +10,7 @@ confinement: strict
|
||||
apps:
|
||||
neochat:
|
||||
extensions:
|
||||
- kde-neon-6@latest/beta
|
||||
- kde-neon-6
|
||||
command: usr/bin/neochat
|
||||
common-id: org.kde.neochat
|
||||
desktop: usr/share/applications/org.kde.neochat.desktop
|
||||
@@ -25,7 +25,7 @@ apps:
|
||||
- password-manager-service
|
||||
- accounts-service
|
||||
environment:
|
||||
QT_PLUGIN_PATH: "$SNAP/usr/lib/$CRAFT_ARCH_TRIPLET/plugins:/snap/kf6-core24/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/plugins"
|
||||
QT_PLUGIN_PATH: "$SNAP/usr/lib/$CRAFT_ARCH_TRIPLET/plugins/snap/kf6-core24/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/plugins"
|
||||
QML_IMPORT_PATH: "$SNAP/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/qml:/snap/kf6-core24/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/qml"
|
||||
|
||||
compression: lzo
|
||||
@@ -55,11 +55,53 @@ parts:
|
||||
- -usr/lib/*/pkgconfig
|
||||
- -usr/lib/*/cmake
|
||||
|
||||
libsecret:
|
||||
source: https://gitlab.gnome.org/GNOME/libsecret.git
|
||||
source-tag: '0.21.4'
|
||||
source-depth: 1
|
||||
plugin: meson
|
||||
meson-parameters:
|
||||
- --prefix=/usr
|
||||
- -Doptimization=3
|
||||
- -Ddebug=true
|
||||
- -Dmanpage=false
|
||||
- -Dvapi=false
|
||||
- -Dintrospection=false
|
||||
- -Dcrypto=disabled
|
||||
- -Dgtk_doc=false
|
||||
build-packages:
|
||||
- meson
|
||||
- libglib2.0-dev
|
||||
- libgcrypt20-dev
|
||||
prime:
|
||||
- -usr/include
|
||||
- -usr/lib/*/pkgconfig
|
||||
|
||||
qtkeychain:
|
||||
after: [libsecret]
|
||||
source: https://github.com/frankosterfeld/qtkeychain.git
|
||||
source-tag: 0.14.3
|
||||
source-depth: 1
|
||||
plugin: cmake
|
||||
build-environment:
|
||||
- PATH: /snap/bin:${PATH}
|
||||
- PKG_CONFIG_PATH: "$CRAFT_STAGE/usr/lib/$CRAFT_ARCH_TRIPLET/pkgconfig:$PKG_CONFIG_PATH"
|
||||
cmake-parameters:
|
||||
- -DCMAKE_INSTALL_PREFIX=/usr
|
||||
- -DCMAKE_BUILD_TYPE=Release
|
||||
- -DBUILD_TRANSLATIONS=NO
|
||||
- -DBUILD_WITH_QT6=ON
|
||||
prime:
|
||||
- -usr/include
|
||||
- -usr/lib/*/pkgconfig
|
||||
- -usr/lib/*/cmake
|
||||
|
||||
libquotient:
|
||||
after:
|
||||
- olm
|
||||
- qtkeychain
|
||||
source: https://github.com/quotient-im/libQuotient.git
|
||||
source-branch: 0.9.5
|
||||
source-tag: 0.9.2
|
||||
source-depth: 1
|
||||
plugin: cmake
|
||||
build-environment:
|
||||
@@ -68,16 +110,12 @@ parts:
|
||||
- cmake
|
||||
build-packages:
|
||||
- libssl-dev
|
||||
- curl
|
||||
cmake-parameters:
|
||||
- -DCMAKE_INSTALL_PREFIX=/usr
|
||||
- -DCMAKE_BUILD_TYPE=Release
|
||||
- -DBUILD_TESTING=OFF
|
||||
- -DQuotient_ENABLE_E2EE=ON
|
||||
- -DBUILD_WITH_QT6=ON
|
||||
override-pull: |
|
||||
craftctl default
|
||||
curl https://github.com/quotient-im/libQuotient/commit/ea83157eed37ff97ab275a5d14c971f0a5a70595.diff | patch -p1
|
||||
prime:
|
||||
- -usr/include
|
||||
- -usr/lib/*/pkgconfig
|
||||
@@ -85,39 +123,38 @@ parts:
|
||||
|
||||
kquickimageeditor:
|
||||
source: https://invent.kde.org/libraries/kquickimageeditor.git
|
||||
source-tag: 'v0.6.0'
|
||||
source-tag: 'v0.3.0'
|
||||
source-depth: 1
|
||||
plugin: cmake
|
||||
build-environment: &build-environment
|
||||
- LD_LIBRARY_PATH: "/snap/kde-qt6-core24-sdk/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:/snap/kde-qt6-core24-sdk/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libproxy:/snap/kde-qt6-core24-sdk/current/usr/lib:/snap/kf6-core24-sdk/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:/snap/kf6-core24-sdk/current/usr/lib:$CRAFT_STAGE/usr/lib:$CRAFT_STAGE/lib/:$CRAFT_STAGE/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
|
||||
- PATH: /snap/kde-qt6-core24-sdk/current/usr/bin${PATH:+:$PATH}
|
||||
- PKG_CONFIG_PATH: /snap/kde-qt6-core24-sdk/current/usr/lib/${CRAFT_ARCH_TRIPLET_BUILD_FOR}/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}
|
||||
build-environment:
|
||||
- PATH: /snap/bin:${PATH}
|
||||
- PYTHONPATH: ${CRAFT_STAGE}/lib/python3.12/site-packages:${CRAFT_STAGE}/usr/lib/python3/dist-packages
|
||||
- XDG_DATA_DIRS: $CRAFT_STAGE/usr/share:/snap/kde-qt6-core24-sdk/current/usr/share:/usr/share${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}
|
||||
- XDG_CONFIG_HOME: $CRAFT_STAGE/etc/xdg:/snap/kde-qt6-core24-sdk/current/etc/xdg:/etc/xdg${XDG_CONFIG_HOME:+:$XDG_CONFIG_HOME}
|
||||
cmake-parameters: &cmake-parameters
|
||||
- LD_LIBRARY_PATH: "/snap/mesa-2404/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:$CRAFT_STAGE/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:/snap/kde-qt6-core24-sdk/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libproxy:$LD_LIBRARY_PATH"
|
||||
cmake-parameters:
|
||||
- -DCMAKE_INSTALL_PREFIX=/usr
|
||||
- -DCMAKE_BUILD_TYPE=Release
|
||||
- -DQT_MAJOR_VERSION=6
|
||||
- -DBUILD_WITH_QT6=ON
|
||||
- -DBUILD_TESTING=OFF
|
||||
- "-DCMAKE_FIND_ROOT_PATH=$CRAFT_STAGE\\;/snap/kde-qt6-core24-sdk/current\\;/snap/kf6-core24-sdk/current/usr"
|
||||
- "-DCMAKE_PREFIX_PATH=$CRAFT_STAGE\\;/snap/kde-qt6-core24-sdk/current\\;/snap/kf6-core24-sdk/current/usr"
|
||||
prime: &prime
|
||||
prime:
|
||||
- -usr/include
|
||||
- -usr/lib/*/pkgconfig
|
||||
- -usr/lib/*/cmake
|
||||
|
||||
kunifiedpush:
|
||||
source: https://invent.kde.org/libraries/kunifiedpush.git
|
||||
source-branch: release/24.12
|
||||
plugin: cmake
|
||||
build-environment: *build-environment
|
||||
cmake-parameters: *cmake-parameters
|
||||
prime: *prime
|
||||
build-environment:
|
||||
- PATH: /snap/bin:${PATH}
|
||||
- PYTHONPATH: ${CRAFT_STAGE}/lib/python3.12/site-packages:${CRAFT_STAGE}/usr/lib/python3/dist-packages
|
||||
- LD_LIBRARY_PATH: "/snap/mesa-2404/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:$CRAFT_STAGE/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:/snap/kde-qt6-core24-sdk/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libproxy:$LD_LIBRARY_PATH"
|
||||
cmake-parameters:
|
||||
- -DCMAKE_INSTALL_PREFIX=/usr
|
||||
- -DCMAKE_BUILD_TYPE=Release
|
||||
- -DBUILD_TESTING=OFF
|
||||
|
||||
neochat:
|
||||
after:
|
||||
- qtkeychain
|
||||
- libquotient
|
||||
- kquickimageeditor
|
||||
- kunifiedpush
|
||||
@@ -125,20 +162,24 @@ parts:
|
||||
- usr/share/metainfo/org.kde.neochat.appdata.xml
|
||||
source: .
|
||||
plugin: cmake
|
||||
build-environment: *build-environment
|
||||
build-environment:
|
||||
- PATH: /snap/bin:${PATH}
|
||||
- PYTHONPATH: ${CRAFT_STAGE}/lib/python3.12/site-packages:${CRAFT_STAGE}/usr/lib/python3/dist-packages
|
||||
- LD_LIBRARY_PATH: "/snap/mesa-2404/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:$CRAFT_STAGE/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:/snap/kde-qt6-core24-sdk/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libproxy:$LD_LIBRARY_PATH"
|
||||
build-packages:
|
||||
- cmark
|
||||
- docbook-xml
|
||||
- docbook-xsl
|
||||
- duktape-dev
|
||||
- libcmark-dev
|
||||
- libsqlite3-dev
|
||||
- libvulkan-dev
|
||||
- libxkbcommon-dev
|
||||
- libicu-dev
|
||||
- libpulse0
|
||||
cmake-parameters: *cmake-parameters
|
||||
prime: *prime
|
||||
cmake-parameters:
|
||||
- -DCMAKE_INSTALL_PREFIX=/usr
|
||||
- -DCMAKE_BUILD_TYPE=Release
|
||||
- -DBUILD_TESTING=OFF
|
||||
prime:
|
||||
- -usr/share/man
|
||||
|
||||
deps:
|
||||
after: [neochat]
|
||||
@@ -157,14 +198,3 @@ parts:
|
||||
${CRAFT_PART_SRC}/bin/gpu-2404-cleanup mesa-2404
|
||||
prime:
|
||||
- bin/gpu-2404-wrapper
|
||||
|
||||
cleanup:
|
||||
after:
|
||||
- neochat
|
||||
plugin: nil
|
||||
override-prime: |
|
||||
set -eux
|
||||
for snap in "core24" "kf6-core24"; do
|
||||
cd "/snap/$snap/current" && find . -type f,l -exec rm -rf "${CRAFT_PRIME}/{}" \;
|
||||
done
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# SPDX-FileCopyrightText: 2020-2021 Tobias Fella <tobias.fella@kde.org>
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
qt_add_library(neochat STATIC
|
||||
add_library(neochat STATIC
|
||||
controller.cpp
|
||||
controller.h
|
||||
roommanager.cpp
|
||||
@@ -35,8 +35,6 @@ qt_add_library(neochat STATIC
|
||||
models/commonroomsmodel.h
|
||||
texttospeechhelper.h
|
||||
texttospeechhelper.cpp
|
||||
models/limitermodel.cpp
|
||||
models/limitermodel.h
|
||||
)
|
||||
|
||||
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
|
||||
@@ -142,17 +140,10 @@ if(WIN32)
|
||||
set_target_properties(neochat PROPERTIES OUTPUT_NAME "neochatlib")
|
||||
endif()
|
||||
|
||||
qt_add_executable(neochat-app
|
||||
add_executable(neochat-app
|
||||
main.cpp
|
||||
)
|
||||
|
||||
if(ANDROID)
|
||||
set_target_properties(neochat-app PROPERTIES
|
||||
OUTPUT_NAME "neochat-app"
|
||||
PREFIX "lib"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(TARGET Qt::WebView)
|
||||
target_link_libraries(neochat-app PUBLIC Qt::WebView)
|
||||
target_compile_definitions(neochat-app PUBLIC -DHAVE_WEBVIEW)
|
||||
@@ -162,7 +153,6 @@ target_include_directories(neochat-app PRIVATE ${CMAKE_BINARY_DIR})
|
||||
|
||||
target_link_libraries(neochat-app PRIVATE
|
||||
neochat
|
||||
KF6::IconThemes
|
||||
)
|
||||
|
||||
ecm_add_app_icon(NEOCHAT_ICON ICONS ${CMAKE_SOURCE_DIR}/128-logo.png)
|
||||
@@ -193,7 +183,7 @@ else()
|
||||
endif()
|
||||
|
||||
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/models)
|
||||
target_link_libraries(neochat PRIVATE neochatplugin Loginplugin Roomsplugin RoomInfoplugin MessageContentplugin Timelineplugin Spacesplugin Chatbarplugin Settingsplugin Devtoolsplugin)
|
||||
target_link_libraries(neochat PRIVATE Loginplugin Roomsplugin RoomInfoplugin MessageContentplugin Timelineplugin Spacesplugin Chatbarplugin Settingsplugin Devtoolsplugin)
|
||||
target_link_libraries(neochat PUBLIC
|
||||
LibNeoChat
|
||||
Timeline
|
||||
|
||||
@@ -246,10 +246,7 @@ void Controller::initActiveConnection(NeoChatConnection *oldConnection, NeoChatC
|
||||
if (newConnection) {
|
||||
connect(newConnection, &NeoChatConnection::errorOccured, this, &Controller::errorOccured);
|
||||
connect(newConnection, &NeoChatConnection::badgeNotificationCountChanged, this, &Controller::updateBadgeNotificationCount);
|
||||
|
||||
// Refresh and update manually, in case we init too late for the badge count to actually change.
|
||||
newConnection->refreshBadgeNotificationCount();
|
||||
updateBadgeNotificationCount(newConnection->badgeNotificationCount());
|
||||
}
|
||||
Q_EMIT activeConnectionChanged(newConnection);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include <KWindowSystem>
|
||||
#endif
|
||||
|
||||
#include <KIconTheme>
|
||||
#include <KLocalizedQmlContext>
|
||||
#include <KLocalizedString>
|
||||
#include <KirigamiApp>
|
||||
@@ -103,10 +102,6 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
QNetworkProxyFactory::setUseSystemConfiguration(true);
|
||||
|
||||
// We currently need to do this ourselves,
|
||||
// KirigamiApp currently called this after constructing the app which breaks icons on Windows.
|
||||
KIconTheme::initTheme();
|
||||
|
||||
#ifdef HAVE_WEBVIEW
|
||||
QtWebView::initialize();
|
||||
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
|
||||
@@ -166,6 +161,12 @@ int main(int argc, char *argv[])
|
||||
Connection::setEncryptionDefault(true);
|
||||
Connection::setDirectChatEncryptionDefault(true);
|
||||
|
||||
#ifdef NEOCHAT_FLATPAK
|
||||
// Copy over the included FontConfig configuration to the
|
||||
// app's config dir:
|
||||
QFile::copy(u"/app/etc/fonts/conf.d/99-noto-mono-color-emoji.conf"_s, u"/var/config/fontconfig/conf.d/99-noto-mono-color-emoji.conf"_s);
|
||||
#endif
|
||||
|
||||
ColorSchemer colorScheme;
|
||||
|
||||
QCommandLineParser parser;
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "jobs/neochatgetcommonroomsjob.h"
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <Quotient/room.h>
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
@@ -40,22 +39,8 @@ void CommonRoomsModel::setUserId(const QString &userId)
|
||||
|
||||
QVariant CommonRoomsModel::data(const QModelIndex &index, int roleName) const
|
||||
{
|
||||
auto roomId = m_commonRooms[index.row()];
|
||||
auto room = connection()->room(roomId);
|
||||
if (!room) {
|
||||
return {};
|
||||
}
|
||||
|
||||
switch (roleName) {
|
||||
case Qt::DisplayRole:
|
||||
case RoomNameRole:
|
||||
return room->displayName();
|
||||
case RoomAvatarRole:
|
||||
return room->avatarUrl();
|
||||
case RoomIdRole:
|
||||
return roomId;
|
||||
}
|
||||
|
||||
Q_UNUSED(index)
|
||||
Q_UNUSED(roleName)
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -65,15 +50,6 @@ int CommonRoomsModel::rowCount(const QModelIndex &parent) const
|
||||
return m_commonRooms.size();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> CommonRoomsModel::roleNames() const
|
||||
{
|
||||
return {
|
||||
{RoomIdRole, "roomId"},
|
||||
{RoomNameRole, "roomName"},
|
||||
{RoomAvatarRole, "roomAvatar"},
|
||||
};
|
||||
}
|
||||
|
||||
void CommonRoomsModel::reload()
|
||||
{
|
||||
if (!m_connection || m_userId.isEmpty()) {
|
||||
|
||||
@@ -24,9 +24,7 @@ class CommonRoomsModel : public QAbstractListModel
|
||||
|
||||
public:
|
||||
enum Roles {
|
||||
RoomIdRole = Qt::UserRole,
|
||||
RoomNameRole,
|
||||
RoomAvatarRole,
|
||||
RoomIdRole = Qt::DisplayRole,
|
||||
};
|
||||
Q_ENUM(Roles)
|
||||
|
||||
@@ -41,8 +39,6 @@ public:
|
||||
[[nodiscard]] QVariant data(const QModelIndex &index, int roleName) const override;
|
||||
[[nodiscard]] Q_INVOKABLE int rowCount(const QModelIndex &parent = {}) const override;
|
||||
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void connectionChanged();
|
||||
void userIdChanged();
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include "models/limitermodel.h"
|
||||
|
||||
LimiterModel::LimiterModel(QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
{
|
||||
connect(this, &QSortFilterProxyModel::rowsInserted, this, &LimiterModel::extraCountChanged);
|
||||
connect(this, &QSortFilterProxyModel::rowsRemoved, this, &LimiterModel::extraCountChanged);
|
||||
connect(this, &QSortFilterProxyModel::modelReset, this, &LimiterModel::extraCountChanged);
|
||||
}
|
||||
|
||||
int LimiterModel::maximumCount() const
|
||||
{
|
||||
return m_maximumCount;
|
||||
}
|
||||
|
||||
void LimiterModel::setMaximumCount(int maximumCount)
|
||||
{
|
||||
if (m_maximumCount != maximumCount) {
|
||||
m_maximumCount = maximumCount;
|
||||
Q_EMIT maximumCountChanged();
|
||||
}
|
||||
}
|
||||
|
||||
int LimiterModel::extraCount() const
|
||||
{
|
||||
if (sourceModel()) {
|
||||
return std::max(sourceModel()->rowCount() - maximumCount(), 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool LimiterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
|
||||
{
|
||||
Q_UNUSED(source_parent)
|
||||
return source_row < maximumCount();
|
||||
}
|
||||
|
||||
#include "moc_limitermodel.cpp"
|
||||
@@ -1,41 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QQmlEngine>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
/**
|
||||
* @class LimiterModel
|
||||
*
|
||||
* @brief Takes a source QAbstractItemModel model and only displays a desired maximum amount.
|
||||
*
|
||||
* Also gives you the remaining (filtered out) items, useful for sticking in a label or somesuch.
|
||||
*/
|
||||
class LimiterModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
Q_PROPERTY(int maximumCount READ maximumCount WRITE setMaximumCount NOTIFY maximumCountChanged)
|
||||
Q_PROPERTY(int extraCount READ extraCount NOTIFY extraCountChanged)
|
||||
|
||||
public:
|
||||
explicit LimiterModel(QObject *parent = nullptr);
|
||||
|
||||
[[nodiscard]] int maximumCount() const;
|
||||
void setMaximumCount(int maximumCount);
|
||||
|
||||
[[nodiscard]] int extraCount() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void maximumCountChanged();
|
||||
void extraCountChanged();
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
|
||||
|
||||
private:
|
||||
int m_maximumCount = 0;
|
||||
};
|
||||
@@ -287,7 +287,6 @@ Name[ia]=Comparti
|
||||
Name[it]=Condivisione
|
||||
Name[ka]=გაზიარება
|
||||
Name[ko]=공유
|
||||
Name[lt]=Bendrinti
|
||||
Name[lv]=Kopīgot
|
||||
Name[nl]=Gedeelde
|
||||
Name[nn]=Del
|
||||
@@ -323,7 +322,6 @@ Comment[ia]=Le exito de compartir un pecietta de contento
|
||||
Comment[it]=Il risultato della condivisione di un contenuto
|
||||
Comment[ka]=შემცველობის ნაწილის გაზიარების შედეგი
|
||||
Comment[ko]=콘텐츠 공유 결과
|
||||
Comment[lt]=Turinio dalies bendrinimo rezultatas
|
||||
Comment[lv]=Satura kopīgošanas rezultāts
|
||||
Comment[nl]=Het resultaat van het delen van een stukje inhoud
|
||||
Comment[nn]=Resultatet av deling av innhald
|
||||
|
||||
@@ -211,6 +211,10 @@
|
||||
<label>Enable threads</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="SecretBackup" type="bool">
|
||||
<label>Enable secret backup</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="Phone3PId" type="bool">
|
||||
<label>Enable add phone numbers as 3PIDs</label>
|
||||
<default>false</default>
|
||||
|
||||
@@ -216,12 +216,12 @@ void NotificationsManager::postNotification(NeoChatRoom *room,
|
||||
}
|
||||
});
|
||||
|
||||
notification->setTitle(room->displayName());
|
||||
|
||||
QString entry;
|
||||
if (room->isDirectChat()) {
|
||||
if (sender == room->displayName()) {
|
||||
notification->setTitle(sender);
|
||||
entry = text.toHtmlEscaped();
|
||||
} else {
|
||||
notification->setTitle(room->displayName());
|
||||
entry = i18n("%1: %2", sender, text.toHtmlEscaped());
|
||||
}
|
||||
|
||||
@@ -253,9 +253,7 @@ void NotificationsManager::postNotification(NeoChatRoom *room,
|
||||
notification->setReplyAction(std::move(replyAction));
|
||||
}
|
||||
|
||||
if (Controller::instance().accounts()->rowCount() > 1) {
|
||||
notification->setHint(u"x-kde-origin-name"_s, room->localMember().id());
|
||||
}
|
||||
notification->setHint(u"x-kde-origin-name"_s, room->localMember().id());
|
||||
notification->sendEvent();
|
||||
}
|
||||
|
||||
@@ -349,9 +347,7 @@ void NotificationsManager::doPostInviteNotification(QPointer<NeoChatRoom> room)
|
||||
m_invitations.remove(room->id());
|
||||
});
|
||||
|
||||
if (Controller::instance().accounts()->rowCount() > 1) {
|
||||
notification->setHint(u"x-kde-origin-name"_s, room->localMember().id());
|
||||
}
|
||||
notification->setHint(u"x-kde-origin-name"_s, room->localMember().id());
|
||||
|
||||
notification->sendEvent();
|
||||
}
|
||||
|
||||
@@ -79,6 +79,7 @@ KirigamiComponents.ConvergentContextMenu {
|
||||
Kirigami.Action {
|
||||
text: i18nc("@action:inmenu", "Open Secret Backup")
|
||||
icon.name: "unlock"
|
||||
visible: NeoChatConfig.secretBackup
|
||||
onTriggered: root.window.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'UnlockSSSSDialog'), {}, {
|
||||
title: i18nc("@title:window", "Open Key Backup")
|
||||
})
|
||||
|
||||
@@ -45,12 +45,14 @@ Labs.MenuBar {
|
||||
}
|
||||
Labs.MenuItem {
|
||||
icon.name: "compass-symbolic"
|
||||
text: i18nc("@action:inmenu Explore public rooms and spaces", "Explore")
|
||||
text: i18nc("@action:inmenu", "Explore Rooms")
|
||||
enabled: root.connection
|
||||
onTriggered: {
|
||||
let dialog = root.appWindow.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ExploreRoomsPage'), {
|
||||
connection: root.connection
|
||||
}, {});
|
||||
}, {
|
||||
title: i18nc("@title", "Explore Rooms")
|
||||
});
|
||||
dialog.roomSelected.connect((roomId, displayName, avatarUrl, alias, topic, memberCount, isJoined) => {
|
||||
RoomManager.resolveResource(roomId.length > 0 ? roomId : alias, isJoined ? "" : "join");
|
||||
});
|
||||
|
||||
@@ -27,17 +27,16 @@ ColumnLayout {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
KirigamiComponents.AvatarButton {
|
||||
KirigamiComponents.Avatar {
|
||||
id: avatar
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.huge
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.huge
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.fillWidth: true
|
||||
|
||||
name: root.invitingMember.displayName
|
||||
source: NeoChatConfig.hideImages ? undefined : root.invitingMember.avatarUrl
|
||||
color: root.invitingMember.color
|
||||
|
||||
onClicked: RoomManager.resolveResource(root.currentRoom.invitingUserId)
|
||||
}
|
||||
|
||||
Loader {
|
||||
@@ -55,12 +54,6 @@ ColumnLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
Kirigami.Heading {
|
||||
text: root.currentRoom.displayName
|
||||
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
Kirigami.SelectableLabel {
|
||||
Layout.fillWidth: true
|
||||
font: Kirigami.Theme.smallFont
|
||||
@@ -68,7 +61,12 @@ ColumnLayout {
|
||||
visible: root.currentRoom && root.currentRoom.canonicalAlias
|
||||
text: root.currentRoom && root.currentRoom.canonicalAlias ? root.currentRoom.canonicalAlias : ""
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
Kirigami.Heading {
|
||||
text: root.currentRoom.displayName
|
||||
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -139,24 +137,8 @@ ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
FormCard.FormButtonDelegate {
|
||||
id: viewProfileDelegate
|
||||
|
||||
icon.name: "user-properties-symbolic"
|
||||
text: i18nc("@action:button View this user's profile", "View %1's Profile", root.invitingMember.displayName)
|
||||
|
||||
onClicked: RoomManager.resolveResource(root.currentRoom.invitingUserId)
|
||||
}
|
||||
|
||||
FormCard.FormDelegateSeparator {
|
||||
above: viewProfileDelegate
|
||||
below: ignoreUserDelegate
|
||||
}
|
||||
|
||||
FormCard.FormButtonDelegate {
|
||||
id: ignoreUserDelegate
|
||||
|
||||
icon.name: "list-remove-symbolic"
|
||||
text: i18nc("@action:button Ignore the user", "Ignore %1 and Reject Invite", root.invitingMember.displayName)
|
||||
text: i18nc("@action:button Block the user", "Block %1", root.invitingMember.displayName)
|
||||
|
||||
onClicked: {
|
||||
root.currentRoom.forget()
|
||||
|
||||
@@ -23,63 +23,72 @@ Kirigami.Page {
|
||||
name: "cancelled"
|
||||
when: root.session.state === KeyVerificationSession.CANCELED
|
||||
PropertyChanges {
|
||||
stateLoader.sourceComponent: verificationCanceled
|
||||
target: stateLoader
|
||||
sourceComponent: verificationCanceled
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "waitingForVerification"
|
||||
when: root.session.state === KeyVerificationSession.WAITINGFORVERIFICATION
|
||||
PropertyChanges {
|
||||
stateLoader.sourceComponent: emojiSas
|
||||
target: stateLoader
|
||||
sourceComponent: emojiSas
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "waitingForReady"
|
||||
when: root.session.state === KeyVerificationSession.WAITINGFORREADY
|
||||
PropertyChanges {
|
||||
stateLoader.sourceComponent: message
|
||||
target: stateLoader
|
||||
sourceComponent: message
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "incoming"
|
||||
when: root.session.state === KeyVerificationSession.INCOMING
|
||||
PropertyChanges {
|
||||
stateLoader.sourceComponent: message
|
||||
target: stateLoader
|
||||
sourceComponent: message
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "waitingForKey"
|
||||
when: root.session.state === KeyVerificationSession.WAITINGFORKEY
|
||||
PropertyChanges {
|
||||
stateLoader.sourceComponent: message
|
||||
target: stateLoader
|
||||
sourceComponent: message
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "waitingForAccept"
|
||||
when: root.session.state === KeyVerificationSession.WAITINGFORACCEPT
|
||||
PropertyChanges {
|
||||
stateLoader.sourceComponent: message
|
||||
target: stateLoader
|
||||
sourceComponent: message
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "waitingForMac"
|
||||
when: root.session.state === KeyVerificationSession.WAITINGFORMAC
|
||||
PropertyChanges {
|
||||
stateLoader.sourceComponent: message
|
||||
target: stateLoader
|
||||
sourceComponent: message
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "ready"
|
||||
when: root.session.state === KeyVerificationSession.READY
|
||||
PropertyChanges {
|
||||
stateLoader.sourceComponent: chooseVerificationComponent
|
||||
target: stateLoader
|
||||
sourceComponent: chooseVerificationComponent
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "done"
|
||||
when: root.session.state === KeyVerificationSession.DONE
|
||||
PropertyChanges {
|
||||
stateLoader.sourceComponent: message
|
||||
target: stateLoader
|
||||
sourceComponent: message
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -23,45 +23,13 @@ Components.AlbumMaximizeComponent {
|
||||
*/
|
||||
required property NeoChatRoom currentRoom
|
||||
|
||||
readonly property string currentEventId: {
|
||||
const idx = (content as ListView).currentIndex;
|
||||
readonly property string currentEventId: model.data(model.index((content as ListView).currentIndex, 0), TimelineMessageModel.EventIdRole)
|
||||
|
||||
if (idx === -1) {
|
||||
return ""
|
||||
}
|
||||
readonly property var currentAuthor: model.data(model.index((content as ListView).currentIndex, 0), TimelineMessageModel.AuthorRole)
|
||||
|
||||
return model.data(model.index(idx, 0), TimelineMessageModel.EventIdRole)
|
||||
}
|
||||
readonly property var currentTime: model.data(model.index((content as ListView).currentIndex, 0), TimelineMessageModel.TimeRole)
|
||||
|
||||
readonly property var currentAuthor: {
|
||||
const idx = (content as ListView).currentIndex;
|
||||
|
||||
if (idx === -1) {
|
||||
return {}
|
||||
}
|
||||
|
||||
return model.data(model.index(idx, 0), TimelineMessageModel.AuthorRole)
|
||||
}
|
||||
|
||||
readonly property var currentTime: {
|
||||
|
||||
const idx = (content as ListView).currentIndex;
|
||||
|
||||
if (idx === -1) {
|
||||
return {}
|
||||
}
|
||||
|
||||
model.data(model.index(idx, 0), TimelineMessageModel.TimeRole)
|
||||
}
|
||||
|
||||
readonly property var currentProgressInfo: {
|
||||
const idx = (content as ListView).currentIndex;
|
||||
|
||||
if (idx === -1) {
|
||||
return {}
|
||||
}
|
||||
model.data(model.index(idx, 0), TimelineMessageModel.ProgressInfoRole)
|
||||
}
|
||||
readonly property var currentProgressInfo: model.data(model.index((content as ListView).currentIndex, 0), TimelineMessageModel.ProgressInfoRole)
|
||||
|
||||
actions: [
|
||||
ShareAction {
|
||||
|
||||
@@ -30,13 +30,15 @@ Kirigami.SearchDialog {
|
||||
emptyText: i18nc("Placeholder message", "No room found")
|
||||
Kirigami.Action {
|
||||
id: exploreRoomAction
|
||||
text: i18nc("@action:button Explore public rooms and spaces", "Explore")
|
||||
text: i18nc("@action:button", "Explore rooms")
|
||||
icon.name: "compass"
|
||||
onTriggered: {
|
||||
root.close()
|
||||
let dialog = root.window.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ExploreRoomsPage'), {
|
||||
connection: root.connection
|
||||
}, {});
|
||||
}, {
|
||||
title: i18nc("@title", "Explore Rooms")
|
||||
});
|
||||
dialog.roomSelected.connect((roomId, displayName, avatarUrl, alias, topic, memberCount, isJoined) => {
|
||||
RoomManager.resolveResource(roomId.length > 0 ? roomId : alias, isJoined ? "" : "join");
|
||||
});
|
||||
|
||||
@@ -227,8 +227,6 @@ Kirigami.Page {
|
||||
// Used to keep track of messages so we can hide the right one at the right time
|
||||
property string messageId
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
showCloseButton: true
|
||||
visible: false
|
||||
position: Kirigami.InlineMessage.Position.Header
|
||||
@@ -255,6 +253,7 @@ Kirigami.Page {
|
||||
id: timelineView
|
||||
messageFilterModel: root.messageFilterModel
|
||||
compactLayout: NeoChatConfig.compactLayout
|
||||
fileDropEnabled: !Controller.isFlatpak
|
||||
markReadCondition: NeoChatConfig.markReadCondition
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@ import org.kde.neochat
|
||||
FormCard.FormCardPage {
|
||||
id: root
|
||||
|
||||
property bool processing: false
|
||||
|
||||
title: i18nc("@title:window", "Load your encrypted messages")
|
||||
|
||||
topPadding: Kirigami.Units.gridUnit
|
||||
@@ -27,42 +25,75 @@ FormCard.FormCardPage {
|
||||
position: Kirigami.InlineMessage.Position.Header
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Controller.activeConnection
|
||||
function onKeyBackupError(): void {
|
||||
securityKeyField.clear()
|
||||
root.processing = false
|
||||
banner.text = i18nc("@info:status", "The security key or backup passphrase was not correct.")
|
||||
banner.visible = true
|
||||
}
|
||||
property SSSSHandler ssssHandler: SSSSHandler {
|
||||
id: ssssHandler
|
||||
|
||||
function onKeyBackupUnlocked(): void {
|
||||
root.processing = false
|
||||
property bool processing: false
|
||||
|
||||
connection: Controller.activeConnection
|
||||
onKeyBackupUnlocked: {
|
||||
ssssHandler.processing = false
|
||||
banner.text = i18nc("@info:status", "Encryption keys restored.")
|
||||
banner.type = Kirigami.MessageType.Positive
|
||||
banner.visible = true
|
||||
}
|
||||
onError: error => {
|
||||
if (error !== SSSSHandler.WrongKeyError) {
|
||||
banner.text = error
|
||||
banner.visible = true
|
||||
return;
|
||||
}
|
||||
passwordField.clear()
|
||||
ssssHandler.processing = false
|
||||
banner.text = i18nc("@info:status", "The security phrase was not correct.")
|
||||
banner.visible = true
|
||||
}
|
||||
}
|
||||
|
||||
FormCard.FormHeader {
|
||||
title: i18nc("@title", "Unlock using Security Key or Backup Passphrase")
|
||||
title: i18nc("@title", "Unlock using Passphrase")
|
||||
}
|
||||
FormCard.FormCard {
|
||||
FormCard.FormTextDelegate {
|
||||
description: i18nc("@info", "If you have a security key or backup passphrase for this account, enter it below or upload it as a file.")
|
||||
description: i18nc("@info", "If you have a backup passphrase for this account, enter it below.")
|
||||
}
|
||||
FormCard.FormTextFieldDelegate {
|
||||
id: passwordField
|
||||
label: i18nc("@label:textbox", "Backup Password:")
|
||||
echoMode: TextInput.Password
|
||||
}
|
||||
FormCard.FormButtonDelegate {
|
||||
id: unlockButton
|
||||
text: i18nc("@action:button", "Unlock")
|
||||
icon.name: "unlock"
|
||||
enabled: passwordField.text.length > 0 && !ssssHandler.processing
|
||||
onClicked: {
|
||||
ssssHandler.processing = true
|
||||
banner.visible = false
|
||||
ssssHandler.unlockSSSSWithPassphrase(passwordField.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FormCard.FormHeader {
|
||||
title: i18nc("@title", "Unlock using Security Key")
|
||||
}
|
||||
FormCard.FormCard {
|
||||
FormCard.FormTextDelegate {
|
||||
description: i18nc("@info", "If you have a security key for this account, enter it below or upload it as a file.")
|
||||
}
|
||||
FormCard.FormTextFieldDelegate {
|
||||
id: securityKeyField
|
||||
label: i18nc("@label:textbox", "Security Key or Backup Passphrase:")
|
||||
label: i18nc("@label:textbox", "Security Key:")
|
||||
echoMode: TextInput.Password
|
||||
}
|
||||
FormCard.FormButtonDelegate {
|
||||
id: uploadSecurityKeyButton
|
||||
text: i18nc("@action:button", "Upload from File")
|
||||
icon.name: "cloud-upload"
|
||||
enabled: !root.processing
|
||||
enabled: !ssssHandler.processing
|
||||
onClicked: {
|
||||
root.processing = true
|
||||
ssssHandler.processing = true
|
||||
openFileDialog.open()
|
||||
}
|
||||
}
|
||||
@@ -70,10 +101,10 @@ FormCard.FormCardPage {
|
||||
id: unlockSecurityKeyButton
|
||||
text: i18nc("@action:button", "Unlock")
|
||||
icon.name: "unlock"
|
||||
enabled: securityKeyField.text.length > 0 && !root.processing
|
||||
enabled: securityKeyField.text.length > 0 && !ssssHandler.processing
|
||||
onClicked: {
|
||||
root.processing = true
|
||||
Controller.activeConnection.unlockSSSS(securityKeyField.text)
|
||||
ssssHandler.processing = true
|
||||
ssssHandler.unlockSSSSFromSecurityKey(securityKeyField.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,10 +120,10 @@ FormCard.FormCardPage {
|
||||
id: unlockCrossSigningButton
|
||||
icon.name: "emblem-shared-symbolic"
|
||||
text: i18nc("@action:button", "Request from other Devices")
|
||||
enabled: !root.processing
|
||||
enabled: !ssssHandler.processing
|
||||
onClicked: {
|
||||
root.processing = true
|
||||
Controller.activeConnection.unlockSSSS("")
|
||||
ssssHandler.processing = true
|
||||
ssssHandler.unlockSSSSFromCrossSigning()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,47 +20,29 @@ Kirigami.Dialog {
|
||||
// Make sure that code is prepared to deal with this property being null
|
||||
property NeoChatRoom room
|
||||
property var user
|
||||
// Used for the "View Main Profile" feature so you can toggle back to the room profile.
|
||||
property NeoChatRoom oldRoom
|
||||
|
||||
property NeoChatConnection connection
|
||||
|
||||
property CommonRoomsModel model: CommonRoomsModel {
|
||||
connection: root.connection
|
||||
userId: root.user.id
|
||||
}
|
||||
|
||||
property LimiterModel limiterModel: LimiterModel {
|
||||
maximumCount: 5
|
||||
sourceModel: root.model
|
||||
}
|
||||
|
||||
readonly property bool isSelf: root.user.id === root.connection.localUserId
|
||||
readonly property bool hasMutualRooms: root.model.count > 0
|
||||
readonly property bool isRoomProfile: root.room
|
||||
readonly property string shareUrl: "https://matrix.to/#/" + root.user.id
|
||||
|
||||
leftPadding: Kirigami.Units.largeSpacing * 2
|
||||
rightPadding: Kirigami.Units.largeSpacing * 2
|
||||
topPadding: Kirigami.Units.largeSpacing * 2
|
||||
bottomPadding: Kirigami.Units.largeSpacing * 2
|
||||
leftPadding: 0
|
||||
rightPadding: 0
|
||||
topPadding: 0
|
||||
bottomPadding: 0
|
||||
|
||||
standardButtons: Kirigami.Dialog.NoButton
|
||||
|
||||
width: Math.min(QQC2.ApplicationWindow.window.width, Kirigami.Units.gridUnit * 24)
|
||||
title: i18nc("@title:menu Account details dialog", "Account Details")
|
||||
|
||||
header: null
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
RowLayout {
|
||||
id: detailRow
|
||||
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: Kirigami.Units.largeSpacing
|
||||
Layout.rightMargin: Kirigami.Units.largeSpacing
|
||||
Layout.topMargin: Kirigami.Units.largeSpacing
|
||||
Layout.bottomMargin: Kirigami.Units.largeSpacing
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
|
||||
KirigamiComponents.Avatar {
|
||||
id: avatar
|
||||
@@ -68,14 +50,7 @@ Kirigami.Dialog {
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.huge
|
||||
|
||||
name: root.room ? root.room.member(root.user.id).displayName : root.user.displayName
|
||||
source: {
|
||||
if (root.room) {
|
||||
return root.room.member(root.user.id).avatarUrl;
|
||||
} else if(root.user.avatarUrl.toString() !== '') {
|
||||
return root.connection.makeMediaUrl(root.user.avatarUrl);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
source: root.room ? root.room.member(root.user.id).avatarUrl : root.user.avatarUrl
|
||||
color: root.room ? root.room.member(root.user.id).color : QmlUtils.getUserColor(root.user.hueF)
|
||||
}
|
||||
|
||||
@@ -100,306 +75,223 @@ Kirigami.Dialog {
|
||||
id: idLabel
|
||||
textFormat: TextEdit.PlainText
|
||||
text: idLabelTextMetrics.elidedText
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
|
||||
TextMetrics {
|
||||
id: idLabelTextMetrics
|
||||
text: root.user.id
|
||||
elide: Qt.ElideRight
|
||||
elideWidth: root.availableWidth - avatar.width - detailRow.spacing * 2 - detailRow.Layout.leftMargin - detailRow.Layout.rightMargin
|
||||
elideWidth: root.availableWidth - avatar.width - qrButton.width - detailRow.spacing * 2 - detailRow.Layout.leftMargin - detailRow.Layout.rightMargin
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.ActionToolBar {
|
||||
QQC2.Label {
|
||||
property CommonRoomsModel model: CommonRoomsModel {
|
||||
connection: root.connection
|
||||
userId: root.user.id
|
||||
}
|
||||
|
||||
text: i18ncp("@info", "One mutual room", "%1 mutual rooms", model.count)
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
visible: model.count > 0
|
||||
|
||||
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
text: i18nc("@action:intoolbar Message this user directly", "Message")
|
||||
icon.name: "document-send-symbolic"
|
||||
|
||||
onTriggered: {
|
||||
root.close();
|
||||
root.connection.requestDirectChat(root.user.id);
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
icon.name: "im-invisible-user-symbolic"
|
||||
text: root.connection.isIgnored(root.user.id) ? i18nc("@action:intoolbar Unignore or 'unblock' this user", "Unignore") : i18nc("@action:intoolbar Ignore or 'block' this user", "Ignore")
|
||||
|
||||
onTriggered: {
|
||||
root.close();
|
||||
root.connection.isIgnored(root.user.id) ? root.connection.removeFromIgnoredUsers(root.user.id) : root.connection.addToIgnoredUsers(root.user.id);
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18nc("@action:intoolbar Copy shareable link for this user", "Copy Link")
|
||||
icon.name: "username-copy-symbolic"
|
||||
|
||||
onTriggered: Clipboard.saveText(root.shareUrl)
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18nc("@action:intoolbar Search for this user's messages.", "Search Messages…")
|
||||
icon.name: "search-symbolic"
|
||||
|
||||
onTriggered: {
|
||||
((root.QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow).pageStack as Kirigami.PageRow).pushDialogLayer(Qt.createComponent('org.kde.neochat', 'RoomSearchPage'), {
|
||||
room: root.room,
|
||||
senderId: root.user.id
|
||||
}, {
|
||||
title: i18nc("@action:title", "Search")
|
||||
});
|
||||
root.close();
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18nc("@action:intoolbar", "Show QR Code")
|
||||
icon.name: "view-barcode-qr-symbolic"
|
||||
|
||||
onTriggered: {
|
||||
let qrCode = Qt.createComponent('org.kde.neochat', 'QrCodeMaximizeComponent').createObject(QQC2.Overlay.overlay, {
|
||||
text: root.shareUrl,
|
||||
title: root.room ? root.room.member(root.user.id).displayName : root.user.displayName,
|
||||
subtitle: root.user.id,
|
||||
avatarColor: root.room?.member(root.user.id).color,
|
||||
avatarSource: root.room? root.room.member(root.user.id).avatarUrl : root.user.avatarUrl
|
||||
}) as QrCodeMaximizeComponent;
|
||||
root.close();
|
||||
qrCode.open();
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18nc("@action:button 'Report' as in 'Report this user to the administrators'", "Report…")
|
||||
icon.name: "dialog-warning-symbolic"
|
||||
visible: root.connection.supportsMatrixSpecVersion("v1.13")
|
||||
|
||||
onTriggered: {
|
||||
let dialog = ((root.QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow).pageStack as Kirigami.PageRow).pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ReasonDialog'), {
|
||||
title: i18nc("@title:dialog", "Report User"),
|
||||
placeholder: i18nc("@info:placeholder", "Reason for reporting this user"),
|
||||
icon: "dialog-warning-symbolic",
|
||||
actionText: i18nc("@action:button 'Report' as in 'Report this user to the administrators'", "Report")
|
||||
}, {
|
||||
title: i18nc("@title", "Report User"),
|
||||
width: Kirigami.Units.gridUnit * 25
|
||||
}) as ReasonDialog;
|
||||
dialog.accepted.connect(reason => {
|
||||
root.connection.reportUser(root.user.id, reason);
|
||||
});
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
visible: root.room
|
||||
|
||||
text: i18nc("@action:button", "View Main Profile")
|
||||
icon.name: "user-properties-symbolic"
|
||||
onTriggered: {
|
||||
root.oldRoom = root.room;
|
||||
root.room = null;
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
visible: !root.room && root.oldRoom
|
||||
|
||||
text: i18nc("@action:button", "View Room Profile")
|
||||
icon.name: "user-properties-symbolic"
|
||||
onTriggered: {
|
||||
root.room = root.oldRoom;
|
||||
root.oldRoom = null;
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
QQC2.AbstractButton {
|
||||
id: qrButton
|
||||
Layout.minimumHeight: avatar.height * 0.75
|
||||
Layout.maximumHeight: avatar.height * 1.5
|
||||
Layout.maximumWidth: avatar.height * 1.5
|
||||
|
||||
Kirigami.Heading {
|
||||
text: i18nc("@title Moderation actions for this user", "Moderation")
|
||||
level: 2
|
||||
visible: root.isRoomProfile && moderationToolbar.actions.filter(function (it) { return it.visible; }).length > 0
|
||||
|
||||
Layout.topMargin: Kirigami.Units.largeSpacing
|
||||
}
|
||||
|
||||
Kirigami.ActionToolBar {
|
||||
id: moderationToolbar
|
||||
|
||||
flat: false
|
||||
visible: root.isRoomProfile
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
visible: !root.isSelf && root.room.canSendState("kick") && root.room.containsUser(root.user.id) && root.room.memberEffectivePowerLevel(root.user.id) < root.room.memberEffectivePowerLevel(root.connection.localUserId)
|
||||
|
||||
text: i18nc("@action:button Kick the user from the room", "Kick…")
|
||||
icon.name: "im-kick-user"
|
||||
onTriggered: {
|
||||
let dialog = (root.QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow).pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ReasonDialog'), {
|
||||
title: i18nc("@title:dialog", "Kick User"),
|
||||
placeholder: i18nc("@info:placeholder", "Reason for kicking this user"),
|
||||
actionText: i18nc("@action:button 'Kick' as in 'Kick this user from the room'", "Kick"),
|
||||
icon: "im-kick-user"
|
||||
}, {
|
||||
title: i18nc("@title:dialog", "Kick User"),
|
||||
width: Kirigami.Units.gridUnit * 25
|
||||
});
|
||||
dialog.accepted.connect(reason => {
|
||||
root.room.kickMember(root.user.id, reason);
|
||||
});
|
||||
root.close();
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
visible: !root.isSelf && root.room.canSendState("ban") && !root.room.isUserBanned(root.user.id) && root.room.memberEffectivePowerLevel(root.user.id) < root.room.memberEffectivePowerLevel(root.connection.localUserId)
|
||||
|
||||
text: i18nc("@action:button Ban this user from the room", "Ban…")
|
||||
icon.name: "im-ban-user"
|
||||
icon.color: Kirigami.Theme.negativeTextColor
|
||||
onTriggered: {
|
||||
let dialog = (root.QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow).pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ReasonDialog'), {
|
||||
title: i18nc("@title:dialog", "Ban User"),
|
||||
placeholder: i18nc("@info:placeholder", "Reason for banning this user"),
|
||||
actionText: i18nc("@action:button 'Ban' as in 'Ban this user'", "Ban"),
|
||||
icon: "im-ban-user"
|
||||
}, {
|
||||
title: i18nc("@title:dialog", "Ban User"),
|
||||
width: Kirigami.Units.gridUnit * 25
|
||||
});
|
||||
dialog.accepted.connect(reason => {
|
||||
root.room.ban(root.user.id, reason);
|
||||
});
|
||||
root.close();
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
visible: !root.isSelf && root.room.canSendState("ban") && root.room.isUserBanned(root.user.id)
|
||||
|
||||
text: i18nc("@action:button Unban the user from this room", "Unban")
|
||||
icon.name: "im-irc"
|
||||
icon.color: Kirigami.Theme.negativeTextColor
|
||||
onTriggered: {
|
||||
root.room.unban(root.user.id);
|
||||
root.close();
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
visible: (root.user.id === root.connection.localUserId || root.room.canSendState("redact"))
|
||||
|
||||
text: i18nc("@action:button Remove messages from the user in this room", "Remove Messages…")
|
||||
icon.name: "delete"
|
||||
icon.color: Kirigami.Theme.negativeTextColor
|
||||
onTriggered: {
|
||||
let dialog = ((root.QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow).pageStack as Kirigami.PageRow).pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ReasonDialog'), {
|
||||
title: i18nc("@title:dialog", "Remove Messages"),
|
||||
placeholder: i18nc("@info:placeholder", "Reason for removing this user's recent messages"),
|
||||
actionText: i18nc("@action:button 'Remove' as in 'Remove these messages'", "Remove"),
|
||||
icon: "delete"
|
||||
}, {
|
||||
title: i18nc("@title", "Remove Messages"),
|
||||
width: Kirigami.Units.gridUnit * 25
|
||||
});
|
||||
dialog.accepted.connect(reason => {
|
||||
root.room.deleteMessagesByUser(root.user.id, reason);
|
||||
});
|
||||
root.close();
|
||||
}
|
||||
contentItem: Barcode {
|
||||
id: barcode
|
||||
barcodeType: Barcode.QRCode
|
||||
content: "https://matrix.to/#/" + root.user.id
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Kirigami.Heading {
|
||||
text: i18nc("@title Role such as 'Admin' or 'Moderator' for this user", "Role")
|
||||
level: 2
|
||||
visible: root.isRoomProfile
|
||||
|
||||
Layout.topMargin: Kirigami.Units.largeSpacing
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
visible: root.isRoomProfile
|
||||
|
||||
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||
|
||||
QQC2.Label {
|
||||
text: root.room ? QmlUtils.nameForPowerLevelValue(root.room.memberEffectivePowerLevel(root.user.id)) : ""
|
||||
}
|
||||
|
||||
QQC2.Button {
|
||||
visible: root.room.canSendState("m.room.power_levels") && !(root.room.roomCreatorHasUltimatePowerLevel() && root.room.isCreator(root.user.id))
|
||||
text: i18nc("@action:button Set the power level (such as 'Admin') for this user", "Set Power Level")
|
||||
icon.name: "document-edit-symbolic"
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.text: text
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
|
||||
onClicked: {
|
||||
(powerLevelDialog.createObject(this, {
|
||||
room: root.room,
|
||||
userId: root.user.id,
|
||||
powerLevel: root.room.memberEffectivePowerLevel(root.user.id)
|
||||
}) as PowerLevelDialog).open();
|
||||
let qrCode = Qt.createComponent('org.kde.neochat', 'QrCodeMaximizeComponent').createObject(QQC2.Overlay.overlay, {
|
||||
text: barcode.content,
|
||||
title: root.room ? root.room.member(root.user.id).displayName : root.user.displayName,
|
||||
subtitle: root.user.id,
|
||||
avatarColor: root.room?.member(root.user.id).color,
|
||||
avatarSource: root.room? root.room.member(root.user.id).avatarUrl : root.user.avatarUrl
|
||||
}) as QrCodeMaximizeComponent;
|
||||
root.close();
|
||||
qrCode.open();
|
||||
}
|
||||
|
||||
Component {
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.text: barcode.content
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.Chip {
|
||||
visible: root.room
|
||||
text: root.room ? QmlUtils.nameForPowerLevelValue(root.room.memberEffectivePowerLevel(root.user.id)) : ""
|
||||
closable: false
|
||||
checkable: false
|
||||
|
||||
Layout.leftMargin: Kirigami.Units.largeSpacing
|
||||
Layout.bottomMargin: Kirigami.Units.largeSpacing
|
||||
}
|
||||
|
||||
Kirigami.Separator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
FormCard.FormButtonDelegate {
|
||||
visible: root.user.id !== root.connection.localUserId && !!root.user
|
||||
text: !!root.user && root.connection.isIgnored(root.user.id) ? i18n("Unignore this user") : i18n("Ignore this user")
|
||||
icon.name: "im-invisible-user"
|
||||
onClicked: {
|
||||
root.close();
|
||||
root.connection.isIgnored(root.user.id) ? root.connection.removeFromIgnoredUsers(root.user.id) : root.connection.addToIgnoredUsers(root.user.id);
|
||||
}
|
||||
}
|
||||
|
||||
FormCard.FormButtonDelegate {
|
||||
visible: root.room && root.user.id !== root.connection.localUserId && root.room.canSendState("kick") && root.room.containsUser(root.user.id) && root.room.memberEffectivePowerLevel(root.user.id) < root.room.memberEffectivePowerLevel(root.connection.localUserId)
|
||||
|
||||
text: i18nc("@action:button", "Kick this user")
|
||||
icon.name: "im-kick-user"
|
||||
onClicked: {
|
||||
let dialog = (root.QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow).pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ReasonDialog'), {
|
||||
title: i18nc("@title:dialog", "Kick User"),
|
||||
placeholder: i18nc("@info:placeholder", "Reason for kicking this user"),
|
||||
actionText: i18nc("@action:button 'Kick' as in 'Kick this user from the room'", "Kick"),
|
||||
icon: "im-kick-user"
|
||||
}, {
|
||||
title: i18nc("@title:dialog", "Kick User"),
|
||||
width: Kirigami.Units.gridUnit * 25
|
||||
});
|
||||
dialog.accepted.connect(reason => {
|
||||
root.room.kickMember(root.user.id, reason);
|
||||
});
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
|
||||
FormCard.FormButtonDelegate {
|
||||
visible: root.room && root.user.id !== root.connection.localUserId && root.room.canSendState("invite") && !root.room.containsUser(root.user.id)
|
||||
|
||||
enabled: root.room && !root.room.isUserBanned(root.user.id)
|
||||
text: i18nc("@action:button", "Invite this user")
|
||||
icon.name: "list-add-user"
|
||||
onClicked: {
|
||||
root.room.inviteToRoom(root.user.id);
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
|
||||
FormCard.FormButtonDelegate {
|
||||
visible: root.room && root.user.id !== root.connection.localUserId && root.room.canSendState("ban") && !root.room.isUserBanned(root.user.id) && root.room.memberEffectivePowerLevel(root.user.id) < root.room.memberEffectivePowerLevel(root.connection.localUserId)
|
||||
|
||||
text: i18nc("@action:button", "Ban this user")
|
||||
icon.name: "im-ban-user"
|
||||
icon.color: Kirigami.Theme.negativeTextColor
|
||||
onClicked: {
|
||||
let dialog = (root.QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow).pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ReasonDialog'), {
|
||||
title: i18nc("@title:dialog", "Ban User"),
|
||||
placeholder: i18nc("@info:placeholder", "Reason for banning this user"),
|
||||
actionText: i18nc("@action:button 'Ban' as in 'Ban this user'", "Ban"),
|
||||
icon: "im-ban-user"
|
||||
}, {
|
||||
title: i18nc("@title:dialog", "Ban User"),
|
||||
width: Kirigami.Units.gridUnit * 25
|
||||
});
|
||||
dialog.accepted.connect(reason => {
|
||||
root.room.ban(root.user.id, reason);
|
||||
});
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
|
||||
FormCard.FormButtonDelegate {
|
||||
visible: root.room && root.user.id !== root.connection.localUserId && root.room.canSendState("ban") && root.room.isUserBanned(root.user.id)
|
||||
|
||||
text: i18nc("@action:button", "Unban this user")
|
||||
icon.name: "im-irc"
|
||||
icon.color: Kirigami.Theme.negativeTextColor
|
||||
onClicked: {
|
||||
root.room.unban(root.user.id);
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
|
||||
FormCard.FormButtonDelegate {
|
||||
visible: root.room && root.room.canSendState("m.room.power_levels")
|
||||
text: i18nc("@action:button", "Set user power level")
|
||||
icon.name: "visibility"
|
||||
onClicked: {
|
||||
(powerLevelDialog.createObject(this, {
|
||||
room: root.room,
|
||||
userId: root.user.id,
|
||||
powerLevel: root.room.memberEffectivePowerLevel(root.user.id)
|
||||
}) as PowerLevelDialog).open();
|
||||
root.close();
|
||||
}
|
||||
|
||||
Component {
|
||||
id: powerLevelDialog
|
||||
PowerLevelDialog {
|
||||
id: powerLevelDialog
|
||||
PowerLevelDialog {
|
||||
id: powerLevelDialog
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.Heading {
|
||||
text: i18nc("@title The set of common rooms between your current user and the one shown", "Mutual Rooms")
|
||||
level: 4
|
||||
visible: !root.isSelf && root.hasMutualRooms
|
||||
FormCard.FormButtonDelegate {
|
||||
visible: root.room && (root.user.id === root.connection.localUserId || root.room.canSendState("redact"))
|
||||
|
||||
Layout.topMargin: Kirigami.Units.largeSpacing
|
||||
text: i18nc("@action:button", "Remove recent messages by this user")
|
||||
icon.name: "delete"
|
||||
icon.color: Kirigami.Theme.negativeTextColor
|
||||
onClicked: {
|
||||
let dialog = ((QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow).pageStack as Kirigami.PageRow).pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ReasonDialog'), {
|
||||
title: i18nc("@title:dialog", "Remove Messages"),
|
||||
placeholder: i18nc("@info:placeholder", "Reason for removing this user's recent messages"),
|
||||
actionText: i18nc("@action:button 'Remove' as in 'Remove these messages'", "Remove"),
|
||||
icon: "delete"
|
||||
}, {
|
||||
title: i18nc("@title", "Remove Messages"),
|
||||
width: Kirigami.Units.gridUnit * 25
|
||||
});
|
||||
dialog.accepted.connect(reason => {
|
||||
root.room.deleteMessagesByUser(root.user.id, reason);
|
||||
});
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
visible: !root.isSelf && root.hasMutualRooms
|
||||
|
||||
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||
|
||||
Repeater {
|
||||
model: root.limiterModel
|
||||
|
||||
delegate: KirigamiComponents.AvatarButton {
|
||||
required property string roomName
|
||||
required property string roomAvatar
|
||||
required property string roomId
|
||||
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.medium
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.medium
|
||||
|
||||
name: roomName
|
||||
source: roomAvatar
|
||||
|
||||
onClicked: {
|
||||
root.close();
|
||||
RoomManager.resolveResource(roomId);
|
||||
}
|
||||
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.text: name
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
}
|
||||
FormCard.FormButtonDelegate {
|
||||
visible: root.user.id !== root.connection.localUserId
|
||||
text: root.connection.directChatExists(root.user) ? i18nc("%1 is the name of the user.", "Chat with %1", root.room ? root.room.member(root.user.id).htmlSafeDisplayName : QmlUtils.escapeString(root.user.displayName)) : i18n("Invite to private chat")
|
||||
icon.name: "document-send"
|
||||
onClicked: {
|
||||
root.connection.requestDirectChat(root.user.id);
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
|
||||
QQC2.Label {
|
||||
text: i18ncp("@info:label And '%1' more rooms you have in common with this user, but are not shown", "and 1 more…", "and %1 more…", root.limiterModel.extraCount)
|
||||
visible: root.limiterModel.extraCount > 0
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
FormCard.FormButtonDelegate {
|
||||
text: i18nc("@action:button %1 is the name of the user.", "Search room for %1's messages", root.room ? root.room.member(root.user.id).htmlSafeDisplayName : QmlUtils.escapeString(root.user.displayName))
|
||||
icon.name: "search-symbolic"
|
||||
onClicked: {
|
||||
((QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow).pageStack as Kirigami.PageRow).pushDialogLayer(Qt.createComponent('org.kde.neochat', 'RoomSearchPage'), {
|
||||
room: root.room,
|
||||
senderId: root.user.id
|
||||
}, {
|
||||
title: i18nc("@action:title", "Search")
|
||||
});
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
|
||||
FormCard.FormButtonDelegate {
|
||||
text: i18n("Copy link")
|
||||
icon.name: "username-copy"
|
||||
onClicked: Clipboard.saveText("https://matrix.to/#/" + root.user.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,45 +554,6 @@ void RoomManager::setCurrentSpace(const QString &spaceId, bool setRoom)
|
||||
setCurrentRoom({});
|
||||
}
|
||||
|
||||
QString RoomManager::findSpaceIdForCurrentRoom() const
|
||||
{
|
||||
if (!m_currentRoom) {
|
||||
return m_currentSpaceId;
|
||||
}
|
||||
if (m_currentRoom->isDirectChat()) {
|
||||
const auto roomsInSpace = SpaceHierarchyCache::instance().getRoomListForSpace(m_currentSpaceId, false);
|
||||
if (roomsInSpace.contains(m_currentRoom->id())) {
|
||||
return m_currentSpaceId;
|
||||
}
|
||||
return "DM"_L1;
|
||||
}
|
||||
const auto &parentSpaces = SpaceHierarchyCache::instance().parentSpaces(m_currentRoom->id());
|
||||
if (parentSpaces.contains(m_currentSpaceId)) {
|
||||
return m_currentSpaceId;
|
||||
}
|
||||
static auto config = NeoChatConfig::self();
|
||||
if (config->allRoomsInHome()) {
|
||||
return {};
|
||||
}
|
||||
if (const auto &parent = m_connection->room(m_currentRoom->canonicalParent())) {
|
||||
for (const auto &parentParent : SpaceHierarchyCache::instance().parentSpaces(parent->id())) {
|
||||
if (SpaceHierarchyCache::instance().parentSpaces(parentParent).isEmpty()) {
|
||||
return parentParent;
|
||||
}
|
||||
}
|
||||
return parent->id();
|
||||
}
|
||||
for (const auto &space : parentSpaces) {
|
||||
if (SpaceHierarchyCache::instance().parentSpaces(space).isEmpty()) {
|
||||
return space;
|
||||
}
|
||||
}
|
||||
if (m_currentRoom->isSpace()) {
|
||||
return m_currentSpaceId;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void RoomManager::setCurrentRoom(const QString &roomId)
|
||||
{
|
||||
if (m_currentRoom != nullptr) {
|
||||
@@ -610,23 +571,57 @@ void RoomManager::setCurrentRoom(const QString &roomId)
|
||||
}
|
||||
|
||||
Q_EMIT currentRoomChanged();
|
||||
|
||||
if (m_connection) {
|
||||
if (roomId.isEmpty()) {
|
||||
m_lastRoomConfig.deleteEntry(m_currentSpaceId);
|
||||
} else {
|
||||
// We can't have empty keys in KConfig, so name it "Home"
|
||||
if (m_currentSpaceId.isEmpty()) {
|
||||
m_lastRoomConfig.writeEntry(u"Home"_s, roomId);
|
||||
} else {
|
||||
m_lastRoomConfig.writeEntry(m_currentSpaceId, roomId);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (roomId.isEmpty()) {
|
||||
m_lastRoomConfig.deleteEntry(m_currentSpaceId);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto spaceIdForRoom = findSpaceIdForCurrentRoom();
|
||||
// We can't have empty keys in KConfig, so name it "Home"
|
||||
if (spaceIdForRoom.isEmpty()) {
|
||||
m_lastRoomConfig.writeEntry(u"Home"_s, roomId);
|
||||
} else {
|
||||
m_lastRoomConfig.writeEntry(spaceIdForRoom, roomId);
|
||||
if (m_currentRoom->isSpace()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_currentSpaceId != spaceIdForRoom) {
|
||||
setCurrentSpace(spaceIdForRoom, false);
|
||||
if (m_currentRoom->isDirectChat()) {
|
||||
const auto roomsInSpace = SpaceHierarchyCache::instance().getRoomListForSpace(m_currentSpaceId, false);
|
||||
if (!roomsInSpace.contains(m_currentRoom->id()) && m_currentSpaceId != "DM"_L1) {
|
||||
setCurrentSpace("DM"_L1, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const auto &parentSpaces = SpaceHierarchyCache::instance().parentSpaces(roomId);
|
||||
if (parentSpaces.contains(m_currentSpaceId)) {
|
||||
return;
|
||||
}
|
||||
static auto config = NeoChatConfig::self();
|
||||
if (config->allRoomsInHome()) {
|
||||
setCurrentSpace({}, false);
|
||||
return;
|
||||
}
|
||||
if (const auto &parent = m_connection->room(m_currentRoom->canonicalParent())) {
|
||||
for (const auto &parentParent : SpaceHierarchyCache::instance().parentSpaces(parent->id())) {
|
||||
if (SpaceHierarchyCache::instance().parentSpaces(parentParent).isEmpty()) {
|
||||
setCurrentSpace(parentParent, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
setCurrentSpace(parent->id(), false);
|
||||
return;
|
||||
}
|
||||
for (const auto &space : parentSpaces) {
|
||||
if (SpaceHierarchyCache::instance().parentSpaces(space).isEmpty()) {
|
||||
setCurrentSpace(space, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
setCurrentSpace({}, false);
|
||||
}
|
||||
|
||||
void RoomManager::clearCurrentRoom()
|
||||
|
||||
@@ -373,15 +373,6 @@ private:
|
||||
|
||||
void setCurrentRoom(const QString &roomId);
|
||||
|
||||
/**
|
||||
* @brief Find the most appropriate space for the currently selected room
|
||||
*
|
||||
* Should be used to figure out what space to switch to after a room change.
|
||||
*
|
||||
* @return The Space ID that the currently set room should be displayed as part of. (or "DM" for DM and "" for Home)
|
||||
*/
|
||||
QString findSpaceIdForCurrentRoom() const;
|
||||
|
||||
// Space ID, "DM", or empty string
|
||||
void setCurrentSpace(const QString &spaceId, bool setRoom = true);
|
||||
|
||||
|
||||
@@ -286,8 +286,6 @@ QQC2.Control {
|
||||
quickFormatBar.selectionStart = selectionStart;
|
||||
quickFormatBar.selectionEnd = selectionEnd;
|
||||
quickFormatBar.open();
|
||||
} else if (quickFormatBar.visible) {
|
||||
quickFormatBar.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -148,7 +148,7 @@ ColumnLayout {
|
||||
id: quickReactions
|
||||
Layout.fillWidth: true
|
||||
|
||||
model: ["👍", "👎", "😄", "🎉", "😕", "❤️", "🚀", "👀"]
|
||||
model: ["👍", "👎", "😄", "🎉", "😕", "❤", "🚀", "👀"]
|
||||
|
||||
delegate: EmojiDelegate {
|
||||
required property string modelData
|
||||
|
||||
@@ -21,6 +21,12 @@ FormCard.FormCard {
|
||||
|
||||
onToggled: NeoChatConfig.threads = checked
|
||||
}
|
||||
FormCard.FormCheckDelegate {
|
||||
text: i18nc("@option:check Enable the matrix 'secret backup' feature", "Secret Backup")
|
||||
checked: NeoChatConfig.secretBackup
|
||||
|
||||
onToggled: NeoChatConfig.secretBackup = checked
|
||||
}
|
||||
FormCard.FormCheckDelegate {
|
||||
text: i18nc("@option:check Enable the matrix feature to add a phone number as a third party ID", "Add phone numbers as 3PIDs")
|
||||
checked: NeoChatConfig.phone3PId
|
||||
|
||||
@@ -33,8 +33,6 @@ target_sources(LibNeoChat PRIVATE
|
||||
events/imagepackevent.cpp
|
||||
events/pollevent.cpp
|
||||
jobs/neochatgetcommonroomsjob.cpp
|
||||
jobs/neochatreportroomjob.cpp
|
||||
jobs/neochatreportuserjob.cpp
|
||||
models/actionsmodel.cpp
|
||||
models/completionmodel.cpp
|
||||
models/completionproxymodel.cpp
|
||||
|
||||
@@ -3,10 +3,6 @@
|
||||
|
||||
#include "chatbarcache.h"
|
||||
|
||||
#include <QMimeData>
|
||||
|
||||
#include <KUrlMimeData>
|
||||
|
||||
#include <Quotient/roommember.h>
|
||||
|
||||
#include "eventhandler.h"
|
||||
@@ -299,17 +295,4 @@ void ChatBarCache::clearCache()
|
||||
clearRelations();
|
||||
}
|
||||
|
||||
void ChatBarCache::drop(QList<QUrl> u, const QString &transferPortal)
|
||||
{
|
||||
QMimeData mimeData;
|
||||
mimeData.setUrls(u);
|
||||
if (!transferPortal.isEmpty()) {
|
||||
mimeData.setData(u"application/vnd.portal.filetransfer"_s, transferPortal.toLatin1());
|
||||
}
|
||||
auto urls = KUrlMimeData::urlsFromMimeData(&mimeData);
|
||||
if (urls.size() > 0) {
|
||||
setAttachmentPath(urls[0].toString());
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_chatbarcache.cpp"
|
||||
|
||||
@@ -198,8 +198,6 @@ public:
|
||||
*/
|
||||
Q_INVOKABLE void postMessage();
|
||||
|
||||
Q_INVOKABLE void drop(QList<QUrl> urls, const QString &transferPortal);
|
||||
|
||||
Q_SIGNALS:
|
||||
void textChanged();
|
||||
void relationIdChanged(const QString &oldEventId, const QString &newEventId);
|
||||
|
||||
@@ -12,10 +12,6 @@ QString PowerLevel::nameForLevel(Level level)
|
||||
return i18n("Moderator");
|
||||
case PowerLevel::Admin:
|
||||
return i18n("Admin");
|
||||
case PowerLevel::Owner:
|
||||
return i18nc("The person that owns a room", "Owner");
|
||||
case PowerLevel::Creator:
|
||||
return i18nc("The person that created a room", "Creator");
|
||||
case PowerLevel::Mute:
|
||||
return i18n("Mute");
|
||||
case PowerLevel::Custom:
|
||||
@@ -34,8 +30,6 @@ int PowerLevel::valueForLevel(Level level)
|
||||
return 50;
|
||||
case PowerLevel::Admin:
|
||||
return 100;
|
||||
case PowerLevel::Owner:
|
||||
return 150;
|
||||
case PowerLevel::Mute:
|
||||
return -1;
|
||||
default:
|
||||
@@ -52,12 +46,8 @@ PowerLevel::Level PowerLevel::levelForValue(int value)
|
||||
return PowerLevel::Moderator;
|
||||
case 100:
|
||||
return PowerLevel::Admin;
|
||||
case 150:
|
||||
return PowerLevel::Owner;
|
||||
case -1:
|
||||
return PowerLevel::Mute;
|
||||
case std::numeric_limits<int>::max():
|
||||
return PowerLevel::Creator;
|
||||
default:
|
||||
return PowerLevel::Custom;
|
||||
}
|
||||
|
||||
@@ -31,12 +31,10 @@ public:
|
||||
enum Level {
|
||||
Member, /**< A basic member. */
|
||||
Moderator, /**< A moderator with enhanced powers. */
|
||||
Admin, /**< Power level 100. */
|
||||
Owner, /**< Power level 150. */
|
||||
Admin, /**< The highest power level in the room. */
|
||||
Mute, /**< The level to remove posting privileges. */
|
||||
NUMLevels,
|
||||
Custom, /**< A non-standard value. Intentionally after NUMLevels so it doesn't appear in the model. */
|
||||
Creator, /**< The user creating the (co-)creating the room. */
|
||||
};
|
||||
Q_ENUM(Level);
|
||||
|
||||
|
||||
@@ -389,9 +389,9 @@ QString EventHandler::getBody(const NeoChatRoom *room, const Quotient::RoomEvent
|
||||
return i18n("left the room");
|
||||
}
|
||||
if (const auto &reason = e.contentJson()["reason"_L1].toString().toHtmlEscaped(); !reason.isEmpty()) {
|
||||
return i18n("has removed %1 from the room: %2", subjectName, reason);
|
||||
return i18n("has put %1 out of the room: %2", subjectName, reason);
|
||||
}
|
||||
return i18n("has removed %1 from the room", subjectName);
|
||||
return i18n("has put %1 out of the room", subjectName);
|
||||
case Membership::Ban:
|
||||
if (e.senderId() != e.userId()) {
|
||||
if (e.reason().isEmpty()) {
|
||||
@@ -697,9 +697,6 @@ QString EventHandler::subtitleText(const NeoChatRoom *room, const Quotient::Room
|
||||
qCWarning(EventHandling) << "subtitleText called with event set to nullptr.";
|
||||
return {};
|
||||
}
|
||||
if (room->isDirectChat()) {
|
||||
return plainBody(room, event, true);
|
||||
}
|
||||
return singleLineAuthorDisplayname(room, event) + (event->isStateEvent() ? u" "_s : u": "_s) + plainBody(room, event, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "neochatreportroomjob.h"
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
NeochatReportRoomJob::NeochatReportRoomJob(const QString &userId, const QString &reason)
|
||||
: BaseJob(HttpVerb::Post, u"ReportRoomJob"_s, makePath(" /_matrix/client/v3/", userId, "/report"))
|
||||
{
|
||||
QJsonObject _dataJson;
|
||||
addParam<IfNotEmpty>(_dataJson, "reason"_L1, reason);
|
||||
setRequestData({_dataJson});
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Quotient/jobs/basejob.h>
|
||||
|
||||
// TODO: Remove once libQuotient updates to Matrix API v1.14
|
||||
class NeochatReportRoomJob : public Quotient::BaseJob
|
||||
{
|
||||
public:
|
||||
explicit NeochatReportRoomJob(const QString &roomId, const QString &reason);
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "neochatreportuserjob.h"
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
NeochatReportUserJob::NeochatReportUserJob(const QString &userId, const QString &reason)
|
||||
: BaseJob(HttpVerb::Post, u"ReportUserJob"_s, makePath("/_matrix/client/v3/users/", userId, "/report"))
|
||||
{
|
||||
QJsonObject _dataJson;
|
||||
addParam<IfNotEmpty>(_dataJson, "reason"_L1, reason);
|
||||
setRequestData({_dataJson});
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Quotient/jobs/basejob.h>
|
||||
|
||||
// TODO: Remove once libQuotient updates to Matrix API v1.14
|
||||
class NeochatReportUserJob : public Quotient::BaseJob
|
||||
{
|
||||
public:
|
||||
explicit NeochatReportUserJob(const QString &userId, const QString &reason);
|
||||
};
|
||||
@@ -59,7 +59,7 @@ QList<ActionsModel::Action> actions{
|
||||
Action{
|
||||
u"shrug"_s,
|
||||
[](const QString &message, NeoChatRoom *, ChatBarCache *) {
|
||||
return u"¯\\\\\\_(ツ)\\_/¯ %1"_s.arg(message);
|
||||
return u"¯\\\\_(ツ)_/¯ %1"_s.arg(message);
|
||||
},
|
||||
Quotient::RoomMessageEvent::MsgType::Text,
|
||||
kli18n("<message>"),
|
||||
|
||||
@@ -118,10 +118,8 @@ void RoomListModel::connectRoomSignals(NeoChatRoom *room)
|
||||
connect(room, &Room::displaynameChanged, this, [this, room] {
|
||||
refresh(room, {DisplayNameRole});
|
||||
});
|
||||
connect(room, &Room::changed, this, [this, room](Room::Changes changes) {
|
||||
if (changes & (Room::Change::UnreadStats | Room::Change::Highlights)) {
|
||||
refresh(room, {ContextNotificationCountRole, HasHighlightNotificationsRole, NotificationCountRole});
|
||||
}
|
||||
connect(room, &Room::unreadStatsChanged, this, [this, room] {
|
||||
refresh(room, {ContextNotificationCountRole, HasHighlightNotificationsRole, NotificationCountRole});
|
||||
});
|
||||
connect(room, &Room::notificationCountChanged, this, [this, room] {
|
||||
refresh(room);
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <QImageReader>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include "jobs/neochatreportuserjob.h"
|
||||
#include "neochatroom.h"
|
||||
#include "spacehierarchycache.h"
|
||||
|
||||
@@ -20,7 +19,6 @@
|
||||
#include <Quotient/csapi/profile.h>
|
||||
#include <Quotient/csapi/registration.h>
|
||||
#include <Quotient/csapi/versions.h>
|
||||
#include <Quotient/e2ee/sssshandler.h>
|
||||
#include <Quotient/jobs/downloadfilejob.h>
|
||||
#include <Quotient/qt_connection_util.h>
|
||||
#include <Quotient/room.h>
|
||||
@@ -77,37 +75,31 @@ void NeoChatConnection::connectSignals()
|
||||
Q_EMIT directChatInvitesChanged();
|
||||
for (const auto &chatId : additions) {
|
||||
if (const auto chat = room(chatId)) {
|
||||
connect(chat, &Room::changed, this, [this](Room::Changes changes) {
|
||||
if (changes & (Room::Change::UnreadStats | Room::Change::Highlights)) {
|
||||
refreshBadgeNotificationCount();
|
||||
Q_EMIT directChatNotificationsChanged();
|
||||
Q_EMIT directChatsHaveHighlightNotificationsChanged();
|
||||
}
|
||||
connect(chat, &Room::unreadStatsChanged, this, [this]() {
|
||||
refreshBadgeNotificationCount();
|
||||
Q_EMIT directChatNotificationsChanged();
|
||||
Q_EMIT directChatsHaveHighlightNotificationsChanged();
|
||||
});
|
||||
}
|
||||
}
|
||||
for (const auto &chatId : removals) {
|
||||
if (const auto chat = room(chatId)) {
|
||||
disconnect(chat, &Room::changed, this, nullptr);
|
||||
disconnect(chat, &Room::unreadStatsChanged, this, nullptr);
|
||||
}
|
||||
}
|
||||
});
|
||||
connect(this, &NeoChatConnection::joinedRoom, this, [this](Room *room) {
|
||||
if (room->isDirectChat()) {
|
||||
connect(room, &Room::changed, this, [this](Room::Changes changes) {
|
||||
if (changes & (Room::Change::UnreadStats | Room::Change::Highlights)) {
|
||||
Q_EMIT directChatNotificationsChanged();
|
||||
Q_EMIT directChatsHaveHighlightNotificationsChanged();
|
||||
}
|
||||
connect(room, &Room::unreadStatsChanged, this, [this]() {
|
||||
Q_EMIT directChatNotificationsChanged();
|
||||
Q_EMIT directChatsHaveHighlightNotificationsChanged();
|
||||
});
|
||||
}
|
||||
Q_EMIT roomInvitesChanged();
|
||||
connect(room, &Room::changed, this, [this](Room::Changes changes) {
|
||||
if (changes & (Room::Change::UnreadStats | Room::Change::Highlights)) {
|
||||
refreshBadgeNotificationCount();
|
||||
Q_EMIT homeNotificationsChanged();
|
||||
Q_EMIT homeHaveHighlightNotificationsChanged();
|
||||
}
|
||||
connect(room, &Room::unreadStatsChanged, this, [this]() {
|
||||
refreshBadgeNotificationCount();
|
||||
Q_EMIT homeNotificationsChanged();
|
||||
Q_EMIT homeHaveHighlightNotificationsChanged();
|
||||
});
|
||||
});
|
||||
connect(this, &NeoChatConnection::leftRoom, this, [this](Room *room, Room *prev) {
|
||||
@@ -142,9 +134,9 @@ void NeoChatConnection::connectSignals()
|
||||
this,
|
||||
[this] {
|
||||
callApi<GetVersionsJob>(BackgroundRequest).onResult([this](const auto &job) {
|
||||
m_canCheckMutualRooms = job->unstableFeatures().value("uk.half-shot.msc2666.query_mutual_rooms"_L1, false);
|
||||
m_canCheckMutualRooms = job->unstableFeatures().contains("uk.half-shot.msc2666.query_mutual_rooms"_L1);
|
||||
Q_EMIT canCheckMutualRoomsChanged();
|
||||
m_canEraseData = job->unstableFeatures().value("org.matrix.msc4025"_L1, false) || job->versions().count("v1.10"_L1);
|
||||
m_canEraseData = job->unstableFeatures().contains("org.matrix.msc4025"_L1) || job->versions().count("v1.10"_L1);
|
||||
Q_EMIT canEraseDataChanged();
|
||||
});
|
||||
},
|
||||
@@ -168,10 +160,6 @@ void NeoChatConnection::refreshBadgeNotificationCount()
|
||||
for (const auto &r : allRooms()) {
|
||||
if (const auto room = static_cast<NeoChatRoom *>(r)) {
|
||||
count += room->contextAwareNotificationCount();
|
||||
|
||||
if (room->joinState() == JoinState::Invite) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -582,41 +570,4 @@ bool NeoChatConnection::isVerifiedSession() const
|
||||
return isVerifiedDevice(userId(), deviceId());
|
||||
}
|
||||
|
||||
void NeoChatConnection::unlockSSSS(const QString &secret)
|
||||
{
|
||||
auto handler = new SSSSHandler();
|
||||
handler->setConnection(this);
|
||||
connect(handler, &SSSSHandler::error, this, [secret, handler, this]() {
|
||||
disconnect(handler, &SSSSHandler::error, this, nullptr);
|
||||
if (!secret.isEmpty()) {
|
||||
connect(handler, &SSSSHandler::error, this, [handler, this]() {
|
||||
Q_EMIT keyBackupError();
|
||||
delete handler;
|
||||
});
|
||||
handler->unlockSSSSWithPassphrase(secret);
|
||||
} else {
|
||||
Q_EMIT keyBackupError();
|
||||
}
|
||||
});
|
||||
connect(handler, &SSSSHandler::keyBackupUnlocked, this, [handler, this]() {
|
||||
Q_EMIT keyBackupUnlocked();
|
||||
connect(handler, &SSSSHandler::finished, handler, &SSSSHandler::deleteLater);
|
||||
});
|
||||
if (secret.isEmpty()) {
|
||||
handler->unlockSSSSFromCrossSigning();
|
||||
} else {
|
||||
handler->unlockSSSSFromSecurityKey(secret);
|
||||
}
|
||||
}
|
||||
|
||||
void NeoChatConnection::reportUser(const QString &userId, const QString &reason)
|
||||
{
|
||||
callApi<NeochatReportUserJob>(userId, reason);
|
||||
}
|
||||
|
||||
bool NeoChatConnection::supportsMatrixSpecVersion(const QString &version)
|
||||
{
|
||||
return supportedMatrixSpecVersions().contains(version);
|
||||
}
|
||||
|
||||
#include "moc_neochatconnection.cpp"
|
||||
|
||||
@@ -222,18 +222,6 @@ public:
|
||||
*/
|
||||
bool isVerifiedSession() const;
|
||||
|
||||
Q_INVOKABLE void unlockSSSS(const QString &secret);
|
||||
|
||||
/**
|
||||
* @brief Report a user.
|
||||
*/
|
||||
Q_INVOKABLE void reportUser(const QString &userId, const QString &reason);
|
||||
|
||||
/**
|
||||
* @return True if this connection supports the given spec version (e.g. "v1.11").
|
||||
*/
|
||||
Q_INVOKABLE bool supportsMatrixSpecVersion(const QString &version);
|
||||
|
||||
Q_SIGNALS:
|
||||
void globalUrlPreviewEnabledChanged();
|
||||
void labelChanged();
|
||||
@@ -271,9 +259,6 @@ Q_SIGNALS:
|
||||
*/
|
||||
void ownSessionVerified();
|
||||
|
||||
void keyBackupUnlocked();
|
||||
void keyBackupError();
|
||||
|
||||
private:
|
||||
static bool m_globalUrlPreviewDefault;
|
||||
static PushRuleAction::Action m_defaultAction;
|
||||
|
||||
@@ -50,12 +50,12 @@
|
||||
#include "roomlastmessageprovider.h"
|
||||
#include "spacehierarchycache.h"
|
||||
#include "urlhelper.h"
|
||||
#include "jobs/neochatreportroomjob.h"
|
||||
|
||||
#ifndef Q_OS_ANDROID
|
||||
#include <KIO/Job>
|
||||
#include <KIO/JobTracker>
|
||||
#endif
|
||||
|
||||
#include <KJobTrackerInterface>
|
||||
#include <KLocalizedString>
|
||||
|
||||
@@ -169,7 +169,6 @@ NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinS
|
||||
const auto neochatconnection = static_cast<NeoChatConnection *>(connection);
|
||||
Q_ASSERT(neochatconnection);
|
||||
connect(neochatconnection, &NeoChatConnection::globalUrlPreviewEnabledChanged, this, &NeoChatRoom::urlPreviewEnabledChanged);
|
||||
connect(this, &Room::fullyReadMarkerMoved, this, &NeoChatRoom::invalidateLastUnreadHighlightId);
|
||||
}
|
||||
|
||||
bool NeoChatRoom::visible() const
|
||||
@@ -347,10 +346,6 @@ void NeoChatRoom::forget()
|
||||
|
||||
void NeoChatRoom::sendTypingNotification(bool isTyping)
|
||||
{
|
||||
// During the chatbar setup sequence, this may get called while we're still initializing
|
||||
if (localMember().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
connection()->callApi<SetTypingJob>(BackgroundRequest, localMember().id(), id(), isTyping, 10000);
|
||||
}
|
||||
|
||||
@@ -1839,57 +1834,4 @@ QString NeoChatRoom::pinnedMessage() const
|
||||
return m_pinnedMessage;
|
||||
}
|
||||
|
||||
void NeoChatRoom::report(const QString &reason)
|
||||
{
|
||||
connection()->callApi<NeochatReportRoomJob>(id(), reason);
|
||||
}
|
||||
|
||||
QString NeoChatRoom::findNextUnreadHighlightId()
|
||||
{
|
||||
const QString startEventId = !m_lastUnreadHighlightId.isEmpty() ? m_lastUnreadHighlightId : lastFullyReadEventId();
|
||||
const auto startIt = findInTimeline(startEventId);
|
||||
if (startIt == historyEdge()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
for (auto it = startIt.base(); it != messageEvents().cend(); ++it) {
|
||||
const RoomEvent *ev = it->event();
|
||||
if (highlights.contains(ev)) {
|
||||
m_lastUnreadHighlightId = ev->id();
|
||||
Q_EMIT highlightCycleStartedChanged();
|
||||
return m_lastUnreadHighlightId;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_lastUnreadHighlightId.isEmpty()) {
|
||||
m_lastUnreadHighlightId.clear();
|
||||
Q_EMIT highlightCycleStartedChanged();
|
||||
return findNextUnreadHighlightId();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool NeoChatRoom::highlightCycleStarted() const
|
||||
{
|
||||
return !m_lastUnreadHighlightId.isEmpty();
|
||||
}
|
||||
|
||||
void NeoChatRoom::invalidateLastUnreadHighlightId(const QString &fromEventId, const QString &toEventId)
|
||||
{
|
||||
Q_UNUSED(fromEventId);
|
||||
|
||||
if (m_lastUnreadHighlightId.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto lastIt = findInTimeline(m_lastUnreadHighlightId);
|
||||
const auto newReadIt = findInTimeline(toEventId);
|
||||
|
||||
// opposite comparision because both are reverse iterators :p
|
||||
if (newReadIt <= lastIt) {
|
||||
m_lastUnreadHighlightId.clear();
|
||||
Q_EMIT highlightCycleStartedChanged();
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_neochatroom.cpp"
|
||||
|
||||
@@ -208,11 +208,6 @@ class NeoChatRoom : public Quotient::Room
|
||||
*/
|
||||
Q_PROPERTY(QString pinnedMessage READ pinnedMessage NOTIFY pinnedMessageChanged)
|
||||
|
||||
/**
|
||||
* @brief Whether the highlight finding cycle has started.
|
||||
*/
|
||||
Q_PROPERTY(bool highlightCycleStarted READ highlightCycleStarted NOTIFY highlightCycleStartedChanged)
|
||||
|
||||
public:
|
||||
explicit NeoChatRoom(Quotient::Connection *connection, QString roomId, Quotient::JoinState joinState = {});
|
||||
|
||||
@@ -620,31 +615,13 @@ public:
|
||||
/**
|
||||
* @brief Whether this user is considered a creator of this room. Only applies to post-v12 rooms.
|
||||
*/
|
||||
Q_INVOKABLE bool isCreator(const QString &userId) const;
|
||||
bool isCreator(const QString &userId) const;
|
||||
|
||||
/**
|
||||
* @return The most recent pinned message in the room.
|
||||
*/
|
||||
QString pinnedMessage() const;
|
||||
|
||||
/**
|
||||
* @brief Send a report about this room.
|
||||
*/
|
||||
Q_INVOKABLE void report(const QString &reason);
|
||||
|
||||
/**
|
||||
* @brief Returns the ID of the next unread highlight in the room.
|
||||
*
|
||||
* Each call advances the internal highlight cursor. Once the last unread highlight
|
||||
* is reached, the cycle is reset.
|
||||
*/
|
||||
Q_INVOKABLE QString findNextUnreadHighlightId();
|
||||
|
||||
/**
|
||||
* @brief Whether the highlight finding cycle has started.
|
||||
*/
|
||||
bool highlightCycleStarted() const;
|
||||
|
||||
private:
|
||||
bool m_visible = false;
|
||||
|
||||
@@ -680,15 +657,11 @@ private:
|
||||
QString m_pinnedMessage;
|
||||
void loadPinnedMessage();
|
||||
|
||||
QString m_lastUnreadHighlightId;
|
||||
|
||||
private Q_SLOTS:
|
||||
void updatePushNotificationState(QString type);
|
||||
|
||||
void cacheLastEvent();
|
||||
|
||||
void invalidateLastUnreadHighlightId(const QString &fromEventId, const QString &toEventId);
|
||||
|
||||
Q_SIGNALS:
|
||||
void cachedInputChanged();
|
||||
void busyChanged();
|
||||
@@ -714,7 +687,6 @@ Q_SIGNALS:
|
||||
void extraEventNotFound(const QString &eventId);
|
||||
void inviteTimestampChanged();
|
||||
void pinnedMessageChanged();
|
||||
void highlightCycleStartedChanged();
|
||||
|
||||
/**
|
||||
* @brief Request a message be shown to the user of the given type.
|
||||
|
||||
@@ -50,7 +50,7 @@ SearchPage {
|
||||
*/
|
||||
signal roomSelected(string roomId, string displayName, url avatarUrl, string alias, string topic, int memberCount, bool isJoined)
|
||||
|
||||
title: i18nc("@action:title Explore public rooms and spaces", "Explore")
|
||||
title: i18nc("@action:title", "Explore Rooms")
|
||||
customPlaceholderText: publicRoomListModel.redirectedText
|
||||
customPlaceholderIcon: "data-warning"
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user