Compare commits

..

No commits in common. "master" and "tdlib17" have entirely different histories.

512 changed files with 7776 additions and 52981 deletions

View file

@ -1,102 +0,0 @@
name: Fernschreiber build
on:
push:
branches:
- master
tags:
- '*'
# to prevent secrets leaking,
# we don't build on PRs
#pull_request:
# branches:
# - master
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: 'true'
- name: Prepare
run: mkdir output
- name: Fetch TDLib
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: "Wunderfitz/td"
file: "tdlib.zip"
target: tdlib/tdlib.zip
token: ${{ secrets.GITHUB_TOKEN }}
- name: Decompress TDLib
uses: TonyBogdanov/zip@1.0
with:
args: unzip -qq ./tdlib/tdlib.zip -d ./tdlib
- name: Set Secrets
uses: DamianReeves/write-file-action@master
with:
path: ./src/tdlibsecrets.h
contents: |
#ifndef TDLIBSECRETS_H
#define TDLIBSECRETS_H
const char TDLIB_API_ID[] = "${{secrets.TDLIB_API_ID}}";
const char TDLIB_API_HASH[] = "${{secrets.TDLIB_API_HASH}}";
#endif // TDLIBSECRETS_H
write-mode: overwrite
- name: Build armv7hl
id: build_armv7hl
uses: coderus/github-sfos-build@master
with:
release: 4.4.0.58
- name: Build i486
id: build_i486
uses: coderus/github-sfos-build@master
with:
release: 4.4.0.58
arch: i486
- name: Build aarch64
id: build_aarch64
uses: coderus/github-sfos-build@master
with:
release: 4.4.0.58
arch: aarch64
- name: Upload build result
uses: actions/upload-artifact@v2
with:
name: rpm-build-result
path: RPMS
- name: Create release
if: contains(github.ref, 'v')
run: |
set -x
assets=()
for asset in RPMS/*.rpm; do
assets+=("-a" "$asset")
done
tag_name="${GITHUB_REF##*/}"
gh release create "$tag_name" "${assets[@]}"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create prerelease
if: contains(github.ref, 'pre')
run: |
set -x
assets=()
for asset in RPMS/*.rpm; do
assets+=("-a" "$asset")
done
tag_name="${GITHUB_REF##*/}"
gh release create "$tag_name" -p -n "This is a pre-release for testing purposes only. It may or may not be unstable." "${assets[@]}"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

3
.gitignore vendored
View file

@ -53,6 +53,3 @@ compile_commands.json
# TDLib API Secrets # TDLib API Secrets
tdlibsecrets.h tdlibsecrets.h
#Convinience scripts
*.sh

View file

@ -1,7 +1,6 @@
# Fernschreiber # Fernschreiber
A Telegram client for Sailfish OS A Telegram client for Sailfish OS
[![Fernschreiber build](https://github.com/Wunderfitz/harbour-fernschreiber/actions/workflows/main.yml/badge.svg)](https://github.com/Wunderfitz/harbour-fernschreiber/actions/workflows/main.yml)
## Authors ## Authors
Sebastian J. Wolf [sebastian@ygriega.de](mailto:sebastian@ygriega.de) and several contributors Sebastian J. Wolf [sebastian@ygriega.de](mailto:sebastian@ygriega.de) and several contributors
@ -11,27 +10,19 @@ Fernschreiber wouldn't be the same without all the people helping in making it b
### Code (Features, Bugfixes, Optimizations etc.) ### Code (Features, Bugfixes, Optimizations etc.)
- Chat list model, chat model, notifications, TDLib receiver, animated stickers, project dependencies, qml/c++ optimizations, chatPhoto, TDLibFile, code reviews, logging categories: [Slava Monich](https://github.com/monich) - Chat list model, chat model, notifications, TDLib receiver, animated stickers, project dependencies, qml/c++ optimizations, chatPhoto, TDLibFile, code reviews, logging categories: [Slava Monich](https://github.com/monich)
- Chat info page, performance improvements to chat page, location support, app initialization/registration with Telegram, project dependencies, emoji handling, qml/js optimizations, multi-message actions, i18n fixes, chat permission handling, code reviews, logging categories, bot support, github build: [jgibbon](https://github.com/jgibbon) - Chat info page, performance improvements to chat page, location support, app initialization/registration with Telegram, project dependencies, emoji handling, qml/js optimizations, multi-message actions, i18n fixes, chat permission handling, code reviews, logging categories: [jgibbon](https://github.com/jgibbon)
- Copy message to clipboard: [Christian Stemmle](https://github.com/chstem) - Copy message to clipboard [Christian Stemmle](https://github.com/chstem)
- Hide send message button if send-by-enter is switched on, focus text input on entering a chat: [santhoshmanikandan](https://github.com/santhoshmanikandan)
- Integration of logout and sesison options to settings page, search results optimization, highlight unread conversations: [Peter G.](https://github.com/nephros)
- Option to always append last message in notifications: [Johannes Bachmann](https://github.com/dscheinah)
- Option to jump to quoted message, widescreen UI adjustments: [Mikhail Barashkov](https://github.com/mbarashkov)
This list might not be complete. In case I forgot something/somebody, please let me know or create a PR, thanks! :)
### Logo/Icon ### Logo/Icon
- Designed by [Matteo](https://github.com/iamnomeutente), adjustments by [Slava Monich](https://github.com/monich) - Designed by [Matteo](https://github.com/iamnomeutente)
### Translations ### Translations
- Chinese: [dashinfantry](https://github.com/dashinfantry) - Chinese: [dashinfantry](https://github.com/dashinfantry)
- Finnish: [jorm1s](https://github.com/jorm1s) - Finnish: [jorm1s](https://github.com/jorm1s)
- French: [Patrick Hervieux](https://github.com/pherjung), [Nicolas Bourdais](https://github.com/nbourdais)
- Hungarian: [edp17](https://github.com/edp17) - Hungarian: [edp17](https://github.com/edp17)
- Italian: [Matteo](https://github.com/iamnomeutente) - Italian: [Matteo](https://github.com/iamnomeutente)
- Polish: [atlochowski](https://github.com/atlochowski) - Polish: [atlochowski](https://github.com/atlochowski)
- Russian: [Rustem Abzalov](https://github.com/arustg) and [Slava Monich](https://github.com/monich) - Russian: [Rustem Abzalov](https://github.com/arustg) and [Slava Monich](https://github.com/monich)
- Slovak: [okruhliak](https://github.com/okruhliak)
- Spanish: [carlosgonz](https://github.com/GNUuser) - Spanish: [carlosgonz](https://github.com/GNUuser)
- Swedish: [Åke Engelbrektson](https://github.com/eson57) - Swedish: [Åke Engelbrektson](https://github.com/eson57)
@ -39,7 +30,6 @@ This list might not be complete. In case I forgot something/somebody, please let
Licensed under GNU GPLv3 Licensed under GNU GPLv3
## Build ## Build
### Local build
Simply clone this repository and ensure to have all [submodules](https://git-scm.com/docs/git-submodule) imported as well (e.g. by using `git submodule update --init`). Then use the project file `harbour-fernschreiber.pro` to import the sources in your SailfishOS IDE. To build and run Fernschreiber or an application which is based on Fernschreiber, you need to create the file `harbour-fernschreiber/src/tdlibsecrets.h` and enter the required constants in the following format: Simply clone this repository and ensure to have all [submodules](https://git-scm.com/docs/git-submodule) imported as well (e.g. by using `git submodule update --init`). Then use the project file `harbour-fernschreiber.pro` to import the sources in your SailfishOS IDE. To build and run Fernschreiber or an application which is based on Fernschreiber, you need to create the file `harbour-fernschreiber/src/tdlibsecrets.h` and enter the required constants in the following format:
``` ```
@ -52,39 +42,15 @@ const char TDLIB_API_HASH[] = "1234567890abcdef1234567890abcdef";
You get the Telegram API ID and hash as soon as you've registered your own application on [https://my.telegram.org](https://my.telegram.org). You get the Telegram API ID and hash as soon as you've registered your own application on [https://my.telegram.org](https://my.telegram.org).
Moreover, you need to have a compiled version of [TDLib 1.8.21](https://github.com/tdlib/td) or higher in the sub-directory `tdlib`. This sub-directory must contain another sub-directory that fits to the target device architecture (e.g. armv7hl, i486). Within this directory, there needs to be a folder called `lib` that contains at least `libtdjson.so`. For armv7hl the relative path would consequently be `tdlib/armv7hl/lib`. Moreover, you need to have a compiled version of [TDLib 1.7](https://github.com/tdlib/td) in the sub-directory `tdlib`. This sub-directory must contain another sub-directory that fits to the target device architecture (e.g. armv7hl, i486). Within this directory, there needs to be a folder called `lib` that contains at least `libtdjson.so`. For armv7hl the relative path would consequently be `tdlib/armv7hl/lib`.
You may just want to download the [tdlib.zip from our fork](https://github.com/Wunderfitz/td/releases) to just use the exact version of the latest official Fernschreiber release. To use it, you need to extract it into your local `tdlib/` folder as described above. If so, you're done and can compile Fernschreiber using the Sailfish SDK. If you want to build TDLib for yourself, please keep on reading.
In case you want to use the same codebase which was used to compile the library that is shipped with Fernschreiber, please [check out the fork](https://github.com/Wunderfitz/td), be sure to use the branch `fernschreiber` and compile these sources using the following commands (be sure to have the Sailfish OS build engine running):
- `alias sfdk=~/SailfishOS/bin/sfdk`
- `sfdk config target=SailfishOS-4.4.0.58-armv7hl` (this compiles the sources on SFOS 4.4 and ARM - the target needs to be adjusted according to the running SDK engine and the platform)
- `mkdir build`
- `cd build`
- `sfdk build-init`
- `sfdk build-shell cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=../tdlib -DTD_ENABLE_LTO=ON ..` (in case of compilation issues, try removing the flag `-DTD_ENABLE_LTO=ON`)
- `sfdk build-shell cmake --build . --target install`
You'll find the compiled library in the directory `td/tdlib`.
### Github Action
Please read the "Local build" section anyway to understand what's going on before continuing. If you want to automatically build your fork on Github, you'll still need to get a Telegram API ID and hash. These are then [added as project secrets](https://docs.github.com/en/actions/reference/encrypted-secrets#creating-encrypted-secrets-for-a-repository) named `TDLIB_API_ID` and `TDLIB_API_HASH`.
By default, only commits to the master branch will be built. You may [change that for your fork](https://docs.github.com/en/actions/quickstart), but please don't create a pull request to the official repository changing the github action without consulting the [Fernschreiber contributors](https://github.com/Wunderfitz/harbour-fernschreiber/issues/162) first.
If you push a tag containing the letter "v" (for example "v0.99.3"), a github release will be created allowing easy download of the resulting rpms. If the tag is named for example "pre-0.99.3", the resulting release is marked as a pre-release for testing purposes.
In case you encounter strange performance issues on startup (several seconds delay, app seems to do nothing), please be sure to [follow the instructions from the respective GitHub issue](https://github.com/tdlib/td/issues/1322), i.e. let TDLib build SQLite with `-DOMIT_MEMLOCK` and be sure to comment the two lines 22558 (`#ifndef OMIT_MEMLOCK`) and 22567 (`#endif`) in the file `sqlite/sqlite/sqlite3.c`.
## Debug ## Debug
Fernschreiber does only output a few TDLib messages by default. To get its own debug log messages, you can either run a debug build to see all of them or use the environment variable `QT_LOGGING_RULES` to specify/filter which messages you'd like to see. Fernschreiber does only output a few TDLib messages by default. To get its own debug log messages, you can either run a debug build to see all of them or use the environment variable `QT_LOGGING_RULES` to specify/filter which messages you'd like to see.
Run `QT_LOGGING_RULES="fernschreiber.*=true" harbour-fernschreiber` to see all messages or replace the `*` with specific logging categories. You'll find the logging category inside the corresponding `.cpp` file for backend usage or you can use `JS` to only see frontend messages. Run `QT_LOGGING_RULES="fernschreiber.*=true" harbour-fernschreiber` to see all messages or replace the `*` with specific logging categories. You'll find the logging category inside the corresponding `.cpp` file for backend usage or you can use `JS` to only see frontend messages.
You can append ` &> fernschreiber.log` to the command to create a text file containing the debug messages.
**Please be aware that debug messages will most likely include personal information** including (but not limited to) chat content and user ids/names of yourself and all your chat partners. Do not share it publicly and, at your discretion, try to remove private info even from the parts you do share with a trusted person.
## Contribute ## Contribute
If you want to contribute bug fixes, improvements, new features etc. please create a pull request (PR). PRs are always welcome and will be reviewed as soon as possible, but may take some time. :) If you want to contribute bug fixes, improvements, new features etc. please create a pull request (PR). PRs are always welcome and will be reviewed as soon as possible, but may take some time. :)
@ -96,6 +62,5 @@ This project uses
- The Telegram Database Library (TDLib) - available on [GitHub.com](https://github.com/tdlib/td). Thanks for making it available under the conditions of the Boost Software License 1.0! Details about the license of TDLib in [its license file](https://github.com/tdlib/td/blob/master/LICENSE_1_0.txt). - The Telegram Database Library (TDLib) - available on [GitHub.com](https://github.com/tdlib/td). Thanks for making it available under the conditions of the Boost Software License 1.0! Details about the license of TDLib in [its license file](https://github.com/tdlib/td/blob/master/LICENSE_1_0.txt).
- Emoji parsing and artwork by [Twitter Emoji (Twemoji)](http://twitter.github.io/twemoji/), copyright 2018 Twitter, Inc and other contributors, Code licensed under the [MIT License](http://opensource.org/licenses/MIT), Graphics licensed under [CC-BY 4.0](https://creativecommons.org/licenses/by/4.0/) - Emoji parsing and artwork by [Twitter Emoji (Twemoji)](http://twitter.github.io/twemoji/), copyright 2018 Twitter, Inc and other contributors, Code licensed under the [MIT License](http://opensource.org/licenses/MIT), Graphics licensed under [CC-BY 4.0](https://creativecommons.org/licenses/by/4.0/)
- Animated sticker parsing and animation by [rlottie](https://github.com/Samsung/rlottie), copyright 2020 Samsung Electronics Co., Ltd. and [other contributors](https://github.com/Samsung/rlottie/blob/master/AUTHORS), Code licensed under the [MIT License](https://github.com/Samsung/rlottie/blob/master/licenses/COPYING.MIT), some rlottie components [licensed under other licenses](https://github.com/Samsung/rlottie/blob/master/COPYING). - Animated sticker parsing and animation by [rlottie](https://github.com/Samsung/rlottie), copyright 2020 Samsung Electronics Co., Ltd. and [other contributors](https://github.com/Samsung/rlottie/blob/master/AUTHORS), Code licensed under the [MIT License](https://github.com/Samsung/rlottie/blob/master/licenses/COPYING.MIT), some rlottie components [licensed under other licenses](https://github.com/Samsung/rlottie/blob/master/COPYING).
- Reverse geocoding for location attachments by [OpenStreetMap Nominatim](https://wiki.openstreetmap.org/wiki/Nominatim).
Thanks to the maintainers of the used components and - again - all contributors to Fernschreiber! Thanks to the maintainers of the used components and - again - all contributors to Fernschreiber!

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -4,8 +4,3 @@ X-Nemo-Application-Type=silica-qt5
Icon=harbour-fernschreiber Icon=harbour-fernschreiber
Exec=harbour-fernschreiber Exec=harbour-fernschreiber
Name=Fernschreiber Name=Fernschreiber
[X-Sailjail]
Permissions=Audio;Documents;Downloads;Internet;Location;MediaIndexing;Microphone;Music;Pictures;PublicDir;RemovableMedia;UserDirs;Videos
OrganizationName=de.ygriega
ApplicationName=fernschreiber

View file

@ -16,13 +16,12 @@ CONFIG += sailfishapp sailfishapp_i18n
PKGCONFIG += nemonotifications-qt5 zlib PKGCONFIG += nemonotifications-qt5 zlib
QT += core dbus sql multimedia positioning QT += core dbus sql
DEFINES += QT_STATICPLUGIN DEFINES += QT_STATICPLUGIN
SOURCES += src/harbour-fernschreiber.cpp \ SOURCES += src/harbour-fernschreiber.cpp \
src/appsettings.cpp \ src/appsettings.cpp \
src/chatpermissionfiltermodel.cpp \
src/chatlistmodel.cpp \ src/chatlistmodel.cpp \
src/chatmodel.cpp \ src/chatmodel.cpp \
src/contactsmodel.cpp \ src/contactsmodel.cpp \
@ -39,89 +38,37 @@ SOURCES += src/harbour-fernschreiber.cpp \
src/tdlibfile.cpp \ src/tdlibfile.cpp \
src/tdlibreceiver.cpp \ src/tdlibreceiver.cpp \
src/tdlibwrapper.cpp \ src/tdlibwrapper.cpp \
src/textfiltermodel.cpp \
src/tgsplugin.cpp src/tgsplugin.cpp
DISTFILES += qml/harbour-fernschreiber.qml \ DISTFILES += qml/harbour-fernschreiber.qml \
qml/components/AudioPreview.qml \ qml/components/AudioPreview.qml \
qml/components/BackgroundImage.qml \ qml/components/BackgroundImage.qml \
qml/components/ChatListViewItem.qml \ qml/components/ChatListViewItem.qml \
qml/components/ContactSync.qml \
qml/components/DocumentPreview.qml \ qml/components/DocumentPreview.qml \
qml/components/GamePreview.qml \
qml/components/ImagePreview.qml \ qml/components/ImagePreview.qml \
qml/components/InformationEditArea.qml \
qml/components/InformationTextItem.qml \
qml/components/InReplyToRow.qml \ qml/components/InReplyToRow.qml \
qml/components/InlineQuery.qml \
qml/components/LocationPreview.qml \ qml/components/LocationPreview.qml \
qml/components/MessageListViewItem.qml \ qml/components/MessageListViewItem.qml \
qml/components/MessageListViewItemSimple.qml \ qml/components/MessageListViewItemSimple.qml \
qml/components/MessageOverlayFlickable.qml \ qml/components/MessageOverlayFlickable.qml \
qml/components/MessageViaLabel.qml \
qml/components/MultilineEmojiLabel.qml \
qml/components/PinnedMessageItem.qml \ qml/components/PinnedMessageItem.qml \
qml/components/PollPreview.qml \ qml/components/PollPreview.qml \
qml/components/PressEffect.qml \ qml/components/PressEffect.qml \
qml/components/ProfilePictureList.qml \
qml/components/ReplyMarkupButtons.qml \
qml/components/StickerPicker.qml \ qml/components/StickerPicker.qml \
qml/components/PhotoTextsListItem.qml \ qml/components/PhotoTextsListItem.qml \
qml/components/StickerSetOverlay.qml \ qml/components/WebPagePreview.qml \
qml/components/TDLibImage.qml \ qml/components/chatInformationPage/ChatInformationEditArea.qml \
qml/components/TDLibMinithumbnail.qml \
qml/components/TDLibPhoto.qml \
qml/components/TDLibThumbnail.qml \
qml/components/VoiceNoteOverlay.qml \
qml/components/chatInformationPage/ChatInformationPageContent.qml \ qml/components/chatInformationPage/ChatInformationPageContent.qml \
qml/components/chatInformationPage/ChatInformationProfilePicture.qml \ qml/components/chatInformationPage/ChatInformationProfilePicture.qml \
qml/components/chatInformationPage/ChatInformationProfilePictureList.qml \
qml/components/chatInformationPage/ChatInformationTabItemBase.qml \ qml/components/chatInformationPage/ChatInformationTabItemBase.qml \
qml/components/chatInformationPage/ChatInformationTabItemDebug.qml \ qml/components/chatInformationPage/ChatInformationTabItemDebug.qml \
qml/components/chatInformationPage/ChatInformationTabItemMembersGroups.qml \ qml/components/chatInformationPage/ChatInformationTabItemMembersGroups.qml \
qml/components/chatInformationPage/ChatInformationTabItemSettings.qml \ qml/components/chatInformationPage/ChatInformationTabItemSettings.qml \
qml/components/chatInformationPage/ChatInformationTabView.qml \ qml/components/chatInformationPage/ChatInformationTabView.qml \
qml/components/chatInformationPage/ChatInformationTextItem.qml \
qml/components/chatInformationPage/EditGroupChatPermissionsColumn.qml \ qml/components/chatInformationPage/EditGroupChatPermissionsColumn.qml \
qml/components/chatInformationPage/EditSuperGroupSlowModeColumn.qml \ qml/components/chatInformationPage/EditSuperGroupSlowModeColumn.qml \
qml/components/inlineQueryResults/InlineQueryResult.qml \
qml/components/inlineQueryResults/InlineQueryResultAnimation.qml \
qml/components/inlineQueryResults/InlineQueryResultArticle.qml \
qml/components/inlineQueryResults/InlineQueryResultAudio.qml \
qml/components/inlineQueryResults/InlineQueryResultContact.qml \
qml/components/inlineQueryResults/InlineQueryResultDefaultBase.qml \
qml/components/inlineQueryResults/InlineQueryResultDocument.qml \
qml/components/inlineQueryResults/InlineQueryResultGame.qml \
qml/components/inlineQueryResults/InlineQueryResultLocation.qml \
qml/components/inlineQueryResults/InlineQueryResultPhoto.qml \
qml/components/inlineQueryResults/InlineQueryResultSticker.qml \
qml/components/inlineQueryResults/InlineQueryResultVenue.qml \
qml/components/inlineQueryResults/InlineQueryResultVideo.qml \
qml/components/inlineQueryResults/InlineQueryResultVoiceNote.qml \
qml/components/messageContent/MessageAnimatedEmoji.qml \
qml/components/messageContent/MessageAnimation.qml \
qml/components/messageContent/MessageAudio.qml \
qml/components/messageContent/MessageContentBase.qml \
qml/components/messageContent/MessageContentFileInfoBase.qml \
qml/components/messageContent/MessageDocument.qml \
qml/components/messageContent/MessageGame.qml \
qml/components/messageContent/MessageLocation.qml \
qml/components/messageContent/MessagePhoto.qml \
qml/components/messageContent/MessagePoll.qml \
qml/components/messageContent/MessageSticker.qml \
qml/components/messageContent/MessageVenue.qml \
qml/components/messageContent/MessageVideoNote.qml \
qml/components/messageContent/MessageVideo.qml \
qml/components/messageContent/MessageVoiceNote.qml \
qml/components/messageContent/SponsoredMessage.qml \
qml/components/messageContent/WebPagePreview.qml \
qml/components/settingsPage/Accordion.qml \
qml/components/settingsPage/AccordionItem.qml \
qml/components/settingsPage/ResponsiveGrid.qml \
qml/components/settingsPage/SettingsAppearance.qml \
qml/components/settingsPage/SettingsBehavior.qml \
qml/components/settingsPage/SettingsPrivacy.qml \
qml/components/settingsPage/SettingsSession.qml \
qml/components/settingsPage/SettingsStorage.qml \
qml/components/settingsPage/SettingsUserProfile.qml \
qml/js/debug.js \ qml/js/debug.js \
qml/js/functions.js \ qml/js/functions.js \
qml/pages/ChatInformationPage.qml \ qml/pages/ChatInformationPage.qml \
@ -135,11 +82,11 @@ DISTFILES += qml/harbour-fernschreiber.qml \
qml/pages/AboutPage.qml \ qml/pages/AboutPage.qml \
qml/pages/PollCreationPage.qml \ qml/pages/PollCreationPage.qml \
qml/pages/PollResultsPage.qml \ qml/pages/PollResultsPage.qml \
qml/pages/SearchChatsPage.qml \
qml/pages/SettingsPage.qml \ qml/pages/SettingsPage.qml \
qml/pages/VideoPage.qml \ qml/pages/VideoPage.qml \
rpm/harbour-fernschreiber.changes \ rpm/harbour-fernschreiber.changes \
rpm/harbour-fernschreiber.spec \ rpm/harbour-fernschreiber.spec \
rpm/harbour-fernschreiber.yaml \
translations/*.ts \ translations/*.ts \
harbour-fernschreiber.desktop harbour-fernschreiber.desktop
@ -148,28 +95,19 @@ SAILFISHAPP_ICONS = 86x86 108x108 128x128 172x172 256x256
TRANSLATIONS += translations/harbour-fernschreiber-de.ts \ TRANSLATIONS += translations/harbour-fernschreiber-de.ts \
translations/harbour-fernschreiber-es.ts \ translations/harbour-fernschreiber-es.ts \
translations/harbour-fernschreiber-fi.ts \ translations/harbour-fernschreiber-fi.ts \
translations/harbour-fernschreiber-fr.ts \
translations/harbour-fernschreiber-hu.ts \ translations/harbour-fernschreiber-hu.ts \
translations/harbour-fernschreiber-it.ts \ translations/harbour-fernschreiber-it.ts \
translations/harbour-fernschreiber-pl.ts \ translations/harbour-fernschreiber-pl.ts \
translations/harbour-fernschreiber-ru.ts \ translations/harbour-fernschreiber-ru.ts \
translations/harbour-fernschreiber-sv.ts \ translations/harbour-fernschreiber-sv.ts \
translations/harbour-fernschreiber-sk.ts \
translations/harbour-fernschreiber-en.ts \ translations/harbour-fernschreiber-en.ts \
translations/harbour-fernschreiber-zh_CN.ts translations/harbour-fernschreiber-zh_CN.ts
equals(QT_ARCH, arm) { contains(QT_ARCH, arm) {
message(Building ARM)
TARGET_ARCHITECTURE = armv7hl TARGET_ARCHITECTURE = armv7hl
} } else {
equals(QT_ARCH, i386) {
message(Building i486)
TARGET_ARCHITECTURE = i486 TARGET_ARCHITECTURE = i486
} }
equals(QT_ARCH, arm64){
message(Building aarch64)
TARGET_ARCHITECTURE = aarch64
}
INCLUDEPATH += $$PWD/tdlib/include INCLUDEPATH += $$PWD/tdlib/include
DEPENDPATH += $$PWD/tdlib/include DEPENDPATH += $$PWD/tdlib/include
@ -211,7 +149,6 @@ INSTALLS += telegram 86.png 108.png 128.png 172.png 256.png \
HEADERS += \ HEADERS += \
src/appsettings.h \ src/appsettings.h \
src/chatpermissionfiltermodel.h \
src/chatlistmodel.h \ src/chatlistmodel.h \
src/chatmodel.h \ src/chatmodel.h \
src/contactsmodel.h \ src/contactsmodel.h \
@ -231,7 +168,6 @@ HEADERS += \
src/tdlibreceiver.h \ src/tdlibreceiver.h \
src/tdlibsecrets.h \ src/tdlibsecrets.h \
src/tdlibwrapper.h \ src/tdlibwrapper.h \
src/textfiltermodel.h \
src/tgsplugin.h src/tgsplugin.h
# https://github.com/Samsung/rlottie.git # https://github.com/Samsung/rlottie.git

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

View file

@ -5,241 +5,60 @@
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="114.667"
height="114.667"
version="1.1" version="1.1"
xml:space="preserve" id="svg19">
width="114.66667" <metadata
height="114.66667" id="metadata23">
viewBox="0 0 114.66667 114.66667" <rdf:RDF>
inkscape:version="0.92.2 5c3e80d, 2017-08-06" <cc:Work
sodipodi:docname="background-black.svg" rdf:about="">
id="svg60"><sodipodi:namedview <dc:format>image/svg+xml</dc:format>
pagecolor="#ffffff" <dc:type
bordercolor="#666666" rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
borderopacity="1" <dc:title></dc:title>
objecttolerance="10" </cc:Work>
gridtolerance="10" </rdf:RDF>
guidetolerance="10" </metadata>
inkscape:pageopacity="0" <defs
inkscape:pageshadow="2" id="defs9">
inkscape:window-width="1920" <linearGradient
inkscape:window-height="1015" id="linearGradient4649">
id="namedview62" <stop
showgrid="false" style="stop-color:#979797;stop-opacity:1"
inkscape:zoom="2.0581394"
inkscape:cx="57.333336"
inkscape:cy="57.333336"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g67" /><metadata
id="metadata64"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs8"><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath18"><path
d="M 0.301,43 C 0.301,42.364 0.3,1.723 0.3,1.723 v 0 C 0.3,0.938 0.938,0.3 1.723,0.3 v 0 H 43 c 23.584,0 42.7,19.117 42.7,42.7 v 0 C 85.7,66.583 66.584,85.7 43,85.7 v 0 C 19.417,85.7 0.301,66.583 0.301,43"
inkscape:connector-curvature="0"
id="path2" /></clipPath><linearGradient
x1="0"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-72.476372,-72.476372,72.476372,-72.476372,73.193359,73.192871)"
spreadMethod="pad"
id="linearGradient30"><stop
style="stop-opacity:1;stop-color:#727272;opacity:1"
offset="0" offset="0"
id="stop5" /><stop id="stop4645" />
style="stop-opacity:1;stop-color:#898989;opacity:1" <stop
offset="0.959184" style="stop-color:#797979;stop-opacity:1"
id="stop7" /><stop
style="stop-opacity:1;stop-color:#898989;opacity:1"
offset="1" offset="1"
id="stop9" /></linearGradient><linearGradient id="stop4647" />
x1="0" </linearGradient>
y1="0" <linearGradient
x2="1" xlink:href="#linearGradient4649"
y2="0" id="linearGradient4651"
gradientUnits="userSpaceOnUse" x1="0.81535178"
gradientTransform="matrix(-72.476372,-72.476372,72.476372,-72.476372,73.193359,73.192871)" y1="0.99882859"
spreadMethod="pad" x2="71.914337"
id="linearGradient30-529"><stop y2="74.307625"
style="stop-opacity:1;stop-color:#727272;opacity:1" gradientUnits="userSpaceOnUse" />
offset="0" </defs>
id="stop74" /><stop <path
style="stop-opacity:1;stop-color:#898989;opacity:1" d="M 0.301,43 0.3,1.723 C 0.3,0.938 0.938,0.3 1.723,0.3 H 43 C 66.584,0.3 85.7,19.417 85.7,43 85.7,66.583 66.584,85.7 43,85.7 19.417,85.7 0.301,66.583 0.301,43"
offset="0.959184" transform="matrix(1.33333,0,0,-1.33333,0,114.667)"
id="stop76" /><stop id="path11"
style="stop-opacity:1;stop-color:#898989;opacity:1" style="fill:url(#linearGradient4651);fill-opacity:1" />
offset="1" <path
id="stop78" /></linearGradient><linearGradient d="m 100,57.117 c 0,-23.408 -19.043,-42.45 -42.45,-42.45 -23.409,0 -42.451,19.042 -42.451,42.45 v 42.45 h 42.45 C 80.957,99.567 100,80.525 100,57.117"
x1="0" id="path13"
y1="0" style="fill:#444444;fill-opacity:1" />
x2="1" <path
y2="0" d="m 81.517,53.646 c -0.0573,2.403947 3.578298,2.403947 3.521,0 0.0573,-2.403947 -3.578298,-2.403947 -3.521,0 m -8.73,0 c 0.09308,2.256331 3.433918,2.256331 3.527,0 0,-2.351999 -3.528,-2.351999 -3.528,0 m -8.723,0 c 0,2.347999 3.522,2.347999 3.522,0 0,-2.347999 -3.522,-2.347999 -3.522,0 m -8.727,0 c -0.101696,2.44622 3.621306,2.447277 3.521,10e-4 -0.09236,-2.252442 -3.427362,-2.253389 -3.521,-10e-4 m -8.728,0 c -0.05733,2.406646 3.58233,2.406646 3.525,0 -0.05466,-2.294686 -3.470338,-2.294686 -3.525,0 m -8.726,0 c 6.67e-4,2.350666 3.526667,2.349666 3.526,-10e-4 0,-2.350666 -3.526,-2.350666 -3.526,0 m -8.726,0 c -0.05801,2.406625 3.581643,2.407658 3.525,10e-4 -0.05466,-2.294686 -3.470338,-2.294686 -3.525,0 m -8.728,0 c 0,2.353332 3.53,2.353332 3.53,0 0,-0.973 -0.79,-1.763 -1.766,-1.763 -0.975,0 -1.764,0.79 -1.764,1.763"
gradientUnits="userSpaceOnUse" id="path15"
gradientTransform="matrix(-72.476372,-72.476372,72.476372,-72.476372,73.193359,73.192871)" style="fill:#000000;fill-opacity:1" />
spreadMethod="pad" <path
id="linearGradient30-529-824"><stop d="m 79.751,79.82 c -0.08052,4.780502 7.131515,4.780502 7.051,0 -0.109325,-4.589371 -6.940675,-4.589371 -7.05,0 m 0,-8.722 c 0.0022,1.946378 1.578625,3.524144 3.525,3.528 4.703331,0 4.703331,-7.055 0,-7.055 -1.946832,0.0022 -3.524347,1.580167 -3.526,3.527 m 0,-8.727 c 0.0017,1.946995 1.579006,3.525244 3.526,3.528 4.703998,0 4.703998,-7.056 0,-7.056 -1.946994,0.0028 -3.524348,1.581005 -3.526,3.528 M 71.025,44.92 c 0.0018,3.140416 3.799089,4.710649 6.018485,2.489364 C 79.262881,45.188079 77.689416,41.39211 74.549,41.393 c -1.946965,0.0011 -3.524552,1.580034 -3.524,3.527 m 0,-8.728 c -0.0013,4.699998 7.048667,4.701998 7.05,0.002 0.0013,-4.699998 -7.048667,-4.701998 -7.05,-0.002 m -8.727,34.906 c 0.0011,1.946833 1.578168,3.525243 3.525,3.528 4.624805,-0.07787 4.624805,-6.977129 0,-7.055 -1.946899,0.0017 -3.524449,1.580101 -3.525,3.527 m 0,-26.178 c 0,1.946804 1.578196,3.525 3.525,3.525 4.701331,0 4.701331,-7.052 0,-7.052 -1.947127,0.0011 -3.525,1.579872 -3.525,3.527 m -8.73,34.9 c -5.53e-4,1.948689 1.579311,3.528553 3.528,3.528 1.94947,0.0017 3.530553,-1.578529 3.53,-3.528 -0.0033,-1.946737 -1.583261,-3.522659 -3.53,-3.521 -1.946186,-0.0011 -3.525241,1.574816 -3.528,3.521 m 0,-8.722 c 0.0028,1.947319 1.580681,3.525246 3.528,3.528 1.9481,-0.0017 3.527244,-1.579902 3.53,-3.528 -0.0022,-1.948165 -1.581834,-3.52645 -3.53,-3.527 -1.947613,0.0011 -3.526345,1.579387 -3.528,3.527 m 0,-26.178 c 0.0017,1.947289 1.58071,3.525001 3.528,3.525 1.947842,5.53e-4 3.527792,-1.577159 3.53,-3.525 -0.109388,-4.594641 -6.948612,-4.594641 -7.058,0 m -8.723,-8.728 c -5.53e-4,1.948528 1.579472,3.528105 3.528,3.527 4.701331,0 4.701331,-7.052 0,-7.052 -1.947518,-5.52e-4 -3.526896,1.577482 -3.528,3.525 M 36.12,79.82 c -0.0017,1.948757 1.578243,3.529106 3.527,3.528 1.948435,0.0011 3.527766,-1.579567 3.525,-3.528 -5.52e-4,-1.945928 -1.579072,-3.522658 -3.525,-3.521 -1.946252,-0.0017 -3.525344,1.574748 -3.527,3.521 m 0,-34.9 c 0.0013,4.701331 7.053333,4.699331 7.052,-0.002 -0.0013,-4.701331 -7.053333,-4.699331 -7.052,0.002 m -8.726,-8.728 c -6.67e-4,4.701331 7.051333,4.702331 7.052,10e-4 6.67e-4,-4.701331 -7.051333,-4.702331 -7.052,-10e-4 M 18.667,79.82 c -0.0022,1.948204 1.576795,3.528554 3.525,3.528 4.699998,0 4.699998,-7.05 0,-7.05 -1.94609,-0.0011 -3.524448,1.57591 -3.525,3.522"
style="stop-opacity:1;stop-color:#8d8d8d;opacity:1" id="path17"
offset="0" style="fill:#000000;fill-opacity:1" />
id="stop290" /><stop </svg>
style="stop-opacity:1;stop-color:#767676;opacity:1"
offset="0.959184"
id="stop292" /><stop
style="stop-opacity:1;stop-color:#767676;opacity:1"
offset="1"
id="stop294" /></linearGradient></defs><g
inkscape:groupmode="layer"
inkscape:label="harbour-fernschreiber"
transform="matrix(1.3333333,0,0,-1.3333333,0,114.66667)"
id="g67"><g
id="g18"><g
clip-path="url(#clipPath18)"
id="g16"><path
d="M 0.301,43 C 0.301,42.364 0.3,1.723 0.3,1.723 v 0 C 0.3,0.938 0.938,0.3 1.723,0.3 v 0 H 43 c 23.584,0 42.7,19.117 42.7,42.7 v 0 C 85.7,66.583 66.584,85.7 43,85.7 v 0 C 19.417,85.7 0.301,66.583 0.301,43"
style="fill:url(#linearGradient30-529-824);stroke:none;opacity:1"
inkscape:connector-curvature="0"
id="path14" /></g></g><g
transform="translate(75,43.1621)"
id="g20" /><path
style="opacity:0.9;fill:#464646;fill-opacity:1;stroke-width:0.9930262"
d="M 42.700457,74.178768 C 24.766404,74.178768 10.2285,60.954638 10.2285,44.643189 V 15.107611 5.2627488 c 5.978017,0 10.823985,4.255117 10.823985,9.6909432 h 21.647972 c 17.934054,0 32.471954,13.377056 32.471954,29.689497 0,16.311449 -14.5379,29.535579 -32.471954,29.535579 z"
id="path10-3"
inkscape:connector-curvature="0" /><g
id="g46"
transform="translate(15.3208,45.7656)"><path
d="m 0,0 c 0,-0.729 0.592,-1.322 1.323,-1.322 0.732,0 1.324,0.593 1.324,1.322 0,0.73 -0.592,1.322 -1.324,1.322 C 0.592,1.322 0,0.73 0,0"
style="fill:#0b0b0b;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
id="path48"
inkscape:connector-curvature="0" /></g><g
id="g50"
transform="translate(21.8672,45.7656)"><path
d="m 0,0 c 0,-0.729 0.591,-1.322 1.321,-1.322 0.732,0 1.323,0.593 1.323,1.322 0,0.73 -0.591,1.322 -1.323,1.322 C 0.591,1.322 0,0.73 0,0"
style="fill:#0b0b0b;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
id="path52"
inkscape:connector-curvature="0" /></g><g
id="g54"
transform="translate(28.4116,45.7656)"><path
d="m 0,0 c 0,-0.729 0.591,-1.322 1.323,-1.322 0.729,0 1.321,0.593 1.321,1.322 0,0.73 -0.592,1.322 -1.321,1.322 C 0.591,1.322 0,0.73 0,0"
style="fill:#0b0b0b;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
id="path56"
inkscape:connector-curvature="0" /></g><g
id="g58"
transform="translate(34.9561,45.7656)"><path
d="m 0,0 c 0,-0.729 0.592,-1.322 1.323,-1.322 0.73,0 1.321,0.593 1.321,1.322 0,0.73 -0.591,1.322 -1.321,1.322 C 0.592,1.322 0,0.73 0,0"
style="fill:#0b0b0b;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
id="path60"
inkscape:connector-curvature="0" /></g><g
id="g62"
transform="translate(41.502,45.7656)"><path
d="m 0,0 c 0,-0.729 0.593,-1.322 1.32,-1.322 0.732,0 1.322,0.593 1.322,1.322 0,0.73 -0.59,1.322 -1.322,1.322 C 0.593,1.322 0,0.73 0,0"
style="fill:#0b0b0b;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
id="path64"
inkscape:connector-curvature="0" /></g><g
id="g66"
transform="translate(48.0469,45.7656)"><path
d="m 0,0 c 0,-0.729 0.59,-1.322 1.32,-1.322 0.732,0 1.322,0.593 1.322,1.322 0,0.73 -0.59,1.322 -1.322,1.322 C 0.59,1.322 0,0.73 0,0"
style="fill:#0b0b0b;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
id="path68"
inkscape:connector-curvature="0" /></g><g
id="g70"
transform="translate(54.5898,45.7656)"><path
d="m 0,0 c 0,-0.729 0.594,-1.322 1.32,-1.322 0.735,0 1.326,0.593 1.326,1.322 0,0.73 -0.591,1.322 -1.326,1.322 C 0.594,1.322 0,0.73 0,0"
style="fill:#0b0b0b;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
id="path72"
inkscape:connector-curvature="0" /></g><g
id="g74"
transform="translate(61.1377,45.7656)"><path
d="m 0,0 c 0,-0.729 0.59,-1.322 1.319,-1.322 0.732,0 1.322,0.593 1.322,1.322 0,0.73 -0.59,1.322 -1.322,1.322 C 0.59,1.322 0,0.73 0,0"
style="fill:#0b0b0b;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
id="path76"
inkscape:connector-curvature="0" /></g><g
id="g78"
transform="translate(14,26.1348)"><path
d="m 0,0 c 0,-1.465 1.184,-2.646 2.644,-2.646 1.461,0 2.645,1.181 2.645,2.646 0,1.459 -1.184,2.641 -2.645,2.641 C 1.184,2.641 0,1.459 0,0"
style="fill:#040404;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
id="path80"
inkscape:connector-curvature="0" /></g><g
id="g82"
transform="translate(20.5444,58.856)"><path
d="m 0,0 c 0,-1.462 1.185,-2.645 2.644,-2.645 1.461,0 2.645,1.183 2.645,2.645 0,1.459 -1.184,2.644 -2.645,2.644 C 1.185,2.644 0,1.459 0,0"
style="fill:#040404;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
id="path84"
inkscape:connector-curvature="0" /></g><g
id="g86"
transform="translate(27.0894,52.3101)"><path
d="m 0,0 c 0,-1.461 1.185,-2.644 2.645,-2.644 1.461,0 2.644,1.183 2.644,2.644 0,1.46 -1.183,2.645 -2.644,2.645 C 1.185,2.645 0,1.46 0,0"
style="fill:#040404;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
id="path88"
inkscape:connector-curvature="0" /></g><g
id="g90"
transform="translate(27.0894,26.1348)"><path
d="m 0,0 c 0,-1.465 1.185,-2.646 2.645,-2.646 1.461,0 2.644,1.181 2.644,2.646 0,1.459 -1.183,2.641 -2.644,2.641 C 1.185,2.641 0,1.459 0,0"
style="fill:#040404;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
id="path92"
inkscape:connector-curvature="0" /></g><g
id="g94"
transform="translate(33.6338,58.856)"><path
d="M 0,0 C 0,-1.462 1.184,-2.645 2.646,-2.645 4.106,-2.645 5.29,-1.462 5.29,0 5.29,1.459 4.106,2.644 2.646,2.644 1.184,2.644 0,1.459 0,0"
style="fill:#040404;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
id="path96"
inkscape:connector-curvature="0" /></g><g
id="g98"
transform="translate(40.1758,52.3101)"><path
d="m 0,0 c 0,-1.461 1.187,-2.644 2.646,-2.644 1.461,0 2.648,1.183 2.648,2.644 0,1.46 -1.187,2.645 -2.648,2.645 C 1.187,2.645 0,1.46 0,0"
style="fill:#040404;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
id="path100"
inkscape:connector-curvature="0" /></g><g
id="g102"
transform="translate(40.1758,32.6768)"><path
d="m 0,0 c 0,-1.458 1.187,-2.646 2.646,-2.646 1.461,0 2.648,1.188 2.648,2.646 0,1.459 -1.187,2.645 -2.648,2.645 C 1.187,2.645 0,1.459 0,0"
style="fill:#040404;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
id="path104"
inkscape:connector-curvature="0" /></g><g
id="g106"
transform="translate(40.1758,26.1348)"><path
d="m 0,0 c 0,-1.465 1.187,-2.646 2.646,-2.646 1.461,0 2.648,1.181 2.648,2.646 0,1.459 -1.187,2.641 -2.648,2.641 C 1.187,2.641 0,1.459 0,0"
style="fill:#040404;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
id="path108"
inkscape:connector-curvature="0" /></g><g
id="g110"
transform="translate(46.7236,52.3101)"><path
d="m 0,0 c 0,-1.461 1.184,-2.644 2.644,-2.644 1.461,0 2.645,1.183 2.645,2.644 0,1.46 -1.184,2.645 -2.645,2.645 C 1.184,2.645 0,1.46 0,0"
style="fill:#040404;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
id="path112"
inkscape:connector-curvature="0" /></g><g
id="g114"
transform="translate(46.7236,32.6768)"><path
d="m 0,0 c 0,-1.458 1.184,-2.646 2.644,-2.646 1.461,0 2.645,1.188 2.645,2.646 0,1.459 -1.184,2.645 -2.645,2.645 C 1.184,2.645 0,1.459 0,0"
style="fill:#040404;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
id="path116"
inkscape:connector-curvature="0" /></g><g
id="g118"
transform="translate(53.2686,58.856)"><path
d="m 0,0 c 0,-1.462 1.183,-2.645 2.643,-2.645 1.461,0 2.645,1.183 2.645,2.645 0,1.459 -1.184,2.644 -2.645,2.644 C 1.183,2.644 0,1.459 0,0"
style="fill:#040404;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
id="path120"
inkscape:connector-curvature="0" /></g><g
id="g122"
transform="translate(53.2686,52.3101)"><path
d="m 0,0 c 0,-1.461 1.183,-2.644 2.643,-2.644 1.461,0 2.645,1.183 2.645,2.644 0,1.46 -1.184,2.645 -2.645,2.645 C 1.183,2.645 0,1.46 0,0"
style="fill:#040404;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
id="path124"
inkscape:connector-curvature="0" /></g><g
id="g126"
transform="translate(59.8135,39.2217)"><path
d="m 0,0 c 0,-1.459 1.187,-2.646 2.644,-2.646 1.461,0 2.644,1.187 2.644,2.646 0,1.459 -1.183,2.646 -2.644,2.646 C 1.187,2.646 0,1.459 0,0"
style="fill:#040404;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
id="path128"
inkscape:connector-curvature="0" /></g><g
id="g130"
transform="translate(59.8135,32.6768)"><path
d="m 0,0 c 0,-1.458 1.187,-2.646 2.644,-2.646 1.461,0 2.644,1.188 2.644,2.646 0,1.459 -1.183,2.645 -2.644,2.645 C 1.187,2.645 0,1.459 0,0"
style="fill:#040404;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
id="path132"
inkscape:connector-curvature="0" /></g></g></svg>

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View file

@ -5,224 +5,60 @@
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" id="svg19"
version="1.1" version="1.1"
xml:space="preserve" height="114.667"
width="114.66667" width="114.667">
height="114.66667" <metadata
viewBox="0 0 114.66667 114.66667" id="metadata23">
inkscape:version="0.92.2 5c3e80d, 2017-08-06" <rdf:RDF>
sodipodi:docname="background-white.svg" <cc:Work
id="svg60"><sodipodi:namedview rdf:about="">
pagecolor="#ffffff" <dc:format>image/svg+xml</dc:format>
bordercolor="#666666" <dc:type
borderopacity="1" rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
objecttolerance="10" <dc:title></dc:title>
gridtolerance="10" </cc:Work>
guidetolerance="10" </rdf:RDF>
inkscape:pageopacity="0" </metadata>
inkscape:pageshadow="2" <defs
inkscape:window-width="1920" id="defs9">
inkscape:window-height="1015" <linearGradient
id="namedview62" id="linearGradient4649">
showgrid="false" <stop
inkscape:zoom="2.0581394" id="stop4645"
inkscape:cx="57.333336"
inkscape:cy="57.333336"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g67" /><metadata
id="metadata64"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs8"><clipPath
id="clipPath18"
clipPathUnits="userSpaceOnUse"><path
id="path2"
inkscape:connector-curvature="0"
d="M 0.301,43 C 0.301,42.364 0.3,1.723 0.3,1.723 v 0 C 0.3,0.938 0.938,0.3 1.723,0.3 v 0 H 43 c 23.584,0 42.7,19.117 42.7,42.7 v 0 C 85.7,66.583 66.584,85.7 43,85.7 v 0 C 19.417,85.7 0.301,66.583 0.301,43" /></clipPath><linearGradient
id="linearGradient30"
spreadMethod="pad"
gradientTransform="matrix(-72.476372,-72.476372,72.476372,-72.476372,73.193359,73.192871)"
gradientUnits="userSpaceOnUse"
y2="0"
x2="1"
y1="0"
x1="0"><stop
id="stop5"
offset="0" offset="0"
style="stop-opacity:1;stop-color:#8d8d8d;opacity:1" /><stop style="stop-color:#686868;stop-opacity:1" />
id="stop7" <stop
offset="0.959184" id="stop4647"
style="stop-opacity:1;stop-color:#767676;opacity:1" /><stop
id="stop9"
offset="1" offset="1"
style="stop-opacity:1;stop-color:#767676;opacity:1" /></linearGradient><linearGradient style="stop-color:#868686;stop-opacity:1" />
id="linearGradient30-529" </linearGradient>
spreadMethod="pad" <linearGradient
gradientTransform="matrix(-72.476372,-72.476372,72.476372,-72.476372,73.193359,73.192871)"
gradientUnits="userSpaceOnUse" gradientUnits="userSpaceOnUse"
y2="0" y2="74.307625"
x2="1" x2="71.914337"
y1="0" y1="0.99882859"
x1="0"><stop x1="0.81535178"
id="stop74" id="linearGradient4651"
offset="0" xlink:href="#linearGradient4649" />
style="stop-opacity:1;stop-color:#8d8d8d;opacity:1" /><stop </defs>
id="stop76" <path
offset="0.959184" style="fill:url(#linearGradient4651);fill-opacity:1"
style="stop-opacity:1;stop-color:#767676;opacity:1" /><stop id="path11"
id="stop78" transform="matrix(1.33333,0,0,-1.33333,0,114.667)"
offset="1" d="M 0.301,43 0.3,1.723 C 0.3,0.938 0.938,0.3 1.723,0.3 H 43 C 66.584,0.3 85.7,19.417 85.7,43 85.7,66.583 66.584,85.7 43,85.7 19.417,85.7 0.301,66.583 0.301,43" />
style="stop-opacity:1;stop-color:#767676;opacity:1" /></linearGradient></defs><g <path
id="g67" style="fill:#bbbbbb;fill-opacity:1"
transform="matrix(1.3333333,0,0,-1.3333333,0,114.66667)" id="path13"
inkscape:label="harbour-fernschreiber" d="m 100,57.117 c 0,-23.408 -19.043,-42.45 -42.45,-42.45 -23.409,0 -42.451,19.042 -42.451,42.45 v 42.45 h 42.45 C 80.957,99.567 100,80.525 100,57.117" />
inkscape:groupmode="layer"><g <path
id="g18"><g style="fill:#f7f7f7;fill-opacity:1"
id="g16" id="path15"
clip-path="url(#clipPath18)"><path d="m 81.517,53.646 c -0.0573,2.403947 3.578298,2.403947 3.521,0 0.0573,-2.403947 -3.578298,-2.403947 -3.521,0 m -8.73,0 c 0.09308,2.256331 3.433918,2.256331 3.527,0 0,-2.351999 -3.528,-2.351999 -3.528,0 m -8.723,0 c 0,2.347999 3.522,2.347999 3.522,0 0,-2.347999 -3.522,-2.347999 -3.522,0 m -8.727,0 c -0.101696,2.44622 3.621306,2.447277 3.521,10e-4 -0.09236,-2.252442 -3.427362,-2.253389 -3.521,-10e-4 m -8.728,0 c -0.05733,2.406646 3.58233,2.406646 3.525,0 -0.05466,-2.294686 -3.470338,-2.294686 -3.525,0 m -8.726,0 c 6.67e-4,2.350666 3.526667,2.349666 3.526,-10e-4 0,-2.350666 -3.526,-2.350666 -3.526,0 m -8.726,0 c -0.05801,2.406625 3.581643,2.407658 3.525,10e-4 -0.05466,-2.294686 -3.470338,-2.294686 -3.525,0 m -8.728,0 c 0,2.353332 3.53,2.353332 3.53,0 0,-0.973 -0.79,-1.763 -1.766,-1.763 -0.975,0 -1.764,0.79 -1.764,1.763" />
id="path14" <path
inkscape:connector-curvature="0" style="fill:#fcfcfc;fill-opacity:1"
style="fill:url(#linearGradient30-529);stroke:none;opacity:1" id="path17"
d="M 0.301,43 C 0.301,42.364 0.3,1.723 0.3,1.723 v 0 C 0.3,0.938 0.938,0.3 1.723,0.3 v 0 H 43 c 23.584,0 42.7,19.117 42.7,42.7 v 0 C 85.7,66.583 66.584,85.7 43,85.7 v 0 C 19.417,85.7 0.301,66.583 0.301,43" /></g></g><g d="m 79.751,79.82 c -0.08052,4.780502 7.131515,4.780502 7.051,0 -0.109325,-4.589371 -6.940675,-4.589371 -7.05,0 m 0,-8.722 c 0.0022,1.946378 1.578625,3.524144 3.525,3.528 4.703331,0 4.703331,-7.055 0,-7.055 -1.946832,0.0022 -3.524347,1.580167 -3.526,3.527 m 0,-8.727 c 0.0017,1.946995 1.579006,3.525244 3.526,3.528 4.703998,0 4.703998,-7.056 0,-7.056 -1.946994,0.0028 -3.524348,1.581005 -3.526,3.528 M 71.025,44.92 c 0.0018,3.140416 3.799089,4.710649 6.018485,2.489364 C 79.262881,45.188079 77.689416,41.39211 74.549,41.393 c -1.946965,0.0011 -3.524552,1.580034 -3.524,3.527 m 0,-8.728 c -0.0013,4.699998 7.048667,4.701998 7.05,0.002 0.0013,-4.699998 -7.048667,-4.701998 -7.05,-0.002 m -8.727,34.906 c 0.0011,1.946833 1.578168,3.525243 3.525,3.528 4.624805,-0.07787 4.624805,-6.977129 0,-7.055 -1.946899,0.0017 -3.524449,1.580101 -3.525,3.527 m 0,-26.178 c 0,1.946804 1.578196,3.525 3.525,3.525 4.701331,0 4.701331,-7.052 0,-7.052 -1.947127,0.0011 -3.525,1.579872 -3.525,3.527 m -8.73,34.9 c -5.53e-4,1.948689 1.579311,3.528553 3.528,3.528 1.94947,0.0017 3.530553,-1.578529 3.53,-3.528 -0.0033,-1.946737 -1.583261,-3.522659 -3.53,-3.521 -1.946186,-0.0011 -3.525241,1.574816 -3.528,3.521 m 0,-8.722 c 0.0028,1.947319 1.580681,3.525246 3.528,3.528 1.9481,-0.0017 3.527244,-1.579902 3.53,-3.528 -0.0022,-1.948165 -1.581834,-3.52645 -3.53,-3.527 -1.947613,0.0011 -3.526345,1.579387 -3.528,3.527 m 0,-26.178 c 0.0017,1.947289 1.58071,3.525001 3.528,3.525 1.947842,5.53e-4 3.527792,-1.577159 3.53,-3.525 -0.109388,-4.594641 -6.948612,-4.594641 -7.058,0 m -8.723,-8.728 c -5.53e-4,1.948528 1.579472,3.528105 3.528,3.527 4.701331,0 4.701331,-7.052 0,-7.052 -1.947518,-5.52e-4 -3.526896,1.577482 -3.528,3.525 M 36.12,79.82 c -0.0017,1.948757 1.578243,3.529106 3.527,3.528 1.948435,0.0011 3.527766,-1.579567 3.525,-3.528 -5.52e-4,-1.945928 -1.579072,-3.522658 -3.525,-3.521 -1.946252,-0.0017 -3.525344,1.574748 -3.527,3.521 m 0,-34.9 c 0.0013,4.701331 7.053333,4.699331 7.052,-0.002 -0.0013,-4.701331 -7.053333,-4.699331 -7.052,0.002 m -8.726,-8.728 c -6.67e-4,4.701331 7.051333,4.702331 7.052,10e-4 6.67e-4,-4.701331 -7.051333,-4.702331 -7.052,-10e-4 M 18.667,79.82 c -0.0022,1.948204 1.576795,3.528554 3.525,3.528 4.699998,0 4.699998,-7.05 0,-7.05 -1.94609,-0.0011 -3.524448,1.57591 -3.525,3.522" />
id="g20" </svg>
transform="translate(75,43.1621)" /><path
inkscape:connector-curvature="0"
id="path10-3"
d="M 42.700457,74.178768 C 24.766404,74.178768 10.2285,60.954638 10.2285,44.643189 V 15.107611 5.2627488 c 5.978017,0 10.823985,4.255117 10.823985,9.6909432 h 21.647972 c 17.934054,0 32.471954,13.377056 32.471954,29.689497 0,16.311449 -14.5379,29.535579 -32.471954,29.535579 z"
style="opacity:0.9;fill:#b9b9b9;fill-opacity:1;stroke-width:0.9930262" /><g
transform="translate(15.3208,45.7656)"
id="g46"><path
inkscape:connector-curvature="0"
id="path48"
style="fill:#f4f4f4;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
d="m 0,0 c 0,-0.729 0.592,-1.322 1.323,-1.322 0.732,0 1.324,0.593 1.324,1.322 0,0.73 -0.592,1.322 -1.324,1.322 C 0.592,1.322 0,0.73 0,0" /></g><g
transform="translate(21.8672,45.7656)"
id="g50"><path
inkscape:connector-curvature="0"
id="path52"
style="fill:#f4f4f4;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
d="m 0,0 c 0,-0.729 0.591,-1.322 1.321,-1.322 0.732,0 1.323,0.593 1.323,1.322 0,0.73 -0.591,1.322 -1.323,1.322 C 0.591,1.322 0,0.73 0,0" /></g><g
transform="translate(28.4116,45.7656)"
id="g54"><path
inkscape:connector-curvature="0"
id="path56"
style="fill:#f4f4f4;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
d="m 0,0 c 0,-0.729 0.591,-1.322 1.323,-1.322 0.729,0 1.321,0.593 1.321,1.322 0,0.73 -0.592,1.322 -1.321,1.322 C 0.591,1.322 0,0.73 0,0" /></g><g
transform="translate(34.9561,45.7656)"
id="g58"><path
inkscape:connector-curvature="0"
id="path60"
style="fill:#f4f4f4;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
d="m 0,0 c 0,-0.729 0.592,-1.322 1.323,-1.322 0.73,0 1.321,0.593 1.321,1.322 0,0.73 -0.591,1.322 -1.321,1.322 C 0.592,1.322 0,0.73 0,0" /></g><g
transform="translate(41.502,45.7656)"
id="g62"><path
inkscape:connector-curvature="0"
id="path64"
style="fill:#f4f4f4;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
d="m 0,0 c 0,-0.729 0.593,-1.322 1.32,-1.322 0.732,0 1.322,0.593 1.322,1.322 0,0.73 -0.59,1.322 -1.322,1.322 C 0.593,1.322 0,0.73 0,0" /></g><g
transform="translate(48.0469,45.7656)"
id="g66"><path
inkscape:connector-curvature="0"
id="path68"
style="fill:#f4f4f4;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
d="m 0,0 c 0,-0.729 0.59,-1.322 1.32,-1.322 0.732,0 1.322,0.593 1.322,1.322 0,0.73 -0.59,1.322 -1.322,1.322 C 0.59,1.322 0,0.73 0,0" /></g><g
transform="translate(54.5898,45.7656)"
id="g70"><path
inkscape:connector-curvature="0"
id="path72"
style="fill:#f4f4f4;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
d="m 0,0 c 0,-0.729 0.594,-1.322 1.32,-1.322 0.735,0 1.326,0.593 1.326,1.322 0,0.73 -0.591,1.322 -1.326,1.322 C 0.594,1.322 0,0.73 0,0" /></g><g
transform="translate(61.1377,45.7656)"
id="g74"><path
inkscape:connector-curvature="0"
id="path76"
style="fill:#f4f4f4;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
d="m 0,0 c 0,-0.729 0.59,-1.322 1.319,-1.322 0.732,0 1.322,0.593 1.322,1.322 0,0.73 -0.59,1.322 -1.322,1.322 C 0.59,1.322 0,0.73 0,0" /></g><g
transform="translate(14,26.1348)"
id="g78"><path
inkscape:connector-curvature="0"
id="path80"
style="fill:#fbfbfb;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
d="m 0,0 c 0,-1.465 1.184,-2.646 2.644,-2.646 1.461,0 2.645,1.181 2.645,2.646 0,1.459 -1.184,2.641 -2.645,2.641 C 1.184,2.641 0,1.459 0,0" /></g><g
transform="translate(20.5444,58.856)"
id="g82"><path
inkscape:connector-curvature="0"
id="path84"
style="fill:#fbfbfb;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
d="m 0,0 c 0,-1.462 1.185,-2.645 2.644,-2.645 1.461,0 2.645,1.183 2.645,2.645 0,1.459 -1.184,2.644 -2.645,2.644 C 1.185,2.644 0,1.459 0,0" /></g><g
transform="translate(27.0894,52.3101)"
id="g86"><path
inkscape:connector-curvature="0"
id="path88"
style="fill:#fbfbfb;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
d="m 0,0 c 0,-1.461 1.185,-2.644 2.645,-2.644 1.461,0 2.644,1.183 2.644,2.644 0,1.46 -1.183,2.645 -2.644,2.645 C 1.185,2.645 0,1.46 0,0" /></g><g
transform="translate(27.0894,26.1348)"
id="g90"><path
inkscape:connector-curvature="0"
id="path92"
style="fill:#fbfbfb;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
d="m 0,0 c 0,-1.465 1.185,-2.646 2.645,-2.646 1.461,0 2.644,1.181 2.644,2.646 0,1.459 -1.183,2.641 -2.644,2.641 C 1.185,2.641 0,1.459 0,0" /></g><g
transform="translate(33.6338,58.856)"
id="g94"><path
inkscape:connector-curvature="0"
id="path96"
style="fill:#fbfbfb;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
d="M 0,0 C 0,-1.462 1.184,-2.645 2.646,-2.645 4.106,-2.645 5.29,-1.462 5.29,0 5.29,1.459 4.106,2.644 2.646,2.644 1.184,2.644 0,1.459 0,0" /></g><g
transform="translate(40.1758,52.3101)"
id="g98"><path
inkscape:connector-curvature="0"
id="path100"
style="fill:#fbfbfb;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
d="m 0,0 c 0,-1.461 1.187,-2.644 2.646,-2.644 1.461,0 2.648,1.183 2.648,2.644 0,1.46 -1.187,2.645 -2.648,2.645 C 1.187,2.645 0,1.46 0,0" /></g><g
transform="translate(40.1758,32.6768)"
id="g102"><path
inkscape:connector-curvature="0"
id="path104"
style="fill:#fbfbfb;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
d="m 0,0 c 0,-1.458 1.187,-2.646 2.646,-2.646 1.461,0 2.648,1.188 2.648,2.646 0,1.459 -1.187,2.645 -2.648,2.645 C 1.187,2.645 0,1.459 0,0" /></g><g
transform="translate(40.1758,26.1348)"
id="g106"><path
inkscape:connector-curvature="0"
id="path108"
style="fill:#fbfbfb;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
d="m 0,0 c 0,-1.465 1.187,-2.646 2.646,-2.646 1.461,0 2.648,1.181 2.648,2.646 0,1.459 -1.187,2.641 -2.648,2.641 C 1.187,2.641 0,1.459 0,0" /></g><g
transform="translate(46.7236,52.3101)"
id="g110"><path
inkscape:connector-curvature="0"
id="path112"
style="fill:#fbfbfb;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
d="m 0,0 c 0,-1.461 1.184,-2.644 2.644,-2.644 1.461,0 2.645,1.183 2.645,2.644 0,1.46 -1.184,2.645 -2.645,2.645 C 1.184,2.645 0,1.46 0,0" /></g><g
transform="translate(46.7236,32.6768)"
id="g114"><path
inkscape:connector-curvature="0"
id="path116"
style="fill:#fbfbfb;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
d="m 0,0 c 0,-1.458 1.184,-2.646 2.644,-2.646 1.461,0 2.645,1.188 2.645,2.646 0,1.459 -1.184,2.645 -2.645,2.645 C 1.184,2.645 0,1.459 0,0" /></g><g
transform="translate(53.2686,58.856)"
id="g118"><path
inkscape:connector-curvature="0"
id="path120"
style="fill:#fbfbfb;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
d="m 0,0 c 0,-1.462 1.183,-2.645 2.643,-2.645 1.461,0 2.645,1.183 2.645,2.645 0,1.459 -1.184,2.644 -2.645,2.644 C 1.183,2.644 0,1.459 0,0" /></g><g
transform="translate(53.2686,52.3101)"
id="g122"><path
inkscape:connector-curvature="0"
id="path124"
style="fill:#fbfbfb;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
d="m 0,0 c 0,-1.461 1.183,-2.644 2.643,-2.644 1.461,0 2.645,1.183 2.645,2.644 0,1.46 -1.184,2.645 -2.645,2.645 C 1.183,2.645 0,1.46 0,0" /></g><g
transform="translate(59.8135,39.2217)"
id="g126"><path
inkscape:connector-curvature="0"
id="path128"
style="fill:#fbfbfb;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
d="m 0,0 c 0,-1.459 1.187,-2.646 2.644,-2.646 1.461,0 2.644,1.187 2.644,2.646 0,1.459 -1.183,2.646 -2.644,2.646 C 1.187,2.646 0,1.459 0,0" /></g><g
transform="translate(59.8135,32.6768)"
id="g130"><path
inkscape:connector-curvature="0"
id="path132"
style="fill:#fbfbfb;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1"
d="m 0,0 c 0,-1.458 1.187,-2.646 2.644,-2.646 1.461,0 2.644,1.188 2.644,2.646 0,1.459 -1.183,2.645 -2.644,2.645 C 1.187,2.645 0,1.459 0,0" /></g></g></svg>

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 6 KiB

View file

@ -1,204 +1,66 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg <svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" id="svg19"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1" version="1.1"
xml:space="preserve" height="114.667"
width="114.66667" width="114.667">
height="114.66667" <metadata
viewBox="0 0 114.66667 114.66667" id="metadata23">
inkscape:version="0.92.4 (unknown)" <rdf:RDF>
sodipodi:docname="harbour-fernschreiber-3.svg"> <cc:Work
<defs> rdf:about="">
<clipPath <dc:format>image/svg+xml</dc:format>
clipPathUnits="userSpaceOnUse" <dc:type
id="clipPath18"> rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<path <dc:title></dc:title>
d="M 0.301,43 C 0.301,42.364 0.3,1.723 0.3,1.723 v 0 C 0.3,0.938 0.938,0.3 1.723,0.3 v 0 H 43 c 23.584,0 42.7,19.117 42.7,42.7 v 0 C 85.7,66.583 66.584,85.7 43,85.7 v 0 C 19.417,85.7 0.301,66.583 0.301,43" </cc:Work>
inkscape:connector-curvature="0" </rdf:RDF>
id="path2" /> </metadata>
</clipPath> <defs
id="defs9">
<linearGradient <linearGradient
x1="0" id="a"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-72.476372,-72.476372,72.476372,-72.476372,73.193359,73.192871)"
spreadMethod="pad" spreadMethod="pad"
id="linearGradient30"> gradientTransform="rotate(-135 51.755 21.438) scale(102.49707)"
gradientUnits="userSpaceOnUse"
y2="0"
x2="1"
y1="0"
x1="0">
<stop <stop
style="stop-opacity:1;stop-color:#ec7221" id="stop2"
offset="0" stop-color="#ec7221"
id="stop5" /> offset="0" />
<stop <stop
style="stop-opacity:1;stop-color:#e7454c" id="stop4"
offset="0.959184" stop-color="#e7454c"
id="stop7" /> offset=".959" />
<stop <stop
style="stop-opacity:1;stop-color:#e7454c" id="stop6"
offset="1" stop-color="#e7454c"
id="stop9" /> offset="1" />
</linearGradient> </linearGradient>
</defs> </defs>
<g
inkscape:groupmode="layer"
inkscape:label="harbour-fernschreiber"
transform="matrix(1.3333333,0,0,-1.3333333,0,114.66667)"
id="g67">
<g
id="g18">
<g
clip-path="url(#clipPath18)"
id="g16">
<path <path
d="M 0.301,43 C 0.301,42.364 0.3,1.723 0.3,1.723 v 0 C 0.3,0.938 0.938,0.3 1.723,0.3 v 0 H 43 c 23.584,0 42.7,19.117 42.7,42.7 v 0 C 85.7,66.583 66.584,85.7 43,85.7 v 0 C 19.417,85.7 0.301,66.583 0.301,43" id="path11"
style="fill:url(#linearGradient30);stroke:none" transform="matrix(1.33333 0 0 -1.33333 0 114.667)"
inkscape:connector-curvature="0" fill="url(#a)"
id="path14" /> d="M.301 43L.3 1.723C.3.938.938.3 1.723.3H43C66.584.3 85.7 19.417 85.7 43c0 23.583-19.116 42.7-42.7 42.7C19.417 85.7.301 66.583.301 43" />
</g>
</g>
<g
transform="translate(75,43.1621)"
id="g20" />
<path <path
style="opacity:0.9;fill:#fcba02;fill-opacity:1;stroke-width:0.9930262" id="path13"
d="M 42.700457,74.178768 C 24.766404,74.178768 10.2285,60.954638 10.2285,44.643189 V 15.107611 5.2627488 c 5.978017,0 10.823985,4.255117 10.823985,9.6909432 h 21.647972 c 17.934054,0 32.471954,13.377056 32.471954,29.689497 0,16.311449 -14.5379,29.535579 -32.471954,29.535579 z" fill="#fcba02"
id="path10-3" d="M100 57.117c0-23.408-19.043-42.45-42.45-42.45-23.409 0-42.451 19.042-42.451 42.45v42.45h42.45c23.408 0 42.451-19.042 42.451-42.45" />
inkscape:connector-curvature="0" /><g <path
id="g46" style="fill:#fffda9"
transform="translate(15.3208,45.7656)"><path id="path15"
d="m 0,0 c 0,-0.729 0.592,-1.322 1.323,-1.322 0.732,0 1.324,0.593 1.324,1.322 0,0.73 -0.592,1.322 -1.324,1.322 C 0.592,1.322 0,0.73 0,0" d="m 81.517,53.646 c -0.0573,2.403947 3.578298,2.403947 3.521,0 0.0573,-2.403947 -3.578298,-2.403947 -3.521,0 m -8.73,0 c 0.09308,2.256331 3.433918,2.256331 3.527,0 0,-2.351999 -3.528,-2.351999 -3.528,0 m -8.723,0 c 0,2.347999 3.522,2.347999 3.522,0 0,-2.347999 -3.522,-2.347999 -3.522,0 m -8.727,0 c -0.101696,2.44622 3.621306,2.447277 3.521,10e-4 -0.09236,-2.252442 -3.427362,-2.253389 -3.521,-10e-4 m -8.728,0 c -0.05733,2.406646 3.58233,2.406646 3.525,0 -0.05466,-2.294686 -3.470338,-2.294686 -3.525,0 m -8.726,0 c 6.67e-4,2.350666 3.526667,2.349666 3.526,-10e-4 0,-2.350666 -3.526,-2.350666 -3.526,0 m -8.726,0 c -0.05801,2.406625 3.581643,2.407658 3.525,10e-4 -0.05466,-2.294686 -3.470338,-2.294686 -3.525,0 m -8.728,0 c 0,2.353332 3.53,2.353332 3.53,0 0,-0.973 -0.79,-1.763 -1.766,-1.763 -0.975,0 -1.764,0.79 -1.764,1.763" />
style="fill:#fffda9;fill-opacity:1;fill-rule:nonzero;stroke:none" <path
id="path48" style="fill:#fffee3"
inkscape:connector-curvature="0" /></g><g id="path17"
id="g50" d="m 79.751,79.82 c -0.08052,4.780502 7.131515,4.780502 7.051,0 -0.109325,-4.589371 -6.940675,-4.589371 -7.05,0 m 0,-8.722 c 0.0022,1.946378 1.578625,3.524144 3.525,3.528 4.703331,0 4.703331,-7.055 0,-7.055 -1.946832,0.0022 -3.524347,1.580167 -3.526,3.527 m 0,-8.727 c 0.0017,1.946995 1.579006,3.525244 3.526,3.528 4.703998,0 4.703998,-7.056 0,-7.056 -1.946994,0.0028 -3.524348,1.581005 -3.526,3.528 M 71.025,44.92 c 0.0018,3.140416 3.799089,4.710649 6.018485,2.489364 C 79.262881,45.188079 77.689416,41.39211 74.549,41.393 c -1.946965,0.0011 -3.524552,1.580034 -3.524,3.527 m 0,-8.728 c -0.0013,4.699998 7.048667,4.701998 7.05,0.002 0.0013,-4.699998 -7.048667,-4.701998 -7.05,-0.002 m -8.727,34.906 c 0.0011,1.946833 1.578168,3.525243 3.525,3.528 4.624805,-0.07787 4.624805,-6.977129 0,-7.055 -1.946899,0.0017 -3.524449,1.580101 -3.525,3.527 m 0,-26.178 c 0,1.946804 1.578196,3.525 3.525,3.525 4.701331,0 4.701331,-7.052 0,-7.052 -1.947127,0.0011 -3.525,1.579872 -3.525,3.527 m -8.73,34.9 c -5.53e-4,1.948689 1.579311,3.528553 3.528,3.528 1.94947,0.0017 3.530553,-1.578529 3.53,-3.528 -0.0033,-1.946737 -1.583261,-3.522659 -3.53,-3.521 -1.946186,-0.0011 -3.525241,1.574816 -3.528,3.521 m 0,-8.722 c 0.0028,1.947319 1.580681,3.525246 3.528,3.528 1.9481,-0.0017 3.527244,-1.579902 3.53,-3.528 -0.0022,-1.948165 -1.581834,-3.52645 -3.53,-3.527 -1.947613,0.0011 -3.526345,1.579387 -3.528,3.527 m 0,-26.178 c 0.0017,1.947289 1.58071,3.525001 3.528,3.525 1.947842,5.53e-4 3.527792,-1.577159 3.53,-3.525 -0.109388,-4.594641 -6.948612,-4.594641 -7.058,0 m -8.723,-8.728 c -5.53e-4,1.948528 1.579472,3.528105 3.528,3.527 4.701331,0 4.701331,-7.052 0,-7.052 -1.947518,-5.52e-4 -3.526896,1.577482 -3.528,3.525 M 36.12,79.82 c -0.0017,1.948757 1.578243,3.529106 3.527,3.528 1.948435,0.0011 3.527766,-1.579567 3.525,-3.528 -5.52e-4,-1.945928 -1.579072,-3.522658 -3.525,-3.521 -1.946252,-0.0017 -3.525344,1.574748 -3.527,3.521 m 0,-34.9 c 0.0013,4.701331 7.053333,4.699331 7.052,-0.002 -0.0013,-4.701331 -7.053333,-4.699331 -7.052,0.002 m -8.726,-8.728 c -6.67e-4,4.701331 7.051333,4.702331 7.052,10e-4 6.67e-4,-4.701331 -7.051333,-4.702331 -7.052,-10e-4 M 18.667,79.82 c -0.0022,1.948204 1.576795,3.528554 3.525,3.528 4.699998,0 4.699998,-7.05 0,-7.05 -1.94609,-0.0011 -3.524448,1.57591 -3.525,3.522" />
transform="translate(21.8672,45.7656)"><path
d="m 0,0 c 0,-0.729 0.591,-1.322 1.321,-1.322 0.732,0 1.323,0.593 1.323,1.322 0,0.73 -0.591,1.322 -1.323,1.322 C 0.591,1.322 0,0.73 0,0"
style="fill:#fffda9;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path52"
inkscape:connector-curvature="0" /></g><g
id="g54"
transform="translate(28.4116,45.7656)"><path
d="m 0,0 c 0,-0.729 0.591,-1.322 1.323,-1.322 0.729,0 1.321,0.593 1.321,1.322 0,0.73 -0.592,1.322 -1.321,1.322 C 0.591,1.322 0,0.73 0,0"
style="fill:#fffda9;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path56"
inkscape:connector-curvature="0" /></g><g
id="g58"
transform="translate(34.9561,45.7656)"><path
d="m 0,0 c 0,-0.729 0.592,-1.322 1.323,-1.322 0.73,0 1.321,0.593 1.321,1.322 0,0.73 -0.591,1.322 -1.321,1.322 C 0.592,1.322 0,0.73 0,0"
style="fill:#fffda9;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path60"
inkscape:connector-curvature="0" /></g><g
id="g62"
transform="translate(41.502,45.7656)"><path
d="m 0,0 c 0,-0.729 0.593,-1.322 1.32,-1.322 0.732,0 1.322,0.593 1.322,1.322 0,0.73 -0.59,1.322 -1.322,1.322 C 0.593,1.322 0,0.73 0,0"
style="fill:#fffda9;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path64"
inkscape:connector-curvature="0" /></g><g
id="g66"
transform="translate(48.0469,45.7656)"><path
d="m 0,0 c 0,-0.729 0.59,-1.322 1.32,-1.322 0.732,0 1.322,0.593 1.322,1.322 0,0.73 -0.59,1.322 -1.322,1.322 C 0.59,1.322 0,0.73 0,0"
style="fill:#fffda9;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path68"
inkscape:connector-curvature="0" /></g><g
id="g70"
transform="translate(54.5898,45.7656)"><path
d="m 0,0 c 0,-0.729 0.594,-1.322 1.32,-1.322 0.735,0 1.326,0.593 1.326,1.322 0,0.73 -0.591,1.322 -1.326,1.322 C 0.594,1.322 0,0.73 0,0"
style="fill:#fffda9;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path72"
inkscape:connector-curvature="0" /></g><g
id="g74"
transform="translate(61.1377,45.7656)"><path
d="m 0,0 c 0,-0.729 0.59,-1.322 1.319,-1.322 0.732,0 1.322,0.593 1.322,1.322 0,0.73 -0.59,1.322 -1.322,1.322 C 0.59,1.322 0,0.73 0,0"
style="fill:#fffda9;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path76"
inkscape:connector-curvature="0" /></g><g
id="g78"
transform="translate(14,26.1348)"><path
d="m 0,0 c 0,-1.465 1.184,-2.646 2.644,-2.646 1.461,0 2.645,1.181 2.645,2.646 0,1.459 -1.184,2.641 -2.645,2.641 C 1.184,2.641 0,1.459 0,0"
style="fill:#fffee3;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path80"
inkscape:connector-curvature="0" /></g><g
id="g82"
transform="translate(20.5444,58.856)"><path
d="m 0,0 c 0,-1.462 1.185,-2.645 2.644,-2.645 1.461,0 2.645,1.183 2.645,2.645 0,1.459 -1.184,2.644 -2.645,2.644 C 1.185,2.644 0,1.459 0,0"
style="fill:#fffee3;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path84"
inkscape:connector-curvature="0" /></g><g
id="g86"
transform="translate(27.0894,52.3101)"><path
d="m 0,0 c 0,-1.461 1.185,-2.644 2.645,-2.644 1.461,0 2.644,1.183 2.644,2.644 0,1.46 -1.183,2.645 -2.644,2.645 C 1.185,2.645 0,1.46 0,0"
style="fill:#fffee3;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path88"
inkscape:connector-curvature="0" /></g><g
id="g90"
transform="translate(27.0894,26.1348)"><path
d="m 0,0 c 0,-1.465 1.185,-2.646 2.645,-2.646 1.461,0 2.644,1.181 2.644,2.646 0,1.459 -1.183,2.641 -2.644,2.641 C 1.185,2.641 0,1.459 0,0"
style="fill:#fffee3;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path92"
inkscape:connector-curvature="0" /></g><g
id="g94"
transform="translate(33.6338,58.856)"><path
d="M 0,0 C 0,-1.462 1.184,-2.645 2.646,-2.645 4.106,-2.645 5.29,-1.462 5.29,0 5.29,1.459 4.106,2.644 2.646,2.644 1.184,2.644 0,1.459 0,0"
style="fill:#fffee3;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path96"
inkscape:connector-curvature="0" /></g><g
id="g98"
transform="translate(40.1758,52.3101)"><path
d="m 0,0 c 0,-1.461 1.187,-2.644 2.646,-2.644 1.461,0 2.648,1.183 2.648,2.644 0,1.46 -1.187,2.645 -2.648,2.645 C 1.187,2.645 0,1.46 0,0"
style="fill:#fffee3;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path100"
inkscape:connector-curvature="0" /></g><g
id="g102"
transform="translate(40.1758,32.6768)"><path
d="m 0,0 c 0,-1.458 1.187,-2.646 2.646,-2.646 1.461,0 2.648,1.188 2.648,2.646 0,1.459 -1.187,2.645 -2.648,2.645 C 1.187,2.645 0,1.459 0,0"
style="fill:#fffee3;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path104"
inkscape:connector-curvature="0" /></g><g
id="g106"
transform="translate(40.1758,26.1348)"><path
d="m 0,0 c 0,-1.465 1.187,-2.646 2.646,-2.646 1.461,0 2.648,1.181 2.648,2.646 0,1.459 -1.187,2.641 -2.648,2.641 C 1.187,2.641 0,1.459 0,0"
style="fill:#fffee3;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path108"
inkscape:connector-curvature="0" /></g><g
id="g110"
transform="translate(46.7236,52.3101)"><path
d="m 0,0 c 0,-1.461 1.184,-2.644 2.644,-2.644 1.461,0 2.645,1.183 2.645,2.644 0,1.46 -1.184,2.645 -2.645,2.645 C 1.184,2.645 0,1.46 0,0"
style="fill:#fffee3;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path112"
inkscape:connector-curvature="0" /></g><g
id="g114"
transform="translate(46.7236,32.6768)"><path
d="m 0,0 c 0,-1.458 1.184,-2.646 2.644,-2.646 1.461,0 2.645,1.188 2.645,2.646 0,1.459 -1.184,2.645 -2.645,2.645 C 1.184,2.645 0,1.459 0,0"
style="fill:#fffee3;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path116"
inkscape:connector-curvature="0" /></g><g
id="g118"
transform="translate(53.2686,58.856)"><path
d="m 0,0 c 0,-1.462 1.183,-2.645 2.643,-2.645 1.461,0 2.645,1.183 2.645,2.645 0,1.459 -1.184,2.644 -2.645,2.644 C 1.183,2.644 0,1.459 0,0"
style="fill:#fffee3;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path120"
inkscape:connector-curvature="0" /></g><g
id="g122"
transform="translate(53.2686,52.3101)"><path
d="m 0,0 c 0,-1.461 1.183,-2.644 2.643,-2.644 1.461,0 2.645,1.183 2.645,2.644 0,1.46 -1.184,2.645 -2.645,2.645 C 1.183,2.645 0,1.46 0,0"
style="fill:#fffee3;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path124"
inkscape:connector-curvature="0" /></g><g
id="g126"
transform="translate(59.8135,39.2217)"><path
d="m 0,0 c 0,-1.459 1.187,-2.646 2.644,-2.646 1.461,0 2.644,1.187 2.644,2.646 0,1.459 -1.183,2.646 -2.644,2.646 C 1.187,2.646 0,1.459 0,0"
style="fill:#fffee3;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path128"
inkscape:connector-curvature="0" /></g><g
id="g130"
transform="translate(59.8135,32.6768)"><path
d="m 0,0 c 0,-1.458 1.187,-2.646 2.644,-2.646 1.461,0 2.644,1.188 2.644,2.646 0,1.459 -1.183,2.645 -2.644,2.645 C 1.187,2.645 0,1.459 0,0"
style="fill:#fffee3;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path132"
inkscape:connector-curvature="0" /></g>
</g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View file

@ -1,39 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
style="enable-background:new 0 0 64 64;"
viewBox="0 0 64 64"
y="0px"
x="0px"
id="Layer_1"
version="1.1"><metadata
id="metadata17"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs15">
</defs>
<path
style="fill:#ffffff"
d="m 37.855477,15.759299 c -1.73926,0.0029 -4.47725,1.553014 -6.64098,2.8829 -1.6826,1.034172 -3.75291,1.108852 -5.69886,1.124912 h -8.64063 c -1.034,0 -1.875,0.841 -1.875,1.875 v 8.070312 l 2,1.359376 v -9.304688 h 8.51563 c 2.75742,-0.06081 4.84074,-0.2051 6.5836,-1.513027 2.1377,-1.604239 4.80361,-2.501457 7.17616,-2.486973 h 18.51758 c 0.666,0 1.20703,0.541031 1.20703,1.207031 v 31.542969 c 0,0.689 -0.561,1.25 -1.25,1.25 h -39.5 c -0.689,0 -1.25,-0.561 -1.25,-1.25 V 42.08547 l -2,1.359375 v 7.072266 c 0,1.792 1.458,3.25 3.25,3.25 h 39.5 c 1.792,0 3.25,-1.458 3.25,-3.25 V 18.974142 c 0,-1.769 -1.43803,-3.207984 -3.20703,-3.208984 h -18.51758 c -0.4765,0 -0.94899,-0.01047 -1.41992,-0.0059 z"
id="path6-9" /><path
id="path11-6"
d="m 12.995027,29.476688 10.626,7.222 -10.626,7.222 v -14.444 m -2,-1.778 v 18 c 0,1.1 0.744,1.494 1.654,0.876 l 12.875,-8.752 c 0.455,-0.309 0.682,-0.717 0.682,-1.124 0,-0.408 -0.227,-0.815 -0.682,-1.124 l -12.875,-8.751 c -0.91,-0.619 -1.654,-0.225 -1.654,0.875 z"
style="fill:#ffffff" /><path
id="path5-0"
d="m 15.000437,21.683979 v -6.5 c 0,-1.832003 1.6,-3.500003 3.357,-3.500003 h 10.636 c 1.967,0 3.809,0.854 4.848,2.238003 l 3.457,2.756 c -2.99546,1.819905 -4.21018,2.916329 -6.43718,3.672261 -5.13259,1.742208 -10.47736,1.018549 -15.86082,1.333739 z"
style="opacity:0.6;fill:#ffffff" /><path
id="path9-3-6"
d="m 3.3670166,11.247132 c -0.004,1.278302 0.0179,17.502612 0.0179,17.502612 v 0.0059 0.0059 c 0.0626,4.141039 2.28159,6.407836 4.41211,7.382812 2.13052,0.974976 4.2070304,0.853516 4.2070304,0.853516"
style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none" /></svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
style="enable-background:new 0 0 32 32;"
viewBox="0 0 32 32"
height="32"
width="32"
y="0px"
x="0px"
id="Layer_1"
version="1.1"><metadata
id="metadata19"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs17" />
<circle
r="4"
cy="16"
cx="16"
id="path861-7"
style="opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /><path
id="path826-6"
d="m 16.013202,10.0161 c -5.135781,-0.0066 -9.7712792,2.35462 -11.74455,5.983307 1.9732708,3.628688 6.608769,5.991032 11.74455,5.984494 5.107193,-0.0065 9.706497,-2.355358 11.682549,-5.954838 h 0.03565 c -0.0054,-0.01005 -0.01159,-0.01962 -0.01705,-0.02966 0.0055,-0.01002 0.01164,-0.01961 0.01705,-0.02966 h -0.03565 c -1.976079,-3.599428 -6.575398,-5.947148 -11.682549,-5.95365 z"
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /><circle
r="2"
cy="16"
cx="16"
id="path861"
style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /></svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
style="enable-background:new 0 0 32 32;"
viewBox="0 0 32 32"
height="32"
width="32"
y="0px"
x="0px"
id="Layer_1"
version="1.1"><metadata
id="metadata19"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs17" />
<path
id="rect853-3-7"
d="m 5.2218178,19.08774 c -2.1185651,2.118565 -2.1185651,5.573984 -4e-7,7.692548 2.1185648,2.118565 5.5739836,2.118565 7.6925486,0 l 4.866883,-4.866883 c 2.118565,-2.118565 2.118565,-5.573984 0,-7.692549 -2.118564,-2.118564 -5.573983,-2.118564 -7.692548,0 z m 1.4142135,1.414213 4.8668837,-4.866883 c 1.359552,-1.359552 3.504569,-1.359552 4.864121,0 1.359553,1.359553 1.359552,3.504569 0,4.864121 l -4.866884,4.866883 c -1.359552,1.359553 -3.5045682,1.359554 -4.864121,10e-7 -1.3595521,-1.359552 -1.3595521,-3.504569 3e-7,-4.864122 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /><path
id="rect853-6"
d="m 17.290288,17.295275 c -0.604056,-0.141842 -1.179293,-0.451814 -1.657396,-0.929916 -1.359554,-1.359552 -1.358171,-3.503188 0.0014,-4.86274 l -1.7e-5,-4e-6 4.866884,-4.8668837 c 1.359553,-1.3595528 3.503187,-1.3609338 4.86274,-0.00138 1.359553,1.3595528 1.359553,3.5045687 1e-6,4.8641217 l -4.866884,4.866883 c -0.354012,0.354012 -0.76128,0.615843 -1.19407,0.785494 0.09971,0.686342 0.114666,1.379464 -0.04531,2.08658 0.973641,-0.21685 1.898514,-0.702806 2.653575,-1.457867 l 4.866884,-4.866884 c 2.118565,-2.118565 2.118564,-5.5739835 0,-7.6925482 -2.118565,-2.1185648 -5.572602,-2.1171831 -7.691168,0.00138 l -4.866865,4.8668902 c -2.118564,2.118564 -2.119946,5.572602 -0.0014,7.691167 0.825683,0.825683 1.854427,1.329567 2.927951,1.511652 0.245536,-0.61844 0.301651,-1.33063 0.143675,-1.995945 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /></svg>

Before

Width:  |  Height:  |  Size: 4.5 KiB

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
style="enable-background:new 0 0 32 32;"
viewBox="0 0 32 32"
height="32px"
width="32px"
y="0px"
x="0px"
id="Layer_1"
version="1.1"><metadata
id="metadata17"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs3" /> Updated upstream
id=&quot;defs15&quot; /&gt;<path
id="path4567-6-9-2-9-0-3"
d="m 18.070362,15.595073 11.557261,13.3774 c 1.011409,0.983239 0.324995,1.686796 -0.658223,0.67537 L 15.619387,18.059831 Z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /><path
id="rect814-5-6"
d="M 10.644531,1.8125 C 10.384078,1.8161365 10.13532,1.9212454 9.9511719,2.1054688 L 2.1210938,9.9355469 c -0.3903681,0.3905301 -0.3903681,1.0235321 0,1.4140621 l 4.4667968,4.46875 0.78125,8.173829 c 0.079282,0.842901 1.1046782,1.212138 1.703125,0.613281 l 7.7734374,-7.775391 7.775391,-7.7734374 c 0.598857,-0.5984471 0.22962,-1.623844 -0.613282,-1.703125 L 15.832031,6.5722656 11.365234,2.1054688 C 11.174385,1.9145467 10.91446,1.8088858 10.644531,1.8125 Z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:0.6;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /></svg>

Before

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -0,0 +1,422 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import QtMultimedia 5.6
import "../js/functions.js" as Functions
import "../js/debug.js" as Debug
Item {
id: audioMessageComponent
property ListItem messageListItem
property MessageOverlayFlickable overlayFlickable
property var rawMessage: messageListItem ? messageListItem.myMessage : overlayFlickable.overlayMessage
property var audioData: ( rawMessage.content['@type'] === "messageVoiceNote" ) ? rawMessage.content.voice_note : ( ( rawMessage.content['@type'] === "messageAudio" ) ? rawMessage.content.audio : "");
property string audioUrl;
property int previewFileId;
property int audioFileId;
property bool onScreen: messageListItem ? messageListItem.page.status === PageStatus.Active : true
property string audioType : "voiceNote";
property bool highlighted;
signal clicked();
width: parent.width
height: width / 2
function getTimeString(rawSeconds) {
var minutes = Math.floor( rawSeconds / 60 );
var seconds = rawSeconds - ( minutes * 60 );
if ( minutes < 10 ) {
minutes = "0" + minutes;
}
if ( seconds < 10 ) {
seconds = "0" + seconds;
}
return minutes + ":" + seconds;
}
Component.onCompleted: {
updateAudioThumbnail();
}
function updateAudioThumbnail() {
if (audioData) {
audioType = ( audioData['@type'] === "voiceNote" ) ? "voice" : "audio";
audioFileId = audioData[audioType].id;
if (typeof audioData.album_cover_thumbnail !== "undefined") {
previewFileId = audioData.album_cover_thumbnail.photo.id;
if (audioData.album_cover_thumbnail.photo.local.is_downloading_completed) {
placeholderImage.source = audioData.album_cover_thumbnail.photo.local.path;
} else {
tdLibWrapper.downloadFile(previewFileId);
}
} else {
placeholderImage.source = "image://theme/icon-l-music?white";
placeholderImage.width = Theme.itemSizeLarge
placeholderImage.height = Theme.itemSizeLarge
}
}
}
function handlePlay() {
if (audioData[audioType].local.is_downloading_completed) {
audioUrl = audioData[audioType].local.path;
audioComponentLoader.active = true;
} else {
audioDownloadBusyIndicator.running = true;
tdLibWrapper.downloadFile(audioFileId);
}
}
Connections {
target: tdLibWrapper
onFileUpdated: {
if (typeof audioData === "object") {
if (fileInformation.local.is_downloading_completed) {
if (fileId === previewFileId) {
audioData.thumbnail.photo = fileInformation;
placeholderImage.source = fileInformation.local.path;
}
if (fileId === audioFileId) {
audioDownloadBusyIndicator.running = false;
audioData[audioType] = fileInformation;
audioUrl = fileInformation.local.path;
if (onScreen) {
audioComponentLoader.active = true;
}
}
}
if (fileId === audioFileId) {
downloadingProgressBar.maximumValue = fileInformation.size;
downloadingProgressBar.value = fileInformation.local.downloaded_size;
}
}
}
}
Image {
id: placeholderImage
width: parent.width
height: parent.height
anchors.centerIn: parent
asynchronous: true
fillMode: Image.PreserveAspectCrop
visible: status === Image.Ready ? true : false
layer.enabled: audioMessageComponent.highlighted
layer.effect: PressEffect { source: singleImage }
}
BackgroundImage {
visible: placeholderImage.status !== Image.Ready
layer.enabled: audioMessageComponent.highlighted
layer.effect: PressEffect { source: singleImage }
}
Rectangle {
id: placeholderBackground
color: "black"
opacity: 0.3
height: parent.height
width: parent.width
visible: playButton.visible
}
Column {
width: parent.width
height: downloadingProgressBar.height + audioControlRow.height
anchors.centerIn: parent
Row {
id: audioControlRow
width: parent.width
height: Theme.iconSizeLarge
Item {
height: Theme.iconSizeLarge
width: parent.width
IconButton {
id: playButton
anchors.centerIn: parent
width: Theme.iconSizeLarge
height: Theme.iconSizeLarge
icon {
source: "image://theme/icon-l-play?white"
asynchronous: true
}
highlighted: audioMessageComponent.highlighted || down
visible: placeholderImage.status === Image.Ready ? true : false
onClicked: {
handlePlay();
}
}
BusyIndicator {
id: audioDownloadBusyIndicator
running: false
visible: running
anchors.centerIn: parent
size: BusyIndicatorSize.Large
}
}
}
ProgressBar {
id: downloadingProgressBar
minimumValue: 0
maximumValue: 100
value: 0
visible: audioDownloadBusyIndicator.visible
width: parent.width
}
}
Rectangle {
id: audioErrorShade
width: parent.width
height: parent.height
color: "lightgrey"
visible: placeholderImage.status === Image.Error ? true : false
opacity: 0.3
}
Rectangle {
id: errorTextOverlay
color: "black"
opacity: 0.8
width: parent.width
height: parent.height
visible: false
}
Text {
id: errorText
visible: false
width: parent.width
color: Theme.primaryColor
font.pixelSize: Theme.fontSizeExtraSmall
horizontalAlignment: Text.AlignHCenter
anchors {
verticalCenter: parent.verticalCenter
}
wrapMode: Text.Wrap
text: ""
}
Loader {
id: audioComponentLoader
active: false
width: parent.width
height: parent.height
sourceComponent: audioComponent
}
Component {
id: audioComponent
Item {
width: parent ? parent.width : 0
height: parent ? parent.height : 0
Connections {
target: messageAudio
onPlaying: {
playButton.visible = false;
}
}
Connections {
target: audioMessageComponent
onClicked: {
if (messageAudio.playbackState === MediaPlayer.PlayingState) {
messageAudio.pause();
timeLeftItem.visible = true;
} else {
messageAudio.play();
timeLeftTimer.start();
}
}
}
Audio {
id: messageAudio
Component.onCompleted: {
if (messageAudio.error === MediaPlayer.NoError) {
messageAudio.play();
timeLeftTimer.start();
} else {
errorText.text = qsTr("Error loading audio! " + messageAudio.errorString)
errorTextOverlay.visible = true;
errorText.visible = true;
}
}
onStatusChanged: {
if (status == MediaPlayer.NoMedia) {
Debug.log("No Media");
audioBusyIndicator.visible = false;
}
if (status == MediaPlayer.Loading) {
Debug.log("Loading");
audioBusyIndicator.visible = true;
}
if (status == MediaPlayer.Loaded) {
Debug.log("Loaded");
audioBusyIndicator.visible = false;
}
if (status == MediaPlayer.Buffering) {
Debug.log("Buffering");
audioBusyIndicator.visible = true;
}
if (status == MediaPlayer.Stalled) {
Debug.log("Stalled");
audioBusyIndicator.visible = true;
}
if (status == MediaPlayer.Buffered) {
Debug.log("Buffered");
audioBusyIndicator.visible = false;
}
if (status == MediaPlayer.EndOfMedia) {
Debug.log("End of Media");
audioBusyIndicator.visible = false;
}
if (status == MediaPlayer.InvalidMedia) {
Debug.log("Invalid Media");
audioBusyIndicator.visible = false;
}
if (status == MediaPlayer.UnknownStatus) {
Debug.log("Unknown Status");
audioBusyIndicator.visible = false;
}
}
source: audioUrl
onStopped: {
playButton.visible = true;
audioComponentLoader.active = false;
}
}
BusyIndicator {
id: audioBusyIndicator
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
visible: false
running: visible
size: BusyIndicatorSize.Medium
}
Timer {
id: timeLeftTimer
repeat: false
interval: 2000
onTriggered: {
timeLeftItem.visible = false;
}
}
Item {
id: timeLeftItem
width: parent.width
height: parent.height
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
opacity: visible ? 1 : 0
Behavior on opacity { NumberAnimation {} }
Rectangle {
id: positionTextOverlay
color: "black"
opacity: 0.3
width: parent.width
height: parent.height
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
visible: pausedRow.visible
}
Row {
id: pausedRow
width: parent.width
height: parent.height - ( messageAudioSlider.visible ? messageAudioSlider.height : 0 ) - ( positionText.visible ? positionText.height : 0 )
visible: audioComponentLoader.active && messageAudio.playbackState === MediaPlayer.PausedState
Item {
height: parent.height
width: parent.width
IconButton {
id: pausedPlayButton
anchors.centerIn: parent
width: Theme.iconSizeLarge
height: Theme.iconSizeLarge
highlighted: videoMessageComponent.highlighted || down
icon {
asynchronous: true
source: "image://theme/icon-l-play?white"
}
onClicked: {
messageAudio.play();
timeLeftTimer.start();
}
}
}
}
Slider {
id: messageAudioSlider
width: parent.width
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: positionText.top
minimumValue: 0
maximumValue: messageAudio.duration ? messageAudio.duration : 0
stepSize: 1
value: messageAudio.position
enabled: messageAudio.seekable
visible: (messageAudio.duration > 0)
highlighted: videoMessageComponent.highlighted || down
onReleased: {
messageAudio.seek(Math.floor(value));
messageAudio.play();
timeLeftTimer.start();
}
valueText: getTimeString(Math.round((messageAudio.duration - messageAudioSlider.value) / 1000))
}
Text {
id: positionText
visible: messageAudio.duration === 0
color: Theme.primaryColor
font.pixelSize: Theme.fontSizeTiny
anchors {
bottom: parent.bottom
bottomMargin: Theme.paddingSmall
horizontalCenter: positionTextOverlay.horizontalCenter
}
wrapMode: Text.Wrap
text: ( messageAudio.duration - messageAudio.position ) > 0 ? getTimeString(Math.round((messageAudio.duration - messageAudio.position) / 1000)) : "-:-"
}
}
}
}
}

View file

@ -9,72 +9,30 @@ PhotoTextsListItem {
id: listItem id: listItem
pictureThumbnail { pictureThumbnail {
photoData: photo_small || ({}) photoData: photo_small || ({})
highlighted: listItem.highlighted && !listItem.menuOpen
} }
property int ownUserId property int ownUserId
property bool showDraft: !!draft_message_text && draft_message_date > last_message_date
property string previewText: showDraft ? draft_message_text : last_message_text
// chat title // chat title
primaryText.text: title ? Emoji.emojify(title, Theme.fontSizeMedium) : qsTr("Unknown") primaryText.text: title ? Emoji.emojify(title + ( display.notification_settings.mute_for > 0 ? " 🔇" : "" ), Theme.fontSizeMedium) : qsTr("Unknown")
// last user // last user
prologSecondaryText.text: showDraft ? "<i>"+qsTr("Draft")+"</i>" : (is_channel ? "" : ( last_message_sender_id ? ( last_message_sender_id !== ownUserId ? Emoji.emojify(Functions.getUserName(tdLibWrapper.getUserInformation(last_message_sender_id)), Theme.fontSizeExtraSmall) : qsTr("You") ) : "" )) prologSecondaryText.text: is_channel ? "" : ( last_message_sender_id ? ( last_message_sender_id !== ownUserId ? Emoji.emojify(Functions.getUserName(tdLibWrapper.getUserInformation(last_message_sender_id)), primaryText.font.pixelSize) : qsTr("You") ) : "" )
// last message // last message
secondaryText.text: previewText ? Emoji.emojify(Functions.enhanceHtmlEntities(previewText), Theme.fontSizeExtraSmall) : "<i>" + qsTr("No message in this chat.") + "</i>" secondaryText.text: last_message_text ? Emoji.emojify(Functions.enhanceHtmlEntities(last_message_text), Theme.fontSizeExtraSmall) : "<i>" + qsTr("No message in this chat.") + "</i>"
// message date // message date
tertiaryText.text: showDraft ? Functions.getDateTimeElapsed(draft_message_date) : ( last_message_date ? ( last_message_date.length === 0 ? "" : Functions.getDateTimeElapsed(last_message_date) + Emoji.emojify(last_message_status, tertiaryText.font.pixelSize) ) : "" ) tertiaryText.text: ( last_message_date ? ( last_message_date.length === 0 ? "" : Functions.getDateTimeElapsed(last_message_date) + Emoji.emojify(last_message_status, tertiaryText.font.pixelSize) ) : "" )
unreadCount: unread_count unreadCount: unread_count
unreadReactionCount: unread_reaction_count
unreadMentionCount: unread_mention_count
isSecret: ( chat_type === TelegramAPI.ChatTypeSecret ) isSecret: ( chat_type === TelegramAPI.ChatTypeSecret )
isMarkedAsUnread: is_marked_as_unread
isPinned: is_pinned
isMuted: display.notification_settings.mute_for > 0
openMenuOnPressAndHold: true//chat_id != overviewPage.ownUserId openMenuOnPressAndHold: true//chat_id != overviewPage.ownUserId
menu: ContextMenu {
onPressAndHold: {
contextMenuLoader.active = true;
}
Loader {
id: contextMenuLoader
active: false
asynchronous: true
onStatusChanged: {
if(status === Loader.Ready) {
listItem.menu = item;
listItem.openMenu();
}
}
sourceComponent: Component {
ContextMenu {
MenuItem { MenuItem {
visible: unread_count > 0 || unread_reaction_count > 0 || unread_mention_count > 0 visible: unread_count > 0
onClicked: { onClicked: {
tdLibWrapper.viewMessage(chat_id, display.last_message.id, true); tdLibWrapper.viewMessage(chat_id, display.last_message.id, true);
tdLibWrapper.readAllChatMentions(chat_id);
tdLibWrapper.readAllChatReactions(chat_id);
tdLibWrapper.toggleChatIsMarkedAsUnread(chat_id, false);
} }
text: qsTr("Mark all messages as read") text: qsTr("Mark all messages as read")
} }
MenuItem {
visible: unread_count === 0 && unread_reaction_count === 0 && unread_mention_count === 0
onClicked: {
tdLibWrapper.toggleChatIsMarkedAsUnread(chat_id, !is_marked_as_unread);
}
text: is_marked_as_unread ? qsTr("Mark chat as read") : qsTr("Mark chat as unread")
}
MenuItem {
onClicked: {
tdLibWrapper.toggleChatIsPinned(chat_id, !is_pinned);
}
text: is_pinned ? qsTr("Unpin chat") : qsTr("Pin chat")
}
MenuItem { MenuItem {
visible: chat_id != listItem.ownUserId visible: chat_id != listItem.ownUserId
onClicked: { onClicked: {
@ -87,7 +45,7 @@ PhotoTextsListItem {
newNotificationSettings.use_default_mute_for = false; newNotificationSettings.use_default_mute_for = false;
tdLibWrapper.setChatNotificationSettings(chat_id, newNotificationSettings); tdLibWrapper.setChatNotificationSettings(chat_id, newNotificationSettings);
} }
text: display.notification_settings.mute_for > 0 ? qsTr("Unmute chat") : qsTr("Mute chat") text: display.notification_settings.mute_for > 0 ? qsTr("Unmute Chat") : qsTr("Mute Chat")
} }
MenuItem { MenuItem {
@ -101,7 +59,5 @@ PhotoTextsListItem {
text: model.display.type['@type'] === "chatTypePrivate" ? qsTr("User Info") : qsTr("Group Info") text: model.display.type['@type'] === "chatTypePrivate" ? qsTr("User Info") : qsTr("Group Info")
} }
} }
}
}
} }

View file

@ -1,44 +0,0 @@
/*
Copyright (C) 2021 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.0
//import org.nemomobile.contacts 1.0
Item {
// signal syncError();
// function synchronize() {
// if (peopleModel.count === 0) {
// appNotification.show(qsTr("Could not synchronize your contacts with Telegram."));
// syncError();
// } else {
// contactsModel.startImportingContacts();
// for (var i = 0; i < peopleModel.count; i++ ) {
// contactsModel.importContact(peopleModel.get(i));
// }
// contactsModel.stopImportingContacts();
// }
// }
// PeopleModel {
// id: peopleModel
// requiredProperty: PeopleModel.PhoneNumberRequired
// }
}

View file

@ -0,0 +1,111 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
Item {
id: documentPreviewItem
width: parent.width
height: Theme.itemSizeLarge
property ListItem messageListItem
property MessageOverlayFlickable overlayFlickable
property var rawMessage: messageListItem ? messageListItem.myMessage : overlayFlickable.overlayMessage
property var documentData: rawMessage.content.document
property bool openRequested: false;
property bool highlighted;
Component.onCompleted: {
updateDocument();
}
function updateDocument() {
if (documentData) {
if (documentData.document.local.is_downloading_completed) {
downloadDocumentButton.visible = false;
openDocumentButton.visible = true;
} else {
openDocumentButton.visible = false;
downloadDocumentButton.visible = true;
}
}
}
Connections {
target: tdLibWrapper
onFileUpdated: {
if (documentData) {
if (!fileInformation.remote.is_uploading_active && fileId === documentData.document.id && fileInformation.local.is_downloading_completed) {
downloadingProgressBar.visible = false;
documentData.document = fileInformation;
downloadDocumentButton.visible = false;
openDocumentButton.visible = true;
if (documentPreviewItem.openRequested) {
documentPreviewItem.openRequested = false;
tdLibWrapper.openFileOnDevice(documentData.document.local.path);
}
}
if (fileId === documentData.document.id) {
downloadingProgressBar.maximumValue = fileInformation.size;
downloadingProgressBar.value = fileInformation.local.downloaded_size;
}
}
}
}
Button {
id: downloadDocumentButton
preferredWidth: Theme.buttonWidthMedium
anchors.centerIn: parent
text: qsTr("Download Document")
visible: false
highlighted: videoMessageComponent.highlighted || down
onClicked: {
downloadDocumentButton.visible = false;
downloadingProgressBar.visible = true;
tdLibWrapper.downloadFile(documentData.document.id);
}
}
ProgressBar {
id: downloadingProgressBar
minimumValue: 0
maximumValue: 100
value: 0
visible: false
width: parent.width
anchors.centerIn: parent
}
Button {
id: openDocumentButton
preferredWidth: Theme.buttonWidthMedium
anchors.centerIn: parent
text: qsTr("Open Document")
visible: false
highlighted: videoMessageComponent.highlighted || down
onClicked: {
documentPreviewItem.openRequested = true;
tdLibWrapper.openFileOnDevice(documentData.document.local.path);
}
}
}

View file

@ -0,0 +1,86 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
Item {
id: imagePreviewItem
property ListItem messageListItem
property MessageOverlayFlickable overlayFlickable
property var rawMessage: messageListItem ? messageListItem.myMessage : overlayFlickable.overlayMessage
property var photoData: rawMessage.content.photo
readonly property int defaultHeight: Math.round(width * 2 / 3)
property bool highlighted
width: parent.width
height: singleImage.visible ? Math.min(defaultHeight, singleImage.bestHeight + Theme.paddingSmall) : defaultHeight
function clicked() {
pageStack.push(Qt.resolvedUrl("../pages/ImagePage.qml"), {
"photoData" : imagePreviewItem.photoData,
"pictureFileInformation" : imageFile.fileInformation
})
}
Component.onCompleted: {
if (photoData) {
// Check first which size fits best...
var photo
for (var i = 0; i < photoData.sizes.length; i++) {
photo = photoData.sizes[i].photo
if (photoData.sizes[i].width >= imagePreviewItem.width) {
break
}
}
if (photo) {
imageFile.fileInformation = photo
}
}
}
TDLibFile {
id: imageFile
tdlib: tdLibWrapper
autoLoad: true
}
Image {
id: singleImage
width: parent.width - Theme.paddingSmall
height: parent.height - Theme.paddingSmall
readonly property int bestHeight: (status === Image.Ready) ? Math.round(implicitHeight * width / implicitWidth) : 0
anchors.centerIn: parent
fillMode: Image.PreserveAspectCrop
autoTransform: true
asynchronous: true
source: imageFile.isDownloadingCompleted ? imageFile.path : ""
visible: status === Image.Ready
opacity: visible ? 1 : 0
Behavior on opacity { FadeAnimation {} }
layer.enabled: imagePreviewItem.highlighted
layer.effect: PressEffect { source: singleImage }
}
BackgroundImage {
visible: singleImage.status !== Image.Ready
}
}

View file

@ -31,21 +31,13 @@ Row {
property string myUserId; property string myUserId;
property var inReplyToMessage; property var inReplyToMessage;
property bool editable: false; property bool editable: false;
property bool inReplyToMessageDeleted: false;
signal clearRequested() signal clearRequested()
onInReplyToMessageChanged: { onInReplyToMessageChanged: {
if (inReplyToMessage) { if (inReplyToMessage) {
inReplyToUserText.text = (inReplyToMessage.sender_id["@type"] === "messageSenderChat" ? page.chatInformation.title : (inReplyToRow.inReplyToMessage.sender_id.user_id !== inReplyToRow.myUserId) ? Emoji.emojify(Functions.getUserName(tdLibWrapper.getUserInformation(inReplyToRow.inReplyToMessage.sender_id.user_id)), inReplyToUserText.font.pixelSize) : qsTr("You")); inReplyToUserText.text = (inReplyToRow.inReplyToMessage.sender.user_id !== inReplyToRow.myUserId) ? Emoji.emojify(Functions.getUserName(tdLibWrapper.getUserInformation(inReplyToRow.inReplyToMessage.sender.user_id)), inReplyToUserText.font.pixelSize) : qsTr("You");
inReplyToMessageText.text = Emoji.emojify(Functions.getMessageText(inReplyToRow.inReplyToMessage, true, inReplyToRow.myUserId, false), inReplyToMessageText.font.pixelSize); inReplyToMessageText.text = Emoji.emojify(Functions.getMessageText(inReplyToRow.inReplyToMessage, true, inReplyToRow.inReplyToMessage.sender.user_id === inReplyToRow.myUserId, false), inReplyToMessageText.font.pixelSize);
}
}
onInReplyToMessageDeletedChanged: {
if (inReplyToMessageDeleted) {
inReplyToUserText.text = qsTr("Unknown")
inReplyToMessageText.text = "<i>" + qsTr("This message was deleted") + "</i>";
} }
} }

View file

@ -1,399 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import "../js/debug.js" as Debug
import "../js/twemoji.js" as Emoji
import "../js/functions.js" as Functions
Loader {
id: inlineQueryLoader
active: userName.length > 1
asynchronous: true
anchors {
left: parent.left
right: parent.right
top: parent.top
bottom: active ? parent.bottom : parent.top
}
property bool hasOverlay: active && userNameIsValid && status === Loader.Ready && item.overlay && item.overlay.status === Loader.Ready
property bool hasButton: active && userNameIsValid && status === Loader.Ready && item.button && item.button.status === Loader.Ready
property int buttonPadding: hasButton ? item.button.height + Theme.paddingSmall : 0
Behavior on buttonPadding { NumberAnimation { duration: 200} }
property string chatId
property string userName
property bool userNameIsValid: userName !== "" && inlineBotInformation && userName.toLowerCase() === inlineBotInformation.usernames.editable_username.toLowerCase()
property string query
property int currentOffset: 0
property string responseExtra: chatId+"|"+userName+"|"+query+"|"+currentOffset
property bool queued: false
property TextArea textField
property bool isLoading
property var inlineBotInformation: null
onIsLoadingChanged: {
requestTimeout.start();
}
onStatusChanged: {
inlineBotInformation = null;
if(status === Loader.Ready && userName !== "") {
isLoading = true; inlineQueryLoader.chatId
tdLibWrapper.searchPublicChat(userName, false);
}
}
onUserNameChanged: {
inlineBotInformation = null;
if(status === Loader.Ready && userName !== "") {
isLoading = true;
tdLibWrapper.searchPublicChat(userName, false);
}
}
onQueryChanged: {
if(userName.length > 0) {
isLoading = true;
requestTimer.start();
}
}
function handleQuery(name, query, offset) {
if(!name) {
inlineQueryLoader.userName = "";
inlineQueryLoader.query = "";
return;
}
if(inlineQueryLoader.userName !== name) {
inlineQueryLoader.userName = name
}
if(inlineQueryLoader.query !== query) {
inlineQueryLoader.query = query
}
inlineQueryLoader.currentOffset = offset || 0
}
function request() {
if(!inlineBotInformation || !userNameIsValid) {
queued = true;
} else {
queued = false;
var location = null;
if(inlineBotInformation.type.need_location && fernschreiberUtils.supportsGeoLocation()) {
fernschreiberUtils.startGeoLocationUpdates();
if(!attachmentPreviewRow.locationData.latitude) {
queued = true;
return;
}
}
tdLibWrapper.getInlineQueryResults(inlineBotInformation.id, chatId, location, query, inlineQueryLoader.currentOffset, inlineQueryLoader.responseExtra);
isLoading = true;
}
}
Timer {
id: requestTimeout
interval: 5000
onTriggered: {
inlineQueryLoader.isLoading = false;
}
}
Timer {
id: requestTimer
interval: 1000
onTriggered: {
request();
}
}
Connections {
target: fernschreiberUtils
onNewPositionInformation: {
attachmentPreviewRow.locationData = positionInformation;
if (inlineQueryLoader.queued) {
inlineQueryLoader.queued = false;
inlineQueryLoader.request()
}
}
}
Connections {
target: textField
onTextChanged: {
if(textField.text.charAt(0) === '@') {
var queryMatch = textField.text.match(/^@([a-zA-Z0-9_]+)\s(.*)/);
if(queryMatch) {
inlineQueryLoader.handleQuery(queryMatch[1], queryMatch[2]);
} else {
inlineQueryLoader.handleQuery();
}
} else {
inlineQueryLoader.handleQuery();
}
}
}
sourceComponent: Component {
Item {
id: inlineQueryComponent
anchors.fill: parent
property alias overlay: resultsOverlay
property alias button: switchToPmLoader
property string nextOffset
property string inlineQueryId
property string switchPmText
property string switchPmParameter
property ListModel resultModel: ListModel {
dynamicRoles: true
}
property string inlineQueryPlaceholder: inlineBotInformation ? inlineBotInformation.type.inline_query_placeholder : ""
property bool showInlineQueryPlaceholder: !!inlineQueryPlaceholder && query === ""
property string useDelegateSize: "default"
property var dimensions: ({
"default": [[Screen.width, Screen.height / 2], [Theme.itemSizeLarge, Theme.itemSizeLarge]], // whole line (portrait half)
"inlineQueryResultAnimation": [[Screen.width / 3, Screen.height / 6], [Screen.width / 3, Screen.height / 6]],
"inlineQueryResultVideo": [[Screen.width / 2, Screen.height / 4], [Theme.itemSizeLarge, Theme.itemSizeLarge]],
"inlineQueryResultSticker": [[Screen.width / 3, Screen.height / 6], [Screen.width / 3, Screen.height / 6]],
"inlineQueryResultPhoto": [[Screen.width/2, Screen.height / 3], [Theme.itemSizeExtraLarge, Theme.itemSizeExtraLarge]],
})
property int delegateWidth: chatPage.isPortrait ? dimensions[useDelegateSize][0][0] : dimensions[useDelegateSize][0][1]
property int delegateHeight: chatPage.isPortrait ? dimensions[useDelegateSize][1][0] : dimensions[useDelegateSize][1][1]
function setDelegateSizes() {
var sizeKey = "default";
var modelCount = resultModel.count;
if(modelCount > 0) {
var firstType = resultModel.get(0)["@type"];
if(firstType && dimensions[firstType]) {
var startIndex = inlineQueryLoader.currentOffset === 0 ? 1 : inlineQueryLoader.currentOffset;
var same = true;
for(var i = startIndex; i < modelCount; i += 1) {
if(resultModel.get(i)["@type"] !== firstType) {
same = false;
continue;
}
}
if(same) {
sizeKey = firstType;
}
}
}
useDelegateSize = sizeKey;
}
function loadMore() {
if(nextOffset && inlineQueryLoader.userNameIsValid) {
inlineQueryLoader.currentOffset = nextOffset;
inlineQueryLoader.request();
}
}
Connections {
target: tdLibWrapper
onChatReceived: {
if(chat["@extra"] === "searchPublicChat:"+inlineQueryLoader.userName) {
requestTimeout.stop();
inlineQueryLoader.isLoading = false;
var inlineBotInformation = tdLibWrapper.getUserInformation(chat.type.user_id);
if(inlineBotInformation && inlineBotInformation.type["@type"] === "userTypeBot" && inlineBotInformation.type.is_inline) {
inlineQueryLoader.inlineBotInformation = inlineBotInformation;
requestTimer.start();
}
}
}
onInlineQueryResults: {
if(extra === inlineQueryLoader.responseExtra) {
requestTimeout.stop();
inlineQueryLoader.isLoading = false;
inlineQueryComponent.inlineQueryId = inlineQueryId
inlineQueryComponent.nextOffset = nextOffset
inlineQueryComponent.switchPmText = switchPmText
inlineQueryComponent.switchPmParameter = switchPmParameter
if(inlineQueryLoader.currentOffset === 0) {
inlineQueryComponent.resultModel.clear()
}
for(var i = 0; i < results.length; i++) {
inlineQueryComponent.resultModel.append(results[i]);
}
if(inlineQueryLoader.currentOffset === 0 || inlineQueryLoader.useDelegateSize !== "default") {
inlineQueryComponent.setDelegateSizes()
}
}
}
}
// switch to pm Button
Loader {
id: switchToPmLoader
asynchronous: true
active: inlineQueryComponent.switchPmText.length > 0
opacity: status === Loader.Ready ? 1.0 : 0.0
Behavior on opacity { FadeAnimation {} }
height: Theme.itemSizeSmall
anchors {
top: parent.bottom
topMargin: Theme.paddingSmall
left: parent.left
leftMargin: Theme.horizontalPageMargin
right: parent.right
rightMargin: Theme.horizontalPageMargin
}
sourceComponent: Component {
MouseArea {
id: customButton
onClicked: {
tdLibWrapper.createPrivateChat(inlineQueryLoader.inlineBotInformation.id, "openAndSendStartToBot:"+(inlineQueryComponent.switchPmParameter.length > 0 ? " "+inlineQueryComponent.switchPmParameter:""));
}
Rectangle {
anchors.fill: parent
radius: Theme.paddingSmall
color: parent.pressed ? Theme.highlightBackgroundColor : Theme.rgba(Theme.DarkOnLight ? Qt.lighter(Theme.primaryColor) : Qt.darker(Theme.primaryColor), Theme.opacityFaint)
Label {
anchors {
fill: parent
leftMargin: Theme.paddingLarge
rightMargin: Theme.paddingLarge
}
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
fontSizeMode: Text.Fit;
minimumPixelSize: Theme.fontSizeTiny;
font.pixelSize: Theme.fontSizeSmall
color: customButton.pressed ? Theme.highlightColor : Theme.primaryColor
text: Emoji.emojify(inlineQueryComponent.switchPmText, font.pixelSize)// + "we are gonna make this a bit longer"
}
}
}
}
}
// results grid overlay
Loader {
id: resultsOverlay
asynchronous: true
active: inlineQueryComponent.resultModel.count > 0
anchors.fill: parent
opacity: !!item ? 1.0 : 0.0
Behavior on opacity { FadeAnimation {} }
property var supportedResultTypes: [
"inlineQueryResultAnimation",
"inlineQueryResultArticle",
"inlineQueryResultAudio",
"inlineQueryResultContact",
"inlineQueryResultDocument",
"inlineQueryResultGame",
"inlineQueryResultLocation",
"inlineQueryResultPhoto",
"inlineQueryResultSticker",
"inlineQueryResultVenue",
"inlineQueryResultVideo",
"inlineQueryResultVoiceNote",
]
sourceComponent: Component {
Item {
Rectangle {
id: messageContentBackground
color: Theme.overlayBackgroundColor
opacity: 0.7
anchors.fill: parent
}
Timer {
id: autoLoadMoreTimer
interval: 400
onTriggered: {
if (inlineQueryComponent.nextOffset && resultView.height > resultView.contentHeight - Theme.itemSizeHuge) {
inlineQueryComponent.loadMore();
}
}
}
SilicaGridView {
id: resultView
anchors.fill: parent
cellWidth: inlineQueryComponent.delegateWidth
cellHeight: inlineQueryComponent.delegateHeight
signal requestPlayback(url playbackSource)
clip: true
model: inlineQueryComponent.resultModel
delegate: Loader {
id: queryResultDelegate
height: resultView.cellHeight
width: resultView.cellWidth
source: "inlineQueryResults/" + (resultsOverlay.supportedResultTypes.indexOf(model["@type"]) > -1 ? (model["@type"].charAt(0).toUpperCase() + model["@type"].substring(1)) : "InlineQueryResultDefaultBase") +".qml"
}
footer: Component {
Item {
width: resultView.width
visible: height > 0
height: inlineQueryComponent.nextOffset ? Theme.itemSizeLarge : 0
Behavior on height { NumberAnimation { duration: 500 } }
}
}
onContentYChanged: {
if(!inlineQueryLoader.isLoading && inlineQueryComponent.nextOffset && contentHeight - contentY - height < Theme.itemSizeHuge) {
inlineQueryComponent.loadMore();
}
}
ScrollDecorator { flickable: resultView }
}
}
}
}
// textarea placeholder
Loader {
asynchronous: true
active: inlineQueryComponent.showInlineQueryPlaceholder
sourceComponent: Component {
Label {
text: Emoji.emojify(inlineQueryComponent.inlineQueryPlaceholder, font.pixelSize);
parent: textField
anchors.fill: parent
anchors.leftMargin: textMetrics.boundingRect.width + Theme.paddingSmall
font: textField.font
color: Theme.secondaryColor
truncationMode: TruncationMode.Fade
TextMetrics {
id: textMetrics
font: textField.font
text: textField.text
}
}
}
}
}
}
}

View file

@ -0,0 +1,112 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import QtGraphicalEffects 1.0
import Sailfish.Silica 1.0
Item {
id: imagePreviewItem
property ListItem messageListItem
property MessageOverlayFlickable overlayFlickable
property var rawMessage: messageListItem ? messageListItem.myMessage : overlayFlickable.overlayMessage
property bool highlighted
property var locationData : ( rawMessage.content['@type'] === "messageLocation" ) ? rawMessage.content.location : ( ( rawMessage.content['@type'] === "messageVenue" ) ? rawMessage.content.venue.location : "" )
property string chatId: rawMessage.chat_id
property var pictureFileInformation;
width: parent.width
height: width / 2
Component.onCompleted: {
updatePicture();
}
function clicked(){
if(!processLauncher.launchProgram('harbour-pure-maps', ["geo:"+locationData.latitude+","+locationData.longitude])) {
imageNotification.show(qsTr("Install Pure Maps to inspect this location."));
}
}
function updatePicture() {
imagePreviewItem.pictureFileInformation = null;
if (locationData) {
tdLibWrapper.getMapThumbnailFile(chatId, locationData.latitude, locationData.longitude, Math.round(imagePreviewItem.width), Math.round(imagePreviewItem.height));
}
}
Connections {
target: tdLibWrapper
onFileUpdated: {
// we do not have a way of knowing if this is the correct file, so we have to guess the first new one should be right.
if(!imagePreviewItem.pictureFileInformation) {
imagePreviewItem.pictureFileInformation = fileInformation;
tdLibWrapper.downloadFile(imagePreviewItem.pictureFileInformation.id);
} else if(imagePreviewItem.pictureFileInformation && fileInformation.id === imagePreviewItem.pictureFileInformation.id) {
imagePreviewItem.pictureFileInformation = fileInformation;
singleImage.source = fileInformation.local.path;
}
}
}
AppNotification {
id: imageNotification
}
Image {
id: singleImage
width: parent.width - Theme.paddingSmall
height: parent.height - Theme.paddingSmall
anchors.centerIn: parent
fillMode: Image.PreserveAspectCrop
autoTransform: true
asynchronous: true
visible: status === Image.Ready
opacity: status === Image.Ready ? 1 : 0
Behavior on opacity { NumberAnimation {} }
layer.enabled: imagePreviewItem.highlighted
layer.effect: PressEffect { source: singleImage }
Item {
anchors.centerIn: parent
width: markerImage.width
height: markerImage.height * 1.75 // 0.875 (vertical pin point) * 2
Image {
id: markerImage
source: 'image://theme/icon-m-location'
}
DropShadow {
anchors.fill: markerImage
horizontalOffset: 3
verticalOffset: 3
radius: 8.0
samples: 17
color: Theme.colorScheme ? Theme.lightPrimaryColor : Theme.darkPrimaryColor
source: markerImage
}
}
}
BackgroundImage {
visible: singleImage.status !== Image.Ready
}
}

View file

@ -18,200 +18,57 @@
*/ */
import QtQuick 2.6 import QtQuick 2.6
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import "./messageContent"
import "../js/twemoji.js" as Emoji import "../js/twemoji.js" as Emoji
import "../js/functions.js" as Functions import "../js/functions.js" as Functions
import "../js/debug.js" as Debug import "../js/debug.js" as Debug
ListItem { ListItem {
id: messageListItem id: messageListItem
contentHeight: messageBackground.height + Theme.paddingMedium + ( reactionsColumn.visible ? reactionsColumn.height : 0 ) contentHeight: messageBackground.height + Theme.paddingMedium
Behavior on contentHeight { NumberAnimation { duration: 200 } }
property var chatId property var chatId
property var messageId property var messageId
property int messageIndex
property int messageViewCount
property var myMessage property var myMessage
property var reactions
property bool canReplyToMessage property bool canReplyToMessage
readonly property bool isAnonymous: myMessage.sender_id["@type"] === "messageSenderChat" readonly property var userInformation: tdLibWrapper.getUserInformation(myMessage.sender.user_id)
readonly property var userInformation: tdLibWrapper.getUserInformation(myMessage.sender_id.user_id)
property QtObject precalculatedValues: ListView.view.precalculatedValues property QtObject precalculatedValues: ListView.view.precalculatedValues
readonly property color textColor: isOwnMessage ? Theme.highlightColor : Theme.primaryColor readonly property color textColor: isOwnMessage ? Theme.highlightColor : Theme.primaryColor
readonly property int textAlign: Text.AlignLeft readonly property int textAlign: isOwnMessage ? Text.AlignRight : Text.AlignLeft
readonly property Page page: precalculatedValues.page readonly property Page page: precalculatedValues.page
readonly property bool isSelected: messageListItem.precalculatedValues.pageIsSelecting && page.selectedMessages.some(function(existingMessage) { readonly property bool isSelected: messageListItem.precalculatedValues.pageIsSelecting && page.selectedMessages.some(function(existingMessage) {
return existingMessage.id === messageId return existingMessage.id === messageId
}); });
readonly property bool isOwnMessage: page.myUserId === myMessage.sender_id.user_id readonly property bool isOwnMessage: page.myUserId === myMessage.sender.user_id
readonly property bool canDeleteMessage: myMessage.can_be_deleted_for_all_users || (myMessage.can_be_deleted_only_for_self && myMessage.chat_id === page.myUserId) property string extraContentComponentName
property bool hasContentComponent
property bool additionalOptionsOpened
property bool wasNavigatedTo: false
readonly property var additionalItemsModel: (extraContentLoader.item && ("extraContextMenuItems" in extraContentLoader.item)) ? highlighted: (down || isSelected) && !menuOpen
extraContentLoader.item.extraContextMenuItems : 0
readonly property int numberOfExtraOptionsOtherThanDeleteMessage:
(showCopyMessageToClipboardMenuItem ? 0 : 1) +
(showForwardMessageMenuItem ? 0 : 1) +
(page.canPinMessages() ? 1 : 0) +
(additionalItemsModel ? additionalItemsModel.length : 0)
readonly property bool deleteMessageIsOnlyExtraOption: canDeleteMessage && !numberOfExtraOptionsOtherThanDeleteMessage
readonly property int maxContextMenuItemCount: page.isPortrait ? 5 : 4
readonly property int baseContextMenuItemCount: (canReplyToMessage ? 1 : 0) +
(myMessage.can_be_edited ? 1 : 0) + 2 /* "Select Message" and "More Options..." */
readonly property bool showCopyMessageToClipboardMenuItem: (baseContextMenuItemCount + 1) <= maxContextMenuItemCount
readonly property bool showForwardMessageMenuItem: (baseContextMenuItemCount + 2) <= maxContextMenuItemCount
// And don't count "More Options..." for "Delete Message" if "Delete Message" is the only extra option
readonly property bool haveSpaceForDeleteMessageMenuItem: (baseContextMenuItemCount + 3 - (deleteMessageIsOnlyExtraOption ? 1 : 0)) <= maxContextMenuItemCount
property var chatReactions
property var messageReactions
highlighted: (down || isSelected || additionalOptionsOpened || wasNavigatedTo) && !menuOpen
openMenuOnPressAndHold: !messageListItem.precalculatedValues.pageIsSelecting openMenuOnPressAndHold: !messageListItem.precalculatedValues.pageIsSelecting
signal replyToMessage() signal replyToMessage()
signal editMessage() signal editMessage()
signal forwardMessage()
function deleteMessage() {
var chatId = page.chatInformation.id
var messageId = myMessage.id
Remorse.itemAction(messageListItem, qsTr("Message deleted"), function() {
tdLibWrapper.deleteMessages(chatId, [ messageId ]);
})
}
function copyMessageToClipboard() {
Clipboard.text = Functions.getMessageText(myMessage, true, userInformation.id, true)
}
function openContextMenu() {
messageOptionsDrawer.open = false
if (menu) {
openMenu()
} else {
contextMenuLoader.active = true
}
}
function getInteractionText(viewCount, reactions, size, highlightColor) {
var interactionText = "";
if (viewCount > 0) {
interactionText = Emoji.emojify("👁️ ", size) + Functions.getShortenedCount(viewCount);
}
for (var i = 0; i < reactions.length; i++) {
var reaction = reactions[i]
var reactionText = reaction.reaction ? reaction.reaction : (reaction.type && reaction.type.emoji) ? reaction.type.emoji : ""
if (reactionText) {
interactionText += ( "&nbsp;" + Emoji.emojify(reactionText, size) );
if (!chatPage.isPrivateChat) {
var count = Functions.getShortenedCount(reaction.total_count)
interactionText += " "
interactionText += (reaction.is_chosen ? ( "<font color='" + highlightColor + "'><b>" + count + "</b></font>" ) : count)
}
}
}
return interactionText;
}
function openReactions() {
if (messageListItem.chatReactions) {
Debug.log("Using chat reactions")
messageListItem.messageReactions = chatReactions
showItemCompletelyTimer.requestedIndex = index;
showItemCompletelyTimer.start();
} else {
Debug.log("Obtaining message reactions")
tdLibWrapper.getMessageAvailableReactions(messageListItem.chatId, messageListItem.messageId);
}
selectReactionBubble.visible = false;
}
function getContentWidthMultiplier() {
return Functions.isWidescreen(appWindow) ? 0.4 : 1.0
}
onClicked: { onClicked: {
if(messageListItem.precalculatedValues.pageIsSelecting) { if(messageListItem.precalculatedValues.pageIsSelecting) {
page.toggleMessageSelection(myMessage); page.toggleMessageSelection(myMessage);
} else { } else {
if (messageOptionsDrawer.sourceItem !== messageListItem) {
messageOptionsDrawer.open = false
}
// Allow extra context to react to click // Allow extra context to react to click
var extraContent = extraContentLoader.item var extraContent = extraContentLoader.item
if (extraContent && extraContentLoader.contains(mapToItem(extraContentLoader, mouse.x, mouse.y))) { if (extraContent && ("clicked" in extraContent) && (typeof extraContent.clicked === "function") &&
mouseX >= extraContentLoader.x && mouseY >= extraContentLoader.y &&
mouseX < (extraContentLoader.x + extraContentLoader.width) &&
mouseY < (extraContentLoader.y + extraContentLoader.height)) {
extraContent.clicked() extraContent.clicked()
} else if (webPagePreviewLoader.item) {
webPagePreviewLoader.item.clicked()
} }
if (messageListItem.messageReactions) {
messageListItem.messageReactions = null;
selectReactionBubble.visible = false;
} else {
selectReactionBubble.visible = !selectReactionBubble.visible;
elementSelected(index);
}
}
}
onDoubleClicked: {
if (messageListItem.chatReactions) {
Debug.log("Using chat reactions")
messageListItem.messageReactions = chatReactions
showItemCompletelyTimer.requestedIndex = index;
showItemCompletelyTimer.start();
} else {
Debug.log("Obtaining message reactions")
tdLibWrapper.getMessageAvailableReactions(messageListItem.chatId, messageListItem.messageId);
} }
} }
onPressAndHold: { onPressAndHold: {
if (openMenuOnPressAndHold) { if(messageListItem.precalculatedValues.pageIsSelecting) {
openContextMenu() page.selectedMessages = [];
} else {
page.selectedMessages = []
page.state = "" page.state = ""
} else {
contextMenuLoader.active = true;
} }
} }
onMenuOpenChanged: {
// When opening/closing the context menu, we no longer scroll automatically
chatView.manuallyScrolledToBottom = false;
}
Connections {
target: additionalOptionsOpened ? messageOptionsDrawer : null
onOpenChanged: {
if (!messageOptionsDrawer.open) {
additionalOptionsOpened = false
}
}
}
Connections {
target: chatPage
onResetElements: {
messageListItem.messageReactions = null;
selectReactionBubble.visible = false;
}
onElementSelected: {
if (elementIndex !== index) {
selectReactionBubble.visible = false;
}
}
onNavigatedTo: {
if (targetIndex === index) {
messageListItem.wasNavigatedTo = true;
restoreNormalityTimer.start();
}
}
}
Loader { Loader {
id: contextMenuLoader id: contextMenuLoader
active: false active: false
@ -224,50 +81,53 @@ ListItem {
} }
sourceComponent: Component { sourceComponent: Component {
ContextMenu { ContextMenu {
Repeater {
model: (extraContentLoader.item && ("extraContextMenuItems" in extraContentLoader.item)) ?
extraContentLoader.item.extraContextMenuItems : 0
delegate: MenuItem {
visible: modelData.visible
text: modelData.name
onClicked: modelData.action()
}
}
MenuItem { MenuItem {
visible: canReplyToMessage visible: messageListItem.canReplyToMessage
onClicked: replyToMessage() onClicked: messageListItem.replyToMessage()
text: qsTr("Reply to Message") text: qsTr("Reply to Message")
} }
MenuItem { MenuItem {
visible: typeof myMessage.can_be_edited !== "undefined" && myMessage.can_be_edited visible: myMessage.can_be_edited
onClicked: editMessage() onClicked: messageListItem.editMessage()
text: qsTr("Edit Message") text: qsTr("Edit Message")
} }
MenuItem { MenuItem {
onClicked: page.toggleMessageSelection(myMessage) onClicked: {
text: qsTr("Select Message") Clipboard.text = Functions.getMessageText(myMessage, true, false, true);
} }
MenuItem {
visible: showCopyMessageToClipboardMenuItem
onClicked: copyMessageToClipboard()
text: qsTr("Copy Message to Clipboard") text: qsTr("Copy Message to Clipboard")
} }
MenuItem { MenuItem {
visible: showForwardMessageMenuItem
onClicked: forwardMessage()
text: qsTr("Forward Message")
}
MenuItem {
visible: canDeleteMessage && haveSpaceForDeleteMessageMenuItem
onClicked: deleteMessage()
text: qsTr("Delete Message")
}
MenuItem {
visible: (numberOfExtraOptionsOtherThanDeleteMessage > 0) ||
(deleteMessageIsOnlyExtraOption && !haveSpaceForDeleteMessageMenuItem)
onClicked: { onClicked: {
messageOptionsDrawer.myMessage = myMessage; page.toggleMessageSelection(myMessage);
messageOptionsDrawer.userInformation = userInformation;
messageOptionsDrawer.sourceItem = messageListItem
messageOptionsDrawer.additionalItemsModel = additionalItemsModel
messageOptionsDrawer.showCopyMessageToClipboardMenuItem = !showCopyMessageToClipboardMenuItem
messageOptionsDrawer.showForwardMessageMenuItem = !showForwardMessageMenuItem
messageOptionsDrawer.showDeleteMessageMenuItem = canDeleteMessage && !haveSpaceForDeleteMessageMenuItem
messageListItem.additionalOptionsOpened = true;
messageOptionsDrawer.open = true;
} }
text: qsTr("More Options...") text: qsTr("Select Message")
}
MenuItem {
onClicked: {
tdLibWrapper.pinMessage(page.chatInformation.id, messageId)
}
text: qsTr("Pin Message")
visible: canPinMessages()
}
MenuItem {
onClicked: {
var chatId = page.chatInformation.id;
var messageId = messageListItem.messageId;
Remorse.itemAction(messageListItem, qsTr("Message deleted"), function() { tdLibWrapper.deleteMessages(chatId, [ messageId]); })
}
text: qsTr("Delete Message")
visible: myMessage.can_be_deleted_for_all_users || (myMessage.can_be_deleted_only_for_self && myMessage.chat_id === page.myUserId)
} }
} }
} }
@ -276,103 +136,44 @@ ListItem {
Connections { Connections {
target: chatModel target: chatModel
onMessagesReceived: { onMessagesReceived: {
messageBackground.isUnread = index > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage"; messageBackground.isUnread = index > chatModel.getLastReadMessageIndex();
} }
onMessagesIncrementalUpdate: { onMessagesIncrementalUpdate: {
messageBackground.isUnread = index > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage"; messageBackground.isUnread = index > chatModel.getLastReadMessageIndex();
} }
onNewMessageReceived: { onNewMessageReceived: {
messageBackground.isUnread = index > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage"; messageBackground.isUnread = index > chatModel.getLastReadMessageIndex();
} }
onUnreadCountUpdated: { onUnreadCountUpdated: {
messageBackground.isUnread = index > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage"; messageBackground.isUnread = index > chatModel.getLastReadMessageIndex();
} }
onLastReadSentMessageUpdated: { onLastReadSentMessageUpdated: {
Debug.log("[ChatModel] Messages in this chat were read, new last read: ", lastReadSentIndex, ", updating description for index ", index, ", status: ", (index <= lastReadSentIndex)); Debug.log("[ChatModel] Messages in this chat were read, new last read: ", lastReadSentIndex, ", updating description for index ", index, ", status: ", (index <= lastReadSentIndex));
messageDateText.text = getMessageStatusText(myMessage, index, lastReadSentIndex, messageDateText.useElapsed); messageDateText.text = getMessageStatusText(myMessage, index, lastReadSentIndex, messageDateText.useElapsed);
} }
onMessageUpdated: {
if (index === modelIndex) {
Debug.log("[ChatModel] This message was updated, index ", index, ", updating content...");
messageDateText.text = getMessageStatusText(myMessage, index, chatView.lastReadSentIndex, messageDateText.useElapsed);
messageText.text = Emoji.emojify(Functions.getMessageText(myMessage, false, messageListItem.isOwnMessage. false), messageText.font.pixelSize);
}
}
} }
Connections { Connections {
target: tdLibWrapper target: tdLibWrapper
onReceivedMessage: { onReceivedMessage: {
if (messageId === myMessage.reply_to_message_id) { if (messageId === myMessage.reply_to_message_id.toString()) {
messageInReplyToLoader.inReplyToMessage = message; messageInReplyToLoader.inReplyToMessage = message;
} }
} }
onMessageNotFound: {
if (messageId === myMessage.reply_to_message_id) {
messageInReplyToLoader.inReplyToMessageDeleted = true;
}
}
onAvailableReactionsReceived: {
if (messageListItem.messageId === messageId &&
pageStack.currentPage === chatPage) {
Debug.log("Available reactions for this message: " + reactions);
messageListItem.messageReactions = reactions;
showItemCompletelyTimer.requestedIndex = index;
showItemCompletelyTimer.start();
} else {
messageListItem.messageReactions = null;
}
}
onReactionsUpdated: {
chatReactions = tdLibWrapper.getChatReactions(page.chatInformation.id);
}
}
Timer {
id: showItemCompletelyTimer
property int requestedIndex: (chatView.count - 1)
repeat: false
running: false
interval: 200
triggeredOnStart: false
onTriggered: {
Debug.log("Show item completely timer triggered, requested index: " + requestedIndex + ", current index: " + index)
if (requestedIndex === index) {
var p = chatView.contentItem.mapFromItem(reactionsColumn, 0, 0)
if (chatView.contentY > p.y || p.y + reactionsColumn.height > chatView.contentY + chatView.height) {
Debug.log("Moving reactions for item at", requestedIndex, "info the view")
chatView.highlightMoveDuration = -1
chatView.highlightResizeDuration = -1
chatView.scrollToIndex(requestedIndex, height <= chatView.height ? ListView.Contain : ListView.End)
chatView.highlightMoveDuration = 0
chatView.highlightResizeDuration = 0
}
}
}
}
Timer {
id: restoreNormalityTimer
repeat: false
running: false
interval: 1000
triggeredOnStart: false
onTriggered: {
Debug.log("Restore normality for index " + index);
messageListItem.wasNavigatedTo = false;
}
} }
Component.onCompleted: { Component.onCompleted: {
delegateComponentLoadingTimer.start(); delegateComponentLoadingTimer.start();
if (myMessage.reply_to_message_id) {
tdLibWrapper.getMessage(myMessage.reply_in_chat_id ? myMessage.reply_in_chat_id : page.chatInformation.id,
myMessage.reply_to_message_id)
}
}
onMyMessageChanged: { if (myMessage.reply_to_message_id !== 0) {
Debug.log("[ChatModel] This message was updated, index", messageIndex, ", updating content..."); tdLibWrapper.getMessage(page.chatInformation.id, myMessage.reply_to_message_id);
messageDateText.text = getMessageStatusText(myMessage, messageIndex, chatView.lastReadSentIndex, messageDateText.useElapsed);
messageText.text = Emoji.emojify(Functions.getMessageText(myMessage, false, page.myUserId, false), Theme.fontSizeSmall);
if (webPagePreviewLoader.item) {
webPagePreviewLoader.item.webPageData = myMessage.content.web_page;
} }
} }
@ -382,10 +183,10 @@ ListItem {
repeat: false repeat: false
running: false running: false
onTriggered: { onTriggered: {
if (messageListItem.hasContentComponent) { if (typeof myMessage.content !== "undefined") {
var type = myMessage.content["@type"]; if (messageListItem.extraContentComponentName !== "") {
extraContentLoader.setSource( extraContentLoader.setSource(
"../components/messageContent/" + type.charAt(0).toUpperCase() + type.substring(1) + ".qml", "../components/" +messageListItem.extraContentComponentName +".qml",
{ {
messageListItem: messageListItem messageListItem: messageListItem
}) })
@ -396,15 +197,13 @@ ListItem {
} }
} }
} }
}
Row { Row {
id: messageTextRow id: messageTextRow
spacing: Theme.paddingSmall spacing: Theme.paddingSmall
width: precalculatedValues.entryWidth width: precalculatedValues.entryWidth
anchors.horizontalCenter: Functions.isWidescreen(appWindow) ? undefined : parent.horizontalCenter anchors.centerIn: parent
anchors.left: Functions.isWidescreen(appWindow) ? parent.left : undefined
y: Theme.paddingSmall
anchors.leftMargin: Functions.isWidescreen(appWindow) ? Theme.paddingMedium : undefined
Loader { Loader {
id: profileThumbnailLoader id: profileThumbnailLoader
@ -417,16 +216,16 @@ ListItem {
sourceComponent: Component { sourceComponent: Component {
ProfileThumbnail { ProfileThumbnail {
id: messagePictureThumbnail id: messagePictureThumbnail
photoData: messageListItem.isAnonymous ? ((typeof page.chatInformation.photo !== "undefined") ? page.chatInformation.photo.small : {}) : ((typeof messageListItem.userInformation.profile_photo !== "undefined") ? messageListItem.userInformation.profile_photo.small : ({})) photoData: (typeof messageListItem.userInformation.profile_photo !== "undefined") ? messageListItem.userInformation.profile_photo.small : ({})
replacementStringHint: userText.text replacementStringHint: userText.text
width: Theme.itemSizeSmall width: Theme.itemSizeSmall
height: Theme.itemSizeSmall height: Theme.itemSizeSmall
visible: precalculatedValues.showUserInfo visible: precalculatedValues.showUserInfo
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
enabled: !(messageListItem.precalculatedValues.pageIsSelecting || messageListItem.isAnonymous) enabled: !messageListItem.precalculatedValues.pageIsSelecting
onClicked: { onClicked: {
tdLibWrapper.createPrivateChat(messageListItem.userInformation.id, "openDirectly"); tdLibWrapper.createPrivateChat(messageListItem.userInformation.id);
} }
} }
} }
@ -444,16 +243,16 @@ ListItem {
anchors { anchors {
left: parent.left left: parent.left
leftMargin: page.isPrivateChat ? (messageListItem.isOwnMessage ? precalculatedValues.pageMarginDouble : 0) : 0 //левый марджин для собственных сообщений в приватных чатах. В остальных на полную ширину leftMargin: messageListItem.isOwnMessage ? precalculatedValues.pageMarginDouble : 0
verticalCenter: parent.verticalCenter verticalCenter: parent.verticalCenter
} }
height: messageTextColumn.height + precalculatedValues.paddingMediumDouble height: messageTextColumn.height + precalculatedValues.paddingMediumDouble
width: precalculatedValues.backgroundWidth width: precalculatedValues.backgroundWidth
property bool isUnread: index > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage" property bool isUnread: index > chatModel.getLastReadMessageIndex()
color: Theme.colorScheme === Theme.LightOnDark ? (isOwnMessage ? Theme.highlightBackgroundColor : (isUnread ? Theme.secondaryHighlightColor : Theme.secondaryColor)) : (isOwnMessage ? Theme.highlightBackgroundColor : (isUnread ? Theme.backgroundGlowColor : Theme.overlayBackgroundColor)) color: isUnread ? Theme.secondaryHighlightColor : Theme.secondaryColor
radius: parent.width / 50 radius: parent.width / 50
opacity: isUnread ? 0.5 : 0.2 opacity: isUnread ? 0.5 : 0.2
visible: appSettings.showStickersAsImages || (myMessage.content['@type'] !== "messageSticker" && myMessage.content['@type'] !== "messageAnimatedEmoji") visible: appSettings.showStickersAsImages || myMessage.content['@type'] !== "messageSticker"
Behavior on color { ColorAnimation { duration: 200 } } Behavior on color { ColorAnimation { duration: 200 } }
Behavior on opacity { FadeAnimation {} } Behavior on opacity { FadeAnimation {} }
} }
@ -471,7 +270,7 @@ ListItem {
id: userText id: userText
width: parent.width width: parent.width
text: messageListItem.isOwnMessage ? qsTr("You") : Emoji.emojify( myMessage['@type'] === "sponsoredMessage" ? tdLibWrapper.getChat(myMessage.sponsor_chat_id).title : ( messageListItem.isAnonymous ? page.chatInformation.title : Functions.getUserName(messageListItem.userInformation) ), font.pixelSize) text: messageListItem.isOwnMessage ? qsTr("You") : Emoji.emojify(Functions.getUserName(messageListItem.userInformation), font.pixelSize)
font.pixelSize: Theme.fontSizeExtraSmall font.pixelSize: Theme.fontSizeExtraSmall
font.weight: Font.ExtraBold font.weight: Font.ExtraBold
color: messageListItem.textColor color: messageListItem.textColor
@ -479,28 +278,23 @@ ListItem {
truncationMode: TruncationMode.Fade truncationMode: TruncationMode.Fade
textFormat: Text.StyledText textFormat: Text.StyledText
horizontalAlignment: messageListItem.textAlign horizontalAlignment: messageListItem.textAlign
visible: messageListItem.isOwnMessage ? false : (precalculatedValues.showUserInfo || myMessage['@type'] === "sponsoredMessage") visible: precalculatedValues.showUserInfo
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
enabled: !(messageListItem.precalculatedValues.pageIsSelecting || messageListItem.isAnonymous) enabled: !messageListItem.precalculatedValues.pageIsSelecting
onClicked: { onClicked: {
tdLibWrapper.createPrivateChat(messageListItem.userInformation.id, "openDirectly"); tdLibWrapper.createPrivateChat(messageListItem.userInformation.id);
} }
} }
} }
MessageViaLabel {
message: myMessage
}
Loader { Loader {
id: messageInReplyToLoader id: messageInReplyToLoader
active: typeof myMessage.reply_to_message_id !== "undefined" && myMessage.reply_to_message_id !== 0 active: myMessage.reply_to_message_id !== 0
width: parent.width width: parent.width
// text height ~= 1,28*font.pixelSize // text height ~= 1,28*font.pixelSize
height: active ? precalculatedValues.messageInReplyToHeight : 0 height: active ? precalculatedValues.messageInReplyToHeight : 0
property var inReplyToMessage; property var inReplyToMessage;
property bool inReplyToMessageDeleted: false;
sourceComponent: Component { sourceComponent: Component {
Item { Item {
width: messageInReplyToRow.width width: messageInReplyToRow.width
@ -508,31 +302,14 @@ ListItem {
InReplyToRow { InReplyToRow {
id: messageInReplyToRow id: messageInReplyToRow
myUserId: page.myUserId myUserId: page.myUserId
layer.enabled: messageInReplyToMouseArea.pressed && !messageListItem.highlighted && !messageListItem.menuOpen visible: true
layer.effect: PressEffect { source: messageInReplyToRow }
inReplyToMessage: messageInReplyToLoader.inReplyToMessage inReplyToMessage: messageInReplyToLoader.inReplyToMessage
inReplyToMessageDeleted: messageInReplyToLoader.inReplyToMessageDeleted
} }
MouseArea { MouseArea {
id: messageInReplyToMouseArea
anchors.fill: parent anchors.fill: parent
onClicked: { onClicked: {
if (precalculatedValues.pageIsSelecting) { messageOverlayLoader.overlayMessage = messageInReplyToRow.inReplyToMessage;
page.toggleMessageSelection(myMessage) messageOverlayLoader.active = true;
} else {
messageOptionsDrawer.open = false
if(appSettings.goToQuotedMessage) {
chatPage.showMessage(messageInReplyToRow.inReplyToMessage.id, true)
} else {
messageOverlayLoader.active = true
messageOverlayLoader.overlayMessage = messageInReplyToRow.inReplyToMessage
}
}
}
onPressAndHold: {
if (openMenuOnPressAndHold) {
openContextMenu()
}
} }
} }
} }
@ -552,12 +329,11 @@ ListItem {
width: parent.width width: parent.width
Component.onCompleted: { Component.onCompleted: {
var originType = myMessage.forward_info.origin["@type"] if (myMessage.forward_info.origin["@type"] === "messageForwardOriginChannel") {
if (originType === "messageOriginChannel" || originType === "messageForwardOriginChannel") {
var otherChatInformation = tdLibWrapper.getChat(myMessage.forward_info.origin.chat_id); var otherChatInformation = tdLibWrapper.getChat(myMessage.forward_info.origin.chat_id);
forwardedThumbnail.photoData = (typeof otherChatInformation.photo !== "undefined") ? otherChatInformation.photo.small : {}; forwardedThumbnail.photoData = (typeof otherChatInformation.photo !== "undefined") ? otherChatInformation.photo.small : {};
forwardedChannelText.text = Emoji.emojify(otherChatInformation.title, Theme.fontSizeExtraSmall); forwardedChannelText.text = Emoji.emojify(otherChatInformation.title, Theme.fontSizeExtraSmall);
} else if (originType === "messageOriginUser" || originType === "messageForwardOriginUser") { } else if (myMessage.forward_info.origin["@type"] === "messageForwardOriginUser") {
var otherUserInformation = tdLibWrapper.getUserInformation(myMessage.forward_info.origin.sender_user_id); var otherUserInformation = tdLibWrapper.getUserInformation(myMessage.forward_info.origin.sender_user_id);
forwardedThumbnail.photoData = (typeof otherUserInformation.profile_photo !== "undefined") ? otherUserInformation.profile_photo.small : {}; forwardedThumbnail.photoData = (typeof otherUserInformation.profile_photo !== "undefined") ? otherUserInformation.profile_photo.small : {};
forwardedChannelText.text = Emoji.emojify(Functions.getUserName(otherUserInformation), Theme.fontSizeExtraSmall); forwardedChannelText.text = Emoji.emojify(Functions.getUserName(otherUserInformation), Theme.fontSizeExtraSmall);
@ -603,46 +379,35 @@ ListItem {
Text { Text {
id: messageText id: messageText
width: parent.width width: parent.width
text: Emoji.emojify(Functions.getMessageText(myMessage, false, page.myUserId, false), Theme.fontSizeMedium) text: Emoji.emojify(Functions.getMessageText(myMessage, false, messageListItem.isOwnMessage, false), font.pixelSize)
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: messageListItem.textColor color: messageListItem.textColor
wrapMode: Text.Wrap wrapMode: Text.Wrap
textFormat: Text.StyledText textFormat: Text.StyledText
onLinkActivated: { onLinkActivated: {
var chatCommand = Functions.handleLink(link); Functions.handleLink(link);
if(chatCommand) {
tdLibWrapper.sendTextMessage(chatInformation.id, chatCommand);
}
} }
horizontalAlignment: messageListItem.textAlign horizontalAlignment: messageListItem.textAlign
linkColor: Theme.highlightColor linkColor: Theme.highlightColor
visible: (text !== "") visible: (text !== "")
} }
Loader {
id: sponsoredMessageButtonLoader
active: myMessage['@type'] === "sponsoredMessage"
asynchronous: true
width: parent.width
height: (status === Loader.Ready) ? item.implicitHeight : myMessage['@type'] === "sponsoredMessage" ? Theme.itemSizeMedium : 0
sourceComponent: Component {
SponsoredMessage {
sponsoredMessageData: myMessage
width: parent.width
}
}
}
Loader { Loader {
id: webPagePreviewLoader id: webPagePreviewLoader
active: false active: false
asynchronous: true asynchronous: true
width: parent.width * getContentWidthMultiplier() width: parent.width
height: (status === Loader.Ready) ? item.implicitHeight : myMessage.content.web_page ? precalculatedValues.webPagePreviewHeight : 0 height: typeof myMessage.content.web_page !== "undefined" ? precalculatedValues.webPagePreviewHeight : 0
sourceComponent: Component { sourceComponent: Component {
id: webPagePreviewComponent
WebPagePreview { WebPagePreview {
id: webPagePreview
onImplicitHeightChanged: {
webPagePreviewLoader.height = webPagePreview.implicitHeight;
}
webPageData: myMessage.content.web_page webPageData: myMessage.content.web_page
width: parent.width width: parent.width
highlighted: messageListItem.highlighted highlighted: messageListItem.highlighted
@ -652,9 +417,9 @@ ListItem {
Loader { Loader {
id: extraContentLoader id: extraContentLoader
width: parent.width * getContentWidthMultiplier() width: parent.width
asynchronous: true asynchronous: true
height: item ? item.height : (messageListItem.hasContentComponent ? chatView.getContentComponentHeight(model.content_type, myMessage.content, width) : 0) height: item ? item.height : (messageListItem.extraContentComponentName !== "" ? chatView.getContentComponentHeight(messageListItem.extraContentComponentName, myMessage.content, width) : 0)
} }
Binding { Binding {
@ -664,15 +429,6 @@ ListItem {
value: messageListItem.highlighted value: messageListItem.highlighted
} }
Loader {
id: replyMarkupLoader
width: parent.width
height: active ? (myMessage.reply_markup.rows.length * (Theme.itemSizeSmall + Theme.paddingSmall) - Theme.paddingSmall) : 0
asynchronous: true
active: !!myMessage.reply_markup && myMessage.reply_markup.rows
source: Qt.resolvedUrl("ReplyMarkupButtons.qml")
}
Timer { Timer {
id: messageDateUpdater id: messageDateUpdater
interval: 60000 interval: 60000
@ -683,6 +439,7 @@ ListItem {
} }
} }
Text { Text {
width: parent.width width: parent.width
@ -703,24 +460,6 @@ ListItem {
} }
} }
Loader {
id: interactionLoader
width: parent.width
asynchronous: true
active: ( chatPage.isChannel && messageViewCount > 0 ) || reactions.length > 0
height: ( ( chatPage.isChannel && messageViewCount > 0 ) || reactions.length > 0 ) ? ( Theme.fontSizeExtraSmall + Theme.paddingSmall ) : 0
sourceComponent: Component {
Label {
text: getInteractionText(messageViewCount, reactions, font.pixelSize, Theme.highlightColor)
width: parent.width
font.pixelSize: Theme.fontSizeTiny
color: messageListItem.isOwnMessage ? Theme.secondaryHighlightColor : Theme.secondaryColor
horizontalAlignment: messageListItem.textAlign
textFormat: Text.StyledText
maximumLineCount: 1
elide: Text.ElideRight
}
}
} }
} }
@ -728,60 +467,3 @@ ListItem {
} }
} }
Column {
id: reactionsColumn
width: parent.width - ( 2 * Theme.horizontalPageMargin )
anchors.top: messageTextRow.bottom
anchors.topMargin: Theme.paddingSmall
anchors.horizontalCenter: parent.horizontalCenter
visible: messageListItem.messageReactions ? ( messageListItem.messageReactions.length > 0 ? true : false ) : false
opacity: messageListItem.messageReactions ? ( messageListItem.messageReactions.length > 0 ? 1 : 0 ) : 0
Behavior on opacity { NumberAnimation {} }
spacing: Theme.paddingMedium
Flickable {
width: parent.width
height: reactionsResultRow.height + Theme.paddingSmall
anchors.horizontalCenter: parent.horizontalCenter
contentWidth: reactionsResultRow.width
clip: true
Row {
id: reactionsResultRow
spacing: Theme.paddingMedium
Repeater {
model: messageListItem.messageReactions
Item {
height: singleReactionRow.height
width: singleReactionRow.width
Row {
id: singleReactionRow
spacing: Theme.paddingSmall
Image {
id: emojiPicture
source: Emoji.getEmojiPath(modelData)
width: status === Image.Ready ? Theme.fontSizeLarge : 0
height: Theme.fontSizeLarge
}
}
MouseArea {
anchors.fill: parent
onClicked: {
tdLibWrapper.setMessageReaction(messageListItem.chatId, messageListItem.messageId, modelData);
messageListItem.messageReactions = null;
}
}
}
}
}
}
}
}

View file

@ -20,15 +20,12 @@ import QtQuick 2.6
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import "../js/twemoji.js" as Emoji import "../js/twemoji.js" as Emoji
import "../js/functions.js" as Functions import "../js/functions.js" as Functions
import "../js/debug.js" as Debug
Item { Item {
id: messageListItem id: messageListItem
property var myMessage: display property var myMessage: display
property bool senderIsUser: myMessage.sender_id["@type"] === "messageSenderUser" property var userInformation: tdLibWrapper.getUserInformation(myMessage.sender.user_id)
property var userInformation: senderIsUser ? tdLibWrapper.getUserInformation(myMessage.sender_id.user_id) : null property bool isOwnMessage: chatPage.myUserId === myMessage.sender.user_id
property bool isOwnMessage: senderIsUser && chatPage.myUserId === myMessage.sender_id.user_id
property var linkedMessage
height: backgroundRectangle.height + Theme.paddingMedium height: backgroundRectangle.height + Theme.paddingMedium
Rectangle { Rectangle {
@ -36,7 +33,7 @@ Item {
anchors.centerIn: parent anchors.centerIn: parent
height: messageText.height + Theme.paddingMedium * 2 height: messageText.height + Theme.paddingMedium * 2
width: Math.min(messageText.implicitWidth, messageText.contentWidth) + Theme.paddingMedium * 2 width: Math.min(messageText.implicitWidth, messageText.contentWidth) + Theme.paddingMedium * 2
color: Theme.colorScheme === Theme.LightOnDark ? Theme.rgba(Theme.secondaryColor, 0.1) : Theme.rgba(Theme.overlayBackgroundColor, 0.1) color: Theme.rgba(Theme.secondaryColor, 0.1)
radius: parent.width / 50 radius: parent.width / 50
} }
Text { Text {
@ -46,43 +43,11 @@ Item {
color: Theme.highlightColor color: Theme.highlightColor
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
font.pixelSize: Theme.fontSizeExtraSmall font.pixelSize: Theme.fontSizeExtraSmall
property string messageContentText: Functions.getMessageText(messageListItem.myMessage, false, chatPage.myUserId, false) text: "<a style=\"text-decoration: none; font-weight: bold; color:"+Theme.primaryColor+"\" href=\"userId://" + messageListItem.userInformation.id + "\">" + (!messageListItem.isOwnMessage ? Emoji.emojify(Functions.getUserName(messageListItem.userInformation), font.pixelSize) : qsTr("You")) + "</a> " + Emoji.emojify(Functions.getMessageText(messageListItem.myMessage, false, messageListItem.isOwnMessage, false), font.pixelSize)
text: (messageListItem.senderIsUser
? "<a style=\"text-decoration: none; font-weight: bold; color:"+Theme.primaryColor+"\" href=\"userId://" + messageListItem.userInformation.id + "\">" + (!messageListItem.isOwnMessage ? Emoji.emojify(Functions.getUserName(messageListItem.userInformation), font.pixelSize) : qsTr("You")) + "</a> "
: "<a style=\"text-decoration: none; font-weight: bold; color:"+Theme.secondaryHighlightColor+"\">" + Emoji.emojify(chatPage.chatInformation.title || "") + "</a> ")
+ Emoji.emojify(messageContentText, font.pixelSize)
textFormat: Text.RichText textFormat: Text.RichText
wrapMode: Text.WrapAtWordBoundaryOrAnywhere wrapMode: Text.WrapAtWordBoundaryOrAnywhere
onLinkActivated: { onLinkActivated: {
if(link === "linkedmessage" && linkedMessage) {
messageOverlayLoader.overlayMessage = linkedMessage;
messageOverlayLoader.active = true;
} else {
Functions.handleLink(link); Functions.handleLink(link);
} }
}
}
Loader {
id: gameScoreInfoLoader
active: myMessage.content["@type"] === "messageGameScore"
asynchronous: true
sourceComponent: Component {
Connections {
target: tdLibWrapper
onReceivedMessage: {
if(chatId === chatPage.chatInformation.id && messageId === myMessage.content.game_message_id) {
messageListItem.linkedMessage = message;
messageText.messageContentText = messageListItem.isOwnMessage ?
qsTr("scored %Ln points in %2", "myself", myMessage.content.score).arg("<a href=\"linkedmessage\" style=\"text-decoration: none; color:"+Theme.primaryColor+"\">"+message.content.game.title+"</a>") :
qsTr("scored %Ln points in %2", "", myMessage.content.score).arg("<a href=\"linkedmessage\" style=\"text-decoration: none; color:"+Theme.primaryColor+"\" >"+message.content.game.title+"</a>");
}
}
Component.onCompleted: {
tdLibWrapper.getMessage(chatPage.chatInformation.id, myMessage.content.game_message_id);
}
}
}
} }
} }

View file

@ -18,10 +18,9 @@
*/ */
import QtQuick 2.6 import QtQuick 2.6
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import "./messageContent" import "../components"
import "../js/functions.js" as Functions import "../js/functions.js" as Functions
import "../js/twemoji.js" as Emoji import "../js/twemoji.js" as Emoji
import "../js/debug.js" as Debug
Flickable { Flickable {
id: messageOverlayFlickable id: messageOverlayFlickable
@ -32,21 +31,19 @@ Flickable {
property var overlayMessage; property var overlayMessage;
property bool showHeader: true property bool showHeader: true
readonly property var userInformation: tdLibWrapper.getUserInformation(overlayMessage.sender_id.user_id); readonly property var userInformation: tdLibWrapper.getUserInformation(overlayMessage.sender.user_id);
readonly property bool isOwnMessage: tdLibWrapper.getUserInformation().id === overlayMessage.sender_id.user_id; readonly property bool isOwnMessage: tdLibWrapper.getUserInformation().id === overlayMessage.sender.user_id;
readonly property bool isAnonymous: overlayMessage.sender_id["@type"] === "messageSenderChat" readonly property string extraContentComponentName: (typeof overlayMessage.content !== "undefined" && typeof chatView.contentComponentNames[overlayMessage.content['@type']] !== "undefined" )
property bool hasContentComponent: overlayMessage.content && chatView.delegateMessagesContent.indexOf(overlayMessage.content['@type']) > -1 ? chatView.contentComponentNames[overlayMessage.content['@type']] : ""
signal requestClose; signal requestClose;
function getOriginalAuthor(forwardInformation, fontSize) { function getOriginalAuthor(forwardInformation, fontSize) {
switch (forwardInformation.origin["@type"]) { switch (forwardInformation.origin["@type"]) {
case "messageOriginChannel":
case "messageForwardOriginChannel": case "messageForwardOriginChannel":
var otherChatInformation = tdLibWrapper.getChat(forwardInformation.origin.chat_id); var otherChatInformation = tdLibWrapper.getChat(forwardInformation.origin.chat_id);
return Emoji.emojify(otherChatInformation.title, fontSize); return Emoji.emojify(otherChatInformation.title, fontSize);
case "messageOriginUser":
case "messageForwardOriginUser": case "messageForwardOriginUser":
var otherUserInformation = tdLibWrapper.getUserInformation(forwardInformation.origin.sender_id.user_id); var otherUserInformation = tdLibWrapper.getUserInformation(forwardInformation.origin.sender.user_id);
return Emoji.emojify(Functions.getUserName(otherUserInformation), fontSize); return Emoji.emojify(Functions.getUserName(otherUserInformation), fontSize);
default: default:
return Emoji.emojify(forwardInformation.origin.sender_name, fontSize); return Emoji.emojify(forwardInformation.origin.sender_name, fontSize);
@ -63,18 +60,21 @@ Flickable {
repeat: false repeat: false
running: false running: false
onTriggered: { onTriggered: {
if (messageOverlayFlickable.hasContentComponent) { if (typeof overlayMessage.content !== "undefined") {
var type = overlayMessage.content["@type"]; if (messageOverlayFlickable.extraContentComponentName !== "") {
overlayExtraContentLoader.setSource( overlayExtraContentLoader.setSource(
"../components/messageContent/" + type.charAt(0).toUpperCase() + type.substring(1) + ".qml", "../components/" + messageOverlayFlickable.extraContentComponentName + ".qml",
{ {
overlayFlickable: messageOverlayFlickable overlayFlickable: messageOverlayFlickable
}) })
} else if(overlayMessage.content && overlayMessage.content.web_page) { } else {
if (typeof overlayMessage.content.web_page !== "undefined") {
overlayWebPagePreviewLoader.active = true; overlayWebPagePreviewLoader.active = true;
} }
} }
} }
}
}
Rectangle { Rectangle {
id: messageContentBackground id: messageContentBackground
@ -104,7 +104,7 @@ Flickable {
spacing: Theme.paddingMedium spacing: Theme.paddingMedium
ProfileThumbnail { ProfileThumbnail {
id: overlayMessagePictureThumbnail id: overlayMessagePictureThumbnail
photoData: messageOverlayFlickable.isAnonymous ? ((typeof chatPage.chatInformation.photo !== "undefined") ? chatPage.chatInformation.photo.small : {}) : ((typeof messageOverlayFlickable.userInformation.profile_photo !== "undefined") ? messageOverlayFlickable.userInformation.profile_photo.small : ({})) photoData: (typeof messageOverlayFlickable.userInformation.profile_photo !== "undefined") ? messageOverlayFlickable.userInformation.profile_photo.small : ({})
replacementStringHint: overlayMessageUserText.text replacementStringHint: overlayMessageUserText.text
width: Theme.itemSizeLarge width: Theme.itemSizeLarge
height: Theme.itemSizeLarge height: Theme.itemSizeLarge
@ -114,7 +114,7 @@ Flickable {
width: parent.width - overlayMessagePictureThumbnail.width width: parent.width - overlayMessagePictureThumbnail.width
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: messageOverlayFlickable.isOwnMessage ? qsTr("You") : Emoji.emojify(messageOverlayFlickable.isAnonymous ? chatPage.chatInformation.title : Functions.getUserName(messageOverlayFlickable.userInformation), font.pixelSize) text: messageOverlayFlickable.isOwnMessage ? qsTr("You") : Emoji.emojify(Functions.getUserName(messageOverlayFlickable.userInformation), font.pixelSize)
font.pixelSize: Theme.fontSizeExtraLarge font.pixelSize: Theme.fontSizeExtraLarge
font.weight: Font.ExtraBold font.weight: Font.ExtraBold
maximumLineCount: 1 maximumLineCount: 1
@ -123,10 +123,6 @@ Flickable {
} }
} }
MessageViaLabel {
message: overlayMessage
}
Text { Text {
id: overlayForwardedInfoText id: overlayForwardedInfoText
width: parent.width width: parent.width
@ -142,7 +138,7 @@ Flickable {
Text { Text {
id: overlayMessageText id: overlayMessageText
width: parent.width width: parent.width
text: Emoji.emojify(Functions.getMessageText(overlayMessage, false, tdLibWrapper.getUserInformation().id, false), font.pixelSize) text: Emoji.emojify(Functions.getMessageText(overlayMessage, false, messageOverlayFlickable.isOwnMessage, false), font.pixelSize)
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
color: Theme.primaryColor color: Theme.primaryColor
wrapMode: Text.Wrap wrapMode: Text.Wrap
@ -182,16 +178,6 @@ Flickable {
asynchronous: true asynchronous: true
} }
Loader {
id: replyMarkupLoader
property var myMessage: overlayMessage
width: parent.width
height: active ? (overlayMessage.reply_markup.rows.length * (Theme.itemSizeSmall + Theme.paddingSmall) - Theme.paddingSmall) : 0
asynchronous: true
active: !!overlayMessage.reply_markup && myMessage.reply_markup.rows
source: Qt.resolvedUrl("ReplyMarkupButtons.qml")
}
Timer { Timer {
id: messageDateUpdater id: messageDateUpdater
interval: 60000 interval: 60000

View file

@ -1,49 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import "../js/functions.js" as Functions
import "../js/twemoji.js" as Emoji
Loader {
id: botUserLoader
active: !!message.via_bot_user_id
width: parent.width
asynchronous: true
sourceComponent: Label {
property var botUserInformation: tdLibWrapper.getUserInformation(message.via_bot_user_id)
color: Theme.secondaryColor
font.pixelSize: Theme.fontSizeExtraSmall
text: qsTr("via %1", "message posted via bot user").arg("<a style=\"text-decoration: none; font-weight: bold; color:"+Theme.primaryColor+"\" href=\"userId://" + message.via_bot_user_id + "\">@" + Emoji.emojify(botUserInformation.usernames.editable_username, font.pixelSize)+"</a>")
textFormat: Text.RichText
truncationMode: TruncationMode.Fade
onLinkActivated: {
if(link === "userId://" + message.via_bot_user_id && botUserInformation.type.is_inline) {
newMessageTextField.text = "@"+botUserInformation.usernames.editable_username+" "
newMessageTextField.cursorPosition = newMessageTextField.text.length
lostFocusTimer.start();
}
else {
Functions.handleLink(link);
}
}
}
property var message
}

View file

@ -1,78 +0,0 @@
/*
Copyright (C) 2020 Slava Monich and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.0
import Sailfish.Silica 1.0
import "../js/twemoji.js" as Emoji
// Combination of maximumLineCount and TruncationMode.Elide (or Fade) breaks
// Emoji image alignment, pushing the image down. This one aligns the image
// correctly on its line.
Label {
property string rawText
property int maxLineCount
wrapMode: Text.Wrap
textFormat: Text.StyledText
truncationMode: TruncationMode.Elide
// lineCount is unreliable for StyledText with images and line breaks
readonly property int fontSize: font.pixelSize
readonly property int actualLineHeight: (text === rawText) ? fontSize : (fontSize * 6 / 5)
readonly property int actualLineCount: Math.floor(implicitHeight/actualLineHeight)
Component.onCompleted: refitText()
onFontSizeChanged: refitText()
onWidthChanged: refitText()
onRawTextChanged: refitText()
onMaxLineCountChanged: refitText()
function emojify(str) {
return Emoji.emojify(str, fontSize)
}
function refitText() {
text = emojify(rawText)
if (maxLineCount > 0) {
var divisor = 1
var max = rawText.length
var min = max
while (actualLineCount > maxLineCount && divisor < rawText.length) {
max = min
divisor++
min = rawText.length/divisor
text = emojify(rawText.substr(0, min) + "…")
}
while (min < max) {
var mid = Math.floor((min + max)/2)
if (mid === min) {
text = emojify(rawText.substr(0, min) + "…")
break
} else {
text = emojify(rawText.substr(0, mid) + "…")
if (actualLineCount > maxLineCount) {
max = mid
} else {
min = mid
}
}
}
}
}
}

View file

@ -1,7 +1,6 @@
import QtQuick 2.6 import QtQuick 2.6
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0 import WerkWolf.Fernschreiber 1.0
import "../js/functions.js" as Functions
ListItem { ListItem {
id: chatListViewItem id: chatListViewItem
@ -12,32 +11,36 @@ ListItem {
property alias tertiaryText: tertiaryText //usually last message date property alias tertiaryText: tertiaryText //usually last message date
property int unreadCount: 0 property int unreadCount: 0
property int unreadMentionCount: 0
property int unreadReactionCount: 0
property bool isSecret: false property bool isSecret: false
property bool isVerified: false property bool isVerified: false
property bool isMarkedAsUnread: false
property bool isPinned: false
property bool isMuted: false
property alias pictureThumbnail: pictureThumbnail property alias pictureThumbnail: pictureThumbnail
contentHeight: Theme.itemSizeExtraLarge contentHeight: mainRow.height + separator.height + 2 * Theme.paddingMedium
contentWidth: parent.width contentWidth: parent.width
Column {
ShaderEffectSource { id: mainColumn
id: pictureItem width: parent.width - ( 2 * Theme.horizontalPageMargin )
height: Theme.itemSizeLarge spacing: Theme.paddingSmall
width: height
anchors { anchors {
left: parent.left horizontalCenter: parent.horizontalCenter
leftMargin: Theme.horizontalPageMargin
verticalCenter: parent.verticalCenter verticalCenter: parent.verticalCenter
} }
sourceItem: Item { Row {
width: pictureItem.width id: mainRow
height: pictureItem.width height: contentColumn.height
spacing: Theme.paddingMedium
Column {
id: pictureColumn
width: contentColumn.height - Theme.paddingSmall
height: contentColumn.height - Theme.paddingSmall
anchors.verticalCenter: parent.verticalCenter
Item {
width: parent.width
height: parent.width
ProfileThumbnail { ProfileThumbnail {
id: pictureThumbnail id: pictureThumbnail
@ -46,54 +49,33 @@ ListItem {
height: parent.width height: parent.width
} }
Rectangle {
id: chatPinnedBackground
color: Theme.rgba(Theme.overlayBackgroundColor, Theme.opacityFaint)
width: Theme.fontSizeLarge
height: Theme.fontSizeLarge
anchors.top: parent.top
radius: parent.width / 2
visible: chatListViewItem.isPinned
}
Icon {
source: "../../images/icon-s-pin.svg"
height: Theme.iconSizeExtraSmall
width: Theme.iconSizeExtraSmall
highlighted: chatListViewItem.highlighted
sourceSize: Qt.size(Theme.iconSizeExtraSmall, Theme.iconSizeExtraSmall)
anchors.centerIn: chatPinnedBackground
visible: chatListViewItem.isPinned
}
Rectangle { Rectangle {
id: chatSecretBackground id: chatSecretBackground
color: Theme.rgba(Theme.overlayBackgroundColor, Theme.opacityFaint) color: Theme.overlayBackgroundColor
width: Theme.fontSizeLarge width: Theme.fontSizeExtraLarge
height: Theme.fontSizeLarge height: Theme.fontSizeExtraLarge
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
radius: parent.width / 2 radius: parent.width / 2
visible: chatListViewItem.isSecret visible: chatListViewItem.isSecret
} }
Icon { Image {
source: "image://theme/icon-s-secure" source: "image://theme/icon-s-secure"
height: Theme.iconSizeExtraSmall height: Theme.fontSizeMedium
width: Theme.iconSizeExtraSmall width: Theme.fontSizeMedium
highlighted: chatListViewItem.highlighted
anchors.centerIn: chatSecretBackground anchors.centerIn: chatSecretBackground
visible: chatListViewItem.isSecret visible: chatListViewItem.isSecret
} }
Rectangle { Rectangle {
id: chatUnreadMessagesCountBackground id: chatUnreadMessagesCountBackground
color: isMuted ? ((Theme.colorScheme === Theme.DarkOnLight) ? "lightgray" : "dimgray") : Theme.highlightBackgroundColor color: Theme.highlightBackgroundColor
width: chatUnreadMessagesCount.width + Theme.fontSizeLarge / 2 width: Theme.fontSizeLarge
height: Theme.fontSizeLarge height: Theme.fontSizeLarge
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
radius: parent.width / 2 radius: parent.width / 2
visible: chatListViewItem.unreadCount > 0 || chatListViewItem.isMarkedAsUnread visible: chatListViewItem.unreadCount > 0
} }
Text { Text {
@ -102,54 +84,16 @@ ListItem {
font.bold: true font.bold: true
color: Theme.primaryColor color: Theme.primaryColor
anchors.centerIn: chatUnreadMessagesCountBackground anchors.centerIn: chatUnreadMessagesCountBackground
visible: chatListViewItem.unreadCount > 0 visible: chatUnreadMessagesCountBackground.visible
opacity: isMuted ? Theme.opacityHigh : 1.0 text: chatListViewItem.unreadCount > 99 ? "99+" : chatListViewItem.unreadCount
text: Functions.formatUnreadCount(chatListViewItem.unreadCount)
}
Rectangle {
color: isMuted ? ((Theme.colorScheme === Theme.DarkOnLight) ? "lightgray" : "dimgray") : Theme.highlightBackgroundColor
width: Theme.fontSizeLarge
height: Theme.fontSizeLarge
anchors.right: parent.right
anchors.top: parent.top
radius: parent.width / 2
visible: chatListViewItem.unreadReactionCount > 0 || chatListViewItem.unreadMentionCount > 0
Icon {
source: "image://theme/icon-s-favorite"
height: Theme.iconSizeExtraSmall
width: Theme.iconSizeExtraSmall
highlighted: chatListViewItem.highlighted
anchors.centerIn: parent
visible: chatListViewItem.unreadReactionCount > 0 && !chatListViewItem.unreadMentionCount
}
Text {
font {
pixelSize: Theme.iconSizeExtraSmall
bold: true
}
color: Theme.primaryColor
anchors.centerIn: parent
visible: chatListViewItem.unreadMentionCount > 0
opacity: isMuted ? Theme.opacityHigh : 1.0
text: "@"
}
} }
} }
} }
Column { Column {
id: contentColumn id: contentColumn
anchors { width: mainColumn.width - pictureColumn.width - mainRow.spacing
verticalCenter: parent.verticalCenter spacing: Theme.paddingSmall
left: pictureItem.right
leftMargin: Theme.paddingSmall
right: parent.right
rightMargin: Theme.horizontalPageMargin
}
spacing: Theme.paddingSmall / 2
Row { Row {
id: primaryTextRow id: primaryTextRow
@ -161,29 +105,15 @@ ListItem {
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
truncationMode: TruncationMode.Fade truncationMode: TruncationMode.Fade
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: Math.min(contentColumn.width - (verifiedImage.visible ? (verifiedImage.width + primaryTextRow.spacing) : 0) - (mutedImage.visible ? (mutedImage.width + primaryTextRow.spacing) : 0), implicitWidth) width: Math.min(contentColumn.width - (verifiedImage.visible ? (verifiedImage.width + primaryTextRow.spacing) : 0), implicitWidth)
font.bold: appSettings.highlightUnreadConversations && ( !chatListViewItem.isMuted && (chatListViewItem.unreadCount > 0 || chatListViewItem.isMarkedAsUnread) )
font.italic: appSettings.highlightUnreadConversations && (chatListViewItem.unreadReactionCount > 0)
color: (appSettings.highlightUnreadConversations && (chatListViewItem.unreadCount > 0)) ? Theme.highlightColor : Theme.primaryColor
} }
Image { Image {
id: verifiedImage id: verifiedImage
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
source: chatListViewItem.isVerified ? "../../images/icon-verified.svg" : "" source: chatListViewItem.isVerified ? "../../images/icon-verified.svg" : ""
sourceSize: Qt.size(Theme.iconSizeExtraSmall, Theme.iconSizeExtraSmall) sourceSize.width: Theme.iconSizeExtraSmall
width: Theme.iconSizeSmall width: Theme.iconSizeExtraSmall
height: Theme.iconSizeSmall
visible: status === Image.Ready
}
Image {
id: mutedImage
anchors.verticalCenter: parent.verticalCenter
source: chatListViewItem.isMuted ? "../js/emoji/1f507.svg" : ""
sourceSize: Qt.size(Theme.iconSizeExtraSmall, Theme.iconSizeExtraSmall)
width: Theme.iconSizeSmall
height: Theme.iconSizeSmall
visible: status === Image.Ready visible: status === Image.Ready
} }
} }
@ -217,12 +147,14 @@ ListItem {
truncationMode: TruncationMode.Fade truncationMode: TruncationMode.Fade
} }
} }
}
}
Separator { Separator {
id: separator id: separator
anchors { anchors {
bottom: parent.bottom top: mainColumn.bottom
bottomMargin: -1 topMargin: Theme.paddingMedium
} }
width: parent.width width: parent.width

View file

@ -33,9 +33,9 @@ Item {
onPinnedMessageChanged: { onPinnedMessageChanged: {
if (pinnedMessage) { if (pinnedMessage) {
Debug.log("[ChatPage] Activating pinned message"); Debug.log("[ChatPage] Activating pinned message");
var messageUserText = (pinnedMessage.sender_id.user_id !== chatPage.myUserId) ? Emoji.emojify(Functions.getUserName(tdLibWrapper.getUserInformation(pinnedMessage.sender_id.user_id)), pinnedMessageUserText.font.pixelSize) : qsTr("You"); var messageUserText = (pinnedMessage.sender.user_id !== chatPage.myUserId) ? Emoji.emojify(Functions.getUserName(tdLibWrapper.getUserInformation(pinnedMessage.sender.user_id)), pinnedMessageUserText.font.pixelSize) : qsTr("You");
pinnedMessageUserText.text = (messageUserText === "" ? qsTr("Pinned Message") : messageUserText ); pinnedMessageUserText.text = (messageUserText === "" ? qsTr("Pinned Message") : messageUserText );
pinnedMessageText.text = Emoji.emojify(Functions.getMessageText(pinnedMessage, true, chatPage.myUserId, false), pinnedMessageText.font.pixelSize); pinnedMessageText.text = Emoji.emojify(Functions.getMessageText(pinnedMessage, true, pinnedMessage.sender.user_id === chatPage.myUserId, false), pinnedMessageText.font.pixelSize);
pinnedMessageItem.visible = true; pinnedMessageItem.visible = true;
} else { } else {
pinnedMessageItem.visible = false; pinnedMessageItem.visible = false;
@ -123,7 +123,7 @@ Item {
id: unpinMessageIconButton id: unpinMessageIconButton
icon.source: "image://theme/icon-m-remove" icon.source: "image://theme/icon-m-remove"
onClicked: { onClicked: {
Remorse.itemAction(pinnedMessageRow, qsTr("Message unpinned"), function() { tdLibWrapper.unpinMessage(chatPage.chatInformation.id, pinnedMessage.id); Remorse.itemAction(pinnedMessageRow, qsTr("Message unpinned"), function() { tdLibWrapper.unpinMessage(chatPage.chatInformation.id);
pinnedMessageItem.requestCloseMessage(); }); pinnedMessageItem.requestCloseMessage(); });
} }

View file

@ -21,13 +21,15 @@ import QtQuick 2.6
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0 import WerkWolf.Fernschreiber 1.0
import "../../js/functions.js" as Functions import "../js/functions.js" as Functions
import "../../js/twemoji.js" as Emoji import "../js/twemoji.js" as Emoji
MessageContentBase { Item {
id: pollMessageComponent id: pollMessageComponent
height: pollColumn.height
property ListItem messageListItem
property MessageOverlayFlickable overlayFlickable
readonly property var rawMessage: messageListItem ? messageListItem.myMessage : overlayFlickable.overlayMessage
readonly property string chatId: rawMessage.chat_id readonly property string chatId: rawMessage.chat_id
readonly property bool isOwnMessage: messageListItem ? messageListItem.isOwnMessage : overlayFlickable.isOwnMessage readonly property bool isOwnMessage: messageListItem ? messageListItem.isOwnMessage : overlayFlickable.isOwnMessage
readonly property string messageId: rawMessage.id readonly property string messageId: rawMessage.id
@ -42,6 +44,9 @@ MessageContentBase {
} }
readonly property bool canAnswer: !hasAnswered && !pollData.is_closed readonly property bool canAnswer: !hasAnswered && !pollData.is_closed
readonly property bool isQuiz: pollData.type['@type'] === "pollTypeQuiz" readonly property bool isQuiz: pollData.type['@type'] === "pollTypeQuiz"
property bool highlighted
width: parent.width
height: pollColumn.height
property list<NamedAction> extraContextMenuItems: [ property list<NamedAction> extraContextMenuItems: [
NamedAction { NamedAction {
visible: !pollData.is_closed && pollMessageComponent.canEdit visible: !pollData.is_closed && pollMessageComponent.canEdit
@ -230,24 +235,6 @@ MessageContentBase {
width: 1 width: 1
height: Theme.paddingSmall height: Theme.paddingSmall
} }
Label {
width: parent.width
wrapMode: Text.Wrap
visible: isQuiz && text.length > 0
text: Emoji.emojify(Functions.enhanceMessageText(pollData.type.explanation) || "", font.pixelSize)
textFormat: Text.StyledText
color: pollMessageComponent.isOwnMessage || pollMessageComponent.highlighted ? Theme.highlightColor : Theme.primaryColor
font.pixelSize: Theme.fontSizeExtraSmall
leftPadding: Theme.iconSizeSmall
bottomPadding: Theme.paddingSmall
Icon {
source: "image://theme/icon-s-high-importance"
asynchronous: true
width: Theme.iconSizeExtraSmall
height: Theme.iconSizeExtraSmall
anchors.verticalCenter: parent.verticalCenter
}
}
Item { Item {
x: -Theme.horizontalPageMargin/2 x: -Theme.horizontalPageMargin/2
@ -277,7 +264,7 @@ MessageContentBase {
visible: !pollMessageComponent.canAnswer && !pollData.is_anonymous && pollData.total_voter_count > 0 visible: !pollMessageComponent.canAnswer && !pollData.is_anonymous && pollData.total_voter_count > 0
icon.source: "image://theme/icon-m-media-artists" icon.source: "image://theme/icon-m-media-artists"
onClicked: { onClicked: {
pageStack.push(Qt.resolvedUrl("../../pages/PollResultsPage.qml"), { chatId:chatId, message:pollMessageComponent.rawMessage}); pageStack.push(Qt.resolvedUrl("../pages/PollResultsPage.qml"), { chatId:chatId, message:pollMessageComponent.message});
} }
Icon { Icon {
opacity: 0.8 opacity: 0.8

View file

@ -22,6 +22,7 @@ import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0 import WerkWolf.Fernschreiber 1.0
Item { Item {
id: profileThumbnail id: profileThumbnail
property alias photoData: file.fileInformation property alias photoData: file.fileInformation
@ -29,10 +30,6 @@ Item {
property int radius: width / 2 property int radius: width / 2
property int imageStatus: -1 property int imageStatus: -1
property bool optimizeImageSize: true property bool optimizeImageSize: true
property bool highlighted
layer.enabled: highlighted
layer.effect: PressEffect { source: profileThumbnail }
function getReplacementString() { function getReplacementString() {
if (replacementStringHint.length > 2) { if (replacementStringHint.length > 2) {
@ -69,6 +66,7 @@ Item {
id: singleImage id: singleImage
width: parent.width - Theme.paddingSmall width: parent.width - Theme.paddingSmall
height: width height: width
anchors.centerIn: parent
source: file.path source: file.path
sourceSize.width: optimizeImageSize ? width : undefined sourceSize.width: optimizeImageSize ? width : undefined
sourceSize.height: optimizeImageSize ? height : undefined sourceSize.height: optimizeImageSize ? height : undefined

View file

@ -1,121 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import "../js/twemoji.js" as Emoji
import "../js/functions.js" as Functions
import "../js/debug.js" as Debug
Column {
id: replyMarkupButtons
width: parent.width
height: childrenRect.height
spacing: Theme.paddingSmall
Repeater {
model: myMessage.reply_markup.rows
delegate: Row {
width: parent.width
height: Theme.itemSizeSmall
spacing: Theme.paddingSmall
Repeater {
id: buttonsRepeater
model: modelData
property int itemWidth: replyMarkupButtons.width / count
delegate: MouseArea {
/*
Unimplemented callback types:
inlineKeyboardButtonTypeBuy
inlineKeyboardButtonTypeCallbackGame
inlineKeyboardButtonTypeCallbackWithPassword
inlineKeyboardButtonTypeLoginUrl
inlineKeyboardButtonTypeSwitchInline
*/
property var callbacks: ({
inlineKeyboardButtonTypeCallback: function(){
tdLibWrapper.getCallbackQueryAnswer(myMessage.chat_id, myMessage.id, {data: modelData.type.data, "@type": "callbackQueryPayloadData"})
},
inlineKeyboardButtonTypeCallbackGame: function(){
tdLibWrapper.getCallbackQueryAnswer(myMessage.chat_id, myMessage.id, {game_short_name: myMessage.content.game.short_name, "@type": "callbackQueryPayloadGame"})
},
inlineKeyboardButtonTypeUrl: function() {
Functions.handleLink(modelData.type.url);
},
inlineKeyboardButtonTypeSwitchInline: function() {
if(modelData.type.in_current_chat) {
chatPage.setMessageText("@" + userInformation.usernames.editable_username + " "+(modelData.type.query || ""))
} else {
pageStack.push(Qt.resolvedUrl("../pages/ChatSelectionPage.qml"), {
myUserId: chatPage.myUserId,
payload: { neededPermissions: ["can_send_other_messages"], text:"@" + userInformation.usernames.editable_username + " "+(modelData.type.query || "")},
state: "fillTextArea"
})
}
},
keyboardButtonTypeText: function() {
chatPage.setMessageText(modelData.text, true);
}
})
enabled: !!callbacks[modelData.type["@type"]]
height: Theme.itemSizeSmall
width: (replyMarkupButtons.width + Theme.paddingSmall) / buttonsRepeater.count - (Theme.paddingSmall)
onClicked: {
callbacks[modelData.type["@type"]]();
}
Rectangle {
anchors.fill: parent
radius: Theme.paddingSmall
color: parent.pressed ? Theme.rgba(Theme.highlightBackgroundColor, Theme.highlightBackgroundOpacity)
: Theme.rgba(Theme.primaryColor, Theme.opacityFaint)
opacity: parent.enabled ? 1.0 : Theme.opacityLow
Label {
width: Math.min(parent.width - Theme.paddingSmall*2, contentWidth)
truncationMode: TruncationMode.Fade
text: Emoji.emojify(modelData.text, Theme.fontSizeSmall)
color: parent.parent.pressed ? Theme.highlightColor : Theme.primaryColor
anchors.centerIn: parent
font.pixelSize: Theme.fontSizeSmall
}
Icon {
property var sources: ({
inlineKeyboardButtonTypeUrl: "../../images/icon-s-link.svg",
inlineKeyboardButtonTypeSwitchInline: !modelData.type.in_current_chat ? "image://theme/icon-s-repost" : "image://theme/icon-s-edit",
inlineKeyboardButtonTypeCallbackWithPassword: "image://theme/icon-s-asterisk"
})
visible: !!sources[modelData.type["@type"]]
opacity: 0.6
source: sources[modelData.type["@type"]] || ""
sourceSize: Qt.size(Theme.iconSizeSmall, Theme.iconSizeSmall)
highlighted: parent.pressed
anchors {
right: parent.right
top: parent.top
}
}
}
}
}
}
}
}

View file

@ -25,52 +25,22 @@ Item {
id: stickerPickerOverlayItem id: stickerPickerOverlayItem
anchors.fill: parent anchors.fill: parent
property var recentStickers: stickerManager.getRecentStickers(); property var recentStickers: stickerManager.getRecentStickers()
property var installedStickerSets: stickerManager.getInstalledStickerSets(); property var installedStickerSets: stickerManager.getInstalledStickerSets()
property bool pickerLoaded: false
Connections {
target: tdLibWrapper
onOkReceived: {
if (request === "removeStickerSet") {
appNotification.show(qsTr("Sticker set successfully removed!"));
tdLibWrapper.getInstalledStickerSets();
}
}
}
Connections {
target: stickerManager
onStickerSetsReceived: {
installedStickerSets = stickerManager.getInstalledStickerSets();
}
}
Component {
id: stickerComponent
BackgroundItem {
id: stickerSetItem
width: Theme.itemSizeExtraLarge
height: Theme.itemSizeExtraLarge
onClicked: stickerPickerOverlayItem.stickerPicked(modelData.sticker.remote.id)
TDLibThumbnail {
thumbnail: modelData.thumbnail
anchors.fill: parent
highlighted: stickerSetItem.highlighted
}
Label {
font.pixelSize: Theme.fontSizeSmall
anchors.right: parent.right
anchors.bottom: parent.bottom
text: Emoji.emojify(modelData.emoji, font.pixelSize)
}
}
}
signal stickerPicked(var stickerId) signal stickerPicked(var stickerId)
Timer {
id: stickerPickerLoadedTimer
interval: 100
running: true
repeat: false
onTriggered: {
stickerPickerOverlayItem.pickerLoaded = true;
}
}
Rectangle { Rectangle {
id: stickerPickerOverlayBackground id: stickerPickerOverlayBackground
anchors.fill: parent anchors.fill: parent
@ -79,32 +49,35 @@ Item {
opacity: 0.7 opacity: 0.7
} }
SilicaListView { Flickable {
id: stickerPickerListView id: stickerPickerFlickable
anchors.fill: parent anchors.fill: parent
anchors.margins: Theme.paddingMedium
opacity: stickerPickerOverlayItem.pickerLoaded ? 1 : 0
Behavior on opacity { NumberAnimation {} }
visible: stickerPickerOverlayItem.pickerLoaded
contentHeight: stickerPickerColumn.height
clip: true clip: true
model: stickerPickerOverlayItem.installedStickerSets Column {
id: stickerPickerColumn
header: Column { spacing: Theme.paddingMedium
spacing: Theme.paddingSmall width: stickerPickerFlickable.width
width: stickerPickerListView.width
height: recentStickersGridView.count > 0 ? ( Theme.fontSizeLarge + Theme.itemSizeExtraLarge + 4 * Theme.paddingSmall ) : 0
topPadding: Theme.paddingSmall
Label { Label {
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeMedium
font.bold: true font.bold: true
width: recentStickersGridView.width width: parent.width
leftPadding: Theme.paddingMedium
visible: recentStickersGridView.count > 0
maximumLineCount: 1 maximumLineCount: 1
truncationMode: TruncationMode.Fade truncationMode: TruncationMode.Fade
text: qsTr("Recently used") text: qsTr("Recently used")
} }
SilicaGridView { SilicaGridView {
id: recentStickersGridView id: recentStickersGridView
width: stickerPickerListView.width width: parent.width
height: Theme.itemSizeExtraLarge + Theme.paddingSmall height: Theme.itemSizeExtraLarge
cellWidth: Theme.itemSizeExtraLarge; cellWidth: Theme.itemSizeExtraLarge;
cellHeight: Theme.itemSizeExtraLarge; cellHeight: Theme.itemSizeExtraLarge;
visible: count > 0 visible: count > 0
@ -112,132 +85,119 @@ Item {
flow: GridView.FlowTopToBottom flow: GridView.FlowTopToBottom
model: stickerPickerOverlayItem.recentStickers model: stickerPickerOverlayItem.recentStickers
delegate: stickerComponent
delegate: Item {
width: recentStickersGridView.cellWidth
height: recentStickersGridView.cellHeight
Image {
source: modelData.thumbnail.file.local.path
anchors.fill: parent
asynchronous: true
onStatusChanged: {
if (status === Image.Ready) {
stickerPickerLoadedTimer.restart();
}
}
}
MouseArea {
anchors.fill: parent
onClicked: stickerPickerOverlayItem.stickerPicked(modelData.sticker.remote.id)
}
}
HorizontalScrollDecorator {} HorizontalScrollDecorator {}
} }
}
delegate: Column {
id: stickerSetColumn
property bool isExpanded: false Repeater {
function toggleDisplaySet() { model: stickerPickerOverlayItem.installedStickerSets
stickerSetColumn.isExpanded = !stickerSetColumn.isExpanded; width: stickerPickerFlickable.width
if (stickerSetColumn.isExpanded) { Column {
stickerSetLoader.myStickerSet = modelData.stickers;
}
}
spacing: Theme.paddingSmall
width: parent.width
Row {
id: stickerSetTitleRow
width: parent.width
height: Theme.itemSizeMedium + ( 2 * Theme.paddingSmall )
spacing: Theme.paddingMedium spacing: Theme.paddingMedium
BackgroundItem { width: parent.width
id: stickerSetToggle
width: parent.width - removeSetButton.width - Theme.paddingMedium * 2
height: parent.height
onClicked: {
toggleDisplaySet();
}
TDLibThumbnail {
id: stickerSetThumbnail
thumbnail: modelData.thumbnail ? modelData.thumbnail : modelData.stickers[0].thumbnail
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
leftMargin: Theme.paddingMedium
}
width: Theme.itemSizeMedium
height: Theme.itemSizeMedium
highlighted: stickerSetToggle.down
}
Label { Label {
id: setTitleText font.pixelSize: Theme.fontSizeMedium
font.pixelSize: Theme.fontSizeLarge
font.bold: true font.bold: true
width: parent.width
anchors { maximumLineCount: 1
left: stickerSetThumbnail.right
right: expandSetButton.left
verticalCenter: parent.verticalCenter
margins: Theme.paddingSmall
}
truncationMode: TruncationMode.Fade truncationMode: TruncationMode.Fade
text: modelData.title text: modelData.title
} }
Icon { SilicaGridView {
id: expandSetButton
source: stickerSetColumn.isExpanded ? "image://theme/icon-m-up" : "image://theme/icon-m-down"
anchors {
right: parent.right
verticalCenter: parent.verticalCenter
rightMargin: Theme.paddingMedium
}
}
}
IconButton {
id: removeSetButton
icon.source: "image://theme/icon-m-remove"
anchors.verticalCenter: parent.verticalCenter
onClicked: {
var stickerSetId = modelData.id;
Remorse.popupAction(chatPage, qsTr("Removing sticker set"), function() {
tdLibWrapper.changeStickerSet(stickerSetId, false);
});
}
}
}
Loader {
id: stickerSetLoader
width: parent.width
active: stickerSetColumn.isExpanded || height > 0
height: stickerSetColumn.isExpanded ? Theme.itemSizeExtraLarge + Theme.paddingSmall : 0
opacity: stickerSetColumn.isExpanded ? 1.0 : 0.0
Behavior on height {
NumberAnimation { duration: 200 }
}
Behavior on opacity {
NumberAnimation { duration: 200 }
}
property var myStickerSet
onActiveChanged: {
if(!active) {
myStickerSet = ({});
}
}
sourceComponent: Component {
SilicaListView {
id: installedStickerSetGridView id: installedStickerSetGridView
width: stickerSetLoader.width width: parent.width
height: stickerSetLoader.height height: Theme.itemSizeExtraLarge
cellWidth: Theme.itemSizeExtraLarge;
orientation: Qt.Horizontal cellHeight: Theme.itemSizeExtraLarge;
visible: count > 0 visible: count > 0
clip: true
flow: GridView.FlowTopToBottom
model: stickerSetLoader.myStickerSet model: modelData.stickers
delegate: stickerComponent delegate: Item {
width: installedStickerSetGridView.cellWidth
height: installedStickerSetGridView.cellHeight
Image {
id: singleStickerImage
source: modelData.thumbnail.file.local.is_downloading_completed ? modelData.thumbnail.file.local.path : ""
anchors.fill: parent
visible: modelData.thumbnail.file.local.is_downloading_completed
asynchronous: true
onStatusChanged: {
if (status === Image.Ready) {
stickerPickerLoadedTimer.restart();
}
}
}
Label {
font.pixelSize: Theme.fontSizeHuge
anchors.fill: parent
maximumLineCount: 1
truncationMode: TruncationMode.Fade
text: Emoji.emojify(modelData.emoji, font.pixelSize)
visible: !modelData.thumbnail.file.local.is_downloading_completed
}
MouseArea {
anchors.fill: parent
onClicked: stickerPickerOverlayItem.stickerPicked(modelData.sticker.remote.id)
}
}
HorizontalScrollDecorator {} HorizontalScrollDecorator {}
} }
} }
} }
} }
} }
Column {
anchors.centerIn: parent
width: parent.width
spacing: Theme.paddingMedium
opacity: stickerPickerOverlayItem.pickerLoaded ? 0 : 1
Behavior on opacity { NumberAnimation {} }
visible: !stickerPickerOverlayItem.pickerLoaded
InfoLabel {
id: loadingLabel
text: qsTr("Loading stickers...")
} }
BusyIndicator {
id: loadingBusyIndicator
anchors.horizontalCenter: parent.horizontalCenter
running: !stickerPickerOverlayItem.pickerLoaded
size: BusyIndicatorSize.Large
}
}
}

View file

@ -1,5 +1,5 @@
/* /*
Copyright (C) 2020-21 Sebastian J. Wolf and other contributors Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber. This file is part of Fernschreiber.
@ -19,23 +19,25 @@
import QtQuick 2.6 import QtQuick 2.6
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0 import WerkWolf.Fernschreiber 1.0
import "../"
import "../../js/twemoji.js" as Emoji
MessageContentBase { Item {
id: thisItem property ListItem messageListItem
property MessageOverlayFlickable overlayFlickable
property var stickerData: messageListItem ? messageListItem.myMessage.content.sticker : overlayFlickable.overlayMessage.content.sticker; readonly property var stickerData: messageListItem ? messageListItem.myMessage.content.sticker : overlayFlickable.overlayMessage.content.sticker;
readonly property bool asEmoji: appSettings.showStickersAsEmojis readonly property bool animated: stickerData.is_animated && appSettings.animateStickers
readonly property bool animated: stickerData.format["@type"] === "stickerFormatTgs" && appSettings.animateStickers
readonly property bool stickerVisible: staticStickerLoader.item ? staticStickerLoader.item.visible : readonly property bool stickerVisible: staticStickerLoader.item ? staticStickerLoader.item.visible :
animatedStickerLoader.item ? animatedStickerLoader.item.visible : false animatedStickerLoader.item ? animatedStickerLoader.item.visible : false
readonly property bool isOwnSticker : messageListItem ? messageListItem.isOwnMessage : overlayFlickable.isOwnMessage readonly property bool isOwnSticker : messageListItem ? messageListItem.isOwnMessage : overlayFlickable.isOwnMessage
readonly property real aspectRatio: stickerData.width / stickerData.height property real aspectRatio: stickerData.width / stickerData.height
property bool highlighted
implicitWidth: stickerData.width implicitWidth: stickerData.width
implicitHeight: stickerData.height implicitHeight: stickerData.height
layer.enabled: highlighted
layer.effect: PressEffect { source: singleImage }
TDLibFile { TDLibFile {
id: file id: file
tdlib: tdLibWrapper tdlib: tdLibWrapper
@ -44,7 +46,6 @@ MessageContentBase {
} }
Item { Item {
width: Math.min( stickerData.width, parent.width ) width: Math.min( stickerData.width, parent.width )
height: width * aspectRatio height: width * aspectRatio
// (centered in image mode, text-like in sticker mode) // (centered in image mode, text-like in sticker mode)
@ -55,17 +56,14 @@ MessageContentBase {
Loader { Loader {
id: animatedStickerLoader id: animatedStickerLoader
anchors.fill: parent anchors.fill: parent
active: animated && !asEmoji active: animated
sourceComponent: Component { sourceComponent: Component {
AnimatedImage { AnimatedImage {
id: animatedSticker
anchors.fill: parent anchors.fill: parent
source: file.path source: file.path
asynchronous: true asynchronous: true
paused: !Qt.application.active paused: !Qt.application.active
cache: false cache: false
layer.enabled: thisItem.highlighted
layer.effect: PressEffect { source: animatedSticker }
} }
} }
} }
@ -73,24 +71,17 @@ MessageContentBase {
Loader { Loader {
id: staticStickerLoader id: staticStickerLoader
anchors.fill: parent anchors.fill: parent
active: !animated || asEmoji active: !animated
sourceComponent: Component { sourceComponent: Component {
Image { Image {
id: staticSticker
anchors.fill: parent anchors.fill: parent
source: asEmoji ? Emoji.getEmojiPath(stickerData.emoji) : file.path source: file.path
sourceSize {
width: width
height: height
}
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
autoTransform: true autoTransform: true
asynchronous: true asynchronous: true
visible: opacity > 0 visible: opacity > 0
opacity: status === Image.Ready ? 1 : 0 opacity: status === Image.Ready ? 1 : 0
Behavior on opacity { FadeAnimation {} } Behavior on opacity { FadeAnimation {} }
layer.enabled: thisItem.highlighted
layer.effect: PressEffect { source: staticSticker }
} }
} }
} }
@ -107,11 +98,6 @@ MessageContentBase {
} }
} }
onClicked: {
stickerSetOverlayLoader.stickerSetId = stickerData.set_id
stickerSetOverlayLoader.active = true
}
Timer { Timer {
id: placeHolderDelayTimer id: placeHolderDelayTimer
interval: 1000 interval: 1000

View file

@ -1,173 +0,0 @@
/*
Copyright (C) 2020-21 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import "./messageContent"
import "../js/functions.js" as Functions
import "../js/twemoji.js" as Emoji
import "../js/debug.js" as Debug
Flickable {
id: stickerSetOverlayFlickable
anchors.fill: parent
boundsBehavior: Flickable.StopAtBounds
contentHeight: stickerSetContentColumn.height
clip: true
property string stickerSetId;
property var stickerSet;
signal requestClose;
Component.onCompleted: {
if (!stickerManager.hasStickerSet(stickerSetId)) {
tdLibWrapper.getStickerSet(stickerSetId);
} else {
stickerSet = stickerManager.getStickerSet(stickerSetId);
}
}
Connections {
target: tdLibWrapper
onStickerSetReceived: {
if (stickerSet.id === stickerSetOverlayFlickable.stickerSetId) {
stickerSetOverlayFlickable.stickerSet = stickerSet;
}
}
onOkReceived: {
if (request === "installStickerSet") {
appNotification.show(qsTr("Sticker set successfully installed!"));
installSetButton.visible = false;
tdLibWrapper.getInstalledStickerSets();
}
if (request === "removeStickerSet") {
appNotification.show(qsTr("Sticker set successfully removed!"));
installSetButton.visible = true;
tdLibWrapper.getInstalledStickerSets();
}
}
}
Rectangle {
id: stickerSetContentBackground
color: Theme.overlayBackgroundColor
opacity: 0.7
anchors.fill: parent
MouseArea {
anchors.fill: parent
onClicked: {
stickerSetOverlayFlickable.requestClose();
}
}
}
Column {
id: stickerSetContentColumn
spacing: Theme.paddingMedium
width: parent.width
height: parent.height
Row {
id: stickerSetTitleRow
width: parent.width - ( 2 * Theme.horizontalPageMargin )
height: overlayStickerTitleText.height + ( 2 * Theme.paddingMedium )
anchors.horizontalCenter: parent.horizontalCenter
Label {
id: overlayStickerTitleText
width: parent.width - installSetButton.width - closeSetButton.width
text: stickerSet.title
font.pixelSize: Theme.fontSizeExtraLarge
font.weight: Font.ExtraBold
maximumLineCount: 1
truncationMode: TruncationMode.Fade
textFormat: Text.StyledText
anchors.verticalCenter: parent.verticalCenter
}
IconButton {
id: installSetButton
icon.source: "image://theme/icon-m-add"
anchors.verticalCenter: parent.verticalCenter
visible: !stickerManager.isStickerSetInstalled(stickerSet.id)
onClicked: {
tdLibWrapper.changeStickerSet(stickerSet.id, true);
}
}
IconButton {
id: removeSetButton
icon.source: "image://theme/icon-m-remove"
anchors.verticalCenter: parent.verticalCenter
visible: !installSetButton.visible
onClicked: {
tdLibWrapper.changeStickerSet(stickerSet.id, false);
}
}
IconButton {
id: closeSetButton
icon.source: "image://theme/icon-m-clear"
anchors.verticalCenter: parent.verticalCenter
onClicked: {
stickerSetOverlayFlickable.requestClose();
}
}
}
SilicaGridView {
id: stickerSetGridView
width: parent.width - ( 2 * Theme.horizontalPageMargin )
height: parent.height - stickerSetTitleRow.height - Theme.paddingMedium
anchors.horizontalCenter: parent.horizontalCenter
cellWidth: chatPage.isLandscape ? (width / 5) : (width / 3);
cellHeight: cellWidth
visible: count > 0
clip: true
model: stickerSet.stickers
delegate: Item {
width: stickerSetGridView.cellWidth - Theme.paddingSmall
height: stickerSetGridView.cellHeight - Theme.paddingSmall
TDLibThumbnail {
id: singleStickerThumbnail
thumbnail: modelData.thumbnail
anchors.fill: parent
}
Label {
font.pixelSize: Theme.fontSizeSmall
anchors.right: parent.right
anchors.bottom: parent.bottom
text: Emoji.emojify(modelData.emoji, font.pixelSize)
}
}
VerticalScrollDecorator {}
}
}
}

View file

@ -1,55 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import WerkWolf.Fernschreiber 1.0
import Sailfish.Silica 1.0
import "../js/debug.js" as Debug
Image {
id: tdLibImage
property alias fileInformation: file.fileInformation
readonly property alias file: file
property bool highlighted
asynchronous: true
enabled: !!file.fileId
fillMode: Image.PreserveAspectCrop
clip: true
opacity: status === Image.Ready ? 1.0 : 0.0
source: enabled && file.isDownloadingCompleted ? file.path : ""
visible: opacity > 0
sourceSize {
width: width
height: height
}
Behavior on opacity { FadeAnimation {} }
layer {
enabled: tdLibImage.enabled && tdLibImage.highlighted
effect: PressEffect { source: tdLibImage }
}
TDLibFile {
id: file
autoLoad: true
tdlib: tdLibWrapper
}
}

View file

@ -1,54 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import QtGraphicalEffects 1.0
Loader {
id: loader
property var minithumbnail
property bool highlighted
anchors.fill: parent
active: !!minithumbnail
sourceComponent: Component {
Item {
Image {
id: minithumbnailImage
anchors.fill: parent
source: "data:image/jpg;base64,"+minithumbnail.data
fillMode: tdLibImage.fillMode
opacity: status === Image.Ready ? 1.0 : 0.0
cache: false
visible: opacity > 0
Behavior on opacity { FadeAnimation {} }
layer {
enabled: loader.highlighted
effect: PressEffect { source: minithumbnailImage }
}
}
FastBlur {
anchors.fill: parent
source: minithumbnailImage
radius: Theme.paddingLarge
}
}
}
}

View file

@ -1,69 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import WerkWolf.Fernschreiber 1.0
import Sailfish.Silica 1.0
import QtGraphicalEffects 1.0
Item {
id: tdLibPhoto
property var photo
property bool highlighted
readonly property alias fileInformation: tdLibImage.fileInformation
readonly property alias image: tdLibImage
onWidthChanged: setImageFile()
onPhotoChanged: setImageFile()
function setImageFile() {
if (photo) {
var photoSize;
for (var i = 0; i < photo.sizes.length; i++) {
photoSize = photo.sizes[i].photo;
if (photo.sizes[i].width >= width) {
break;
}
}
if (photoSize && photoSize.id !== tdLibImage.fileInformation.id) {
tdLibImage.fileInformation = photoSize;
}
}
}
TDLibMinithumbnail {
id: minithumbnailLoader
active: !!minithumbnail && tdLibImage.opacity < 1.0
minithumbnail: tdLibPhoto.photo.minithumbnail
highlighted: parent.highlighted
}
BackgroundImage {
visible: !tdLibImage.visible && !(minithumbnailLoader.item && minithumbnailLoader.item.visible)
}
TDLibImage {
id: tdLibImage
width: parent.width //don't use anchors here for easier custom scaling
height: parent.height
cache: false
highlighted: parent.highlighted
}
Component.onCompleted: setImageFile()
}

View file

@ -1,112 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import Nemo.Thumbnailer 1.0
Item {
id: tdlibThumbnail
/*
Optional thumbnail, usually as property "thumbnail".
The following TDLib objects can have it:
- animation
- audio (as "album_cover_thumbnail")
- document
- sticker (no minithumbnail)
- video
- videoNote
- stickerSet (no minithumbnail)
- stickerSetInfo (no minithumbnail)
- inlineQueryResultArticle (no minithumbnail)
- inlineQueryResultContact (no minithumbnail)
- inlineQueryResultLocation (no minithumbnail)
- inlineQueryResultVenue (no minithumbnail)
*/
property var thumbnail
/*
Optional minithumbnail, usually as property "minithumbnail".
Has data inline: If present, it doesn't need another request.
The following TDLib objects can have it:
- animation
- audio (as "album_cover_minithumbnail")
- document
- photo / chatPhoto (Note: No thumbnail, so not applicable here)
- video
- videoNote
*/
property alias minithumbnail: minithumbnailLoader.minithumbnail
property bool useBackgroundImage: true
property bool highlighted
property bool isVideo: !!thumbnail && thumbnail.format["@type"] === "thumbnailFormatMpeg4"
property string videoMimeType: "video/mp4"
readonly property bool hasVisibleThumbnail: thumbnailImage.opacity !== 1.0
&& !(videoThumbnailLoader.item && videoThumbnailLoader.item.opacity === 1.0)
layer {
enabled: highlighted
effect: PressEffect { source: tdlibThumbnail }
}
TDLibMinithumbnail {
id: minithumbnailLoader
active: !!minithumbnail && thumbnailImage.opacity < 1.0
}
BackgroundImage {
visible: tdlibThumbnail.useBackgroundImage && thumbnailImage.opacity < 1.0
}
// image thumbnail
TDLibImage {
id: thumbnailImage
anchors.fill: parent
enabled: !parent.isVideo
fileInformation: tdlibThumbnail.thumbnail ? tdlibThumbnail.thumbnail.file : {}
onStatusChanged: { //TODO check if this is really how it is ;)
if(status === Image.Error) {
// in some cases, webp is used (without correct mime type).
// we just try it blindly and cross our fingers:
tdlibThumbnail.videoMimeType = "image/webp";
tdlibThumbnail.isVideo = true;
}
}
}
// Fallback for video thumbnail format: try to use Nemo.Thumbnailer
Loader {
id: videoThumbnailLoader
active: parent.isVideo
asynchronous: true
anchors.fill: parent
sourceComponent: Component {
id: videoThumbnail
Thumbnail {
id: thumbnail
source: thumbnailImage.file.path
sourceSize.width: width
sourceSize.height: height
mimeType: tdlibThumbnail.videoMimeType
visible: opacity > 0
opacity: status === Thumbnail.Ready ? 1.0 : 0.0
Behavior on opacity { FadeAnimation {} }
}
}
}
}

View file

@ -19,13 +19,16 @@
import QtQuick 2.6 import QtQuick 2.6
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import QtMultimedia 5.6 import QtMultimedia 5.6
import "../" import "../js/functions.js" as Functions
import "../../js/functions.js" as Functions import "../js/debug.js" as Debug
import "../../js/debug.js" as Debug
MessageContentBase { Item {
id: videoMessageComponent id: videoMessageComponent
property ListItem messageListItem
property MessageOverlayFlickable overlayFlickable
property var rawMessage: messageListItem ? messageListItem.myMessage : overlayFlickable.overlayMessage
property var videoData: ( rawMessage.content['@type'] === "messageVideo" ) ? rawMessage.content.video : ( ( rawMessage.content['@type'] === "messageAnimation" ) ? rawMessage.content.animation : rawMessage.content.video_note ) property var videoData: ( rawMessage.content['@type'] === "messageVideo" ) ? rawMessage.content.video : ( ( rawMessage.content['@type'] === "messageAnimation" ) ? rawMessage.content.animation : rawMessage.content.video_note )
property string videoUrl; property string videoUrl;
property int previewFileId; property int previewFileId;
@ -35,7 +38,10 @@ MessageContentBase {
property bool onScreen: messageListItem ? messageListItem.page.status === PageStatus.Active : true; property bool onScreen: messageListItem ? messageListItem.page.status === PageStatus.Active : true;
property string videoType : "video"; property string videoType : "video";
property bool playRequested: false; property bool playRequested: false;
property bool highlighted;
signal clicked();
width: parent.width
height: videoMessageComponent.isVideoNote ? width : Functions.getVideoHeight(width, videoData) height: videoMessageComponent.isVideoNote ? width : Functions.getVideoHeight(width, videoData)
Timer { Timer {
@ -83,7 +89,7 @@ MessageContentBase {
videoMessageComponent.videoType = videoMessageComponent.isVideoNote ? "video" : videoData['@type']; videoMessageComponent.videoType = videoMessageComponent.isVideoNote ? "video" : videoData['@type'];
videoFileId = videoData[videoType].id; videoFileId = videoData[videoType].id;
if (typeof rawMessage !== "undefined" && rawMessage.content['@type'] === "messageAnimation") { if (rawMessage.content['@type'] === "messageAnimation") {
playButton.visible = true; playButton.visible = true;
fullscreenButton.visible = !videoMessageComponent.fullscreen; fullscreenButton.visible = !videoMessageComponent.fullscreen;
handlePlay(); handlePlay();
@ -95,7 +101,7 @@ MessageContentBase {
tdLibWrapper.downloadFile(previewFileId); tdLibWrapper.downloadFile(previewFileId);
} }
} else { } else {
placeholderImage.source = "image://theme/icon-m-video?white"; placeholderImage.source = "image://theme/icon-l-video?white";
placeholderImage.width = Theme.itemSizeLarge placeholderImage.width = Theme.itemSizeLarge
placeholderImage.height = Theme.itemSizeLarge placeholderImage.height = Theme.itemSizeLarge
} }
@ -147,7 +153,7 @@ MessageContentBase {
asynchronous: true asynchronous: true
visible: status === Image.Ready ? true : false visible: status === Image.Ready ? true : false
layer.enabled: videoMessageComponent.highlighted layer.enabled: videoMessageComponent.highlighted
layer.effect: PressEffect { source: placeholderImage } layer.effect: PressEffect { source: singleImage }
} }
BackgroundImage { BackgroundImage {
@ -155,6 +161,7 @@ MessageContentBase {
} }
Rectangle { Rectangle {
id: placeholderBackground
color: "black" color: "black"
opacity: 0.3 opacity: 0.3
height: parent.height height: parent.height
@ -209,7 +216,7 @@ MessageContentBase {
height: Theme.iconSizeLarge height: Theme.iconSizeLarge
icon { icon {
asynchronous: true asynchronous: true
source: "../../../images/icon-l-fullscreen.svg" source: "../../images/icon-l-fullscreen.svg"
sourceSize { sourceSize {
width: Theme.iconSizeLarge width: Theme.iconSizeLarge
height: Theme.iconSizeLarge height: Theme.iconSizeLarge
@ -218,7 +225,7 @@ MessageContentBase {
highlighted: videoMessageComponent.highlighted || down highlighted: videoMessageComponent.highlighted || down
visible: ( placeholderImage.status === Image.Ready && !videoMessageComponent.fullscreen ) ? true : false visible: ( placeholderImage.status === Image.Ready && !videoMessageComponent.fullscreen ) ? true : false
onClicked: { onClicked: {
pageStack.push(Qt.resolvedUrl("../../pages/VideoPage.qml"), {"videoData": videoData, "sourceMessage": rawMessage}); pageStack.push(Qt.resolvedUrl("../pages/VideoPage.qml"), {"videoData": videoData});
} }
} }
} }
@ -234,6 +241,7 @@ MessageContentBase {
} }
Rectangle { Rectangle {
id: videoErrorShade
width: parent.width width: parent.width
height: parent.height height: parent.height
color: "lightgrey" color: "lightgrey"
@ -288,6 +296,21 @@ MessageContentBase {
} }
} }
Connections {
target: videoMessageComponent
onClicked: {
if (messageVideo.playbackState === MediaPlayer.PlayingState) {
enableScreensaver();
messageVideo.pause();
timeLeftItem.visible = true;
} else {
disableScreensaver();
messageVideo.play();
timeLeftTimer.start();
}
}
}
Video { Video {
id: messageVideo id: messageVideo
@ -346,7 +369,7 @@ MessageContentBase {
height: parent.height height: parent.height
source: videoUrl source: videoUrl
layer.enabled: videoMessageComponent.highlighted layer.enabled: videoMessageComponent.highlighted
layer.effect: PressEffect { source: messageVideo } layer.effect: PressEffect { source: singleImage }
onStopped: { onStopped: {
enableScreensaver(); enableScreensaver();
messageVideo.visible = false; messageVideo.visible = false;
@ -355,21 +378,6 @@ MessageContentBase {
videoComponentLoader.active = false; videoComponentLoader.active = false;
fullscreenItem.visible = !videoMessageComponent.fullscreen; fullscreenItem.visible = !videoMessageComponent.fullscreen;
} }
MouseArea {
anchors.fill: parent
onClicked: {
if (messageVideo.playbackState === MediaPlayer.PlayingState) {
enableScreensaver();
messageVideo.pause();
timeLeftItem.visible = true;
} else {
disableScreensaver();
messageVideo.play();
timeLeftTimer.start();
}
}
}
} }
BusyIndicator { BusyIndicator {
@ -456,7 +464,7 @@ MessageContentBase {
highlighted: videoMessageComponent.highlighted || down highlighted: videoMessageComponent.highlighted || down
icon { icon {
asynchronous: true asynchronous: true
source: "../../../images/icon-l-fullscreen.svg" source: "../../images/icon-l-fullscreen.svg"
sourceSize { sourceSize {
width: Theme.iconSizeLarge width: Theme.iconSizeLarge
height: Theme.iconSizeLarge height: Theme.iconSizeLarge
@ -464,7 +472,7 @@ MessageContentBase {
} }
visible: ( videoComponentLoader.active && messageVideo.playbackState === MediaPlayer.PausedState ) ? true : false visible: ( videoComponentLoader.active && messageVideo.playbackState === MediaPlayer.PausedState ) ? true : false
onClicked: { onClicked: {
pageStack.push(Qt.resolvedUrl("../../pages/VideoPage.qml"), {"videoData": videoData, "sourceMessage": rawMessage}); pageStack.push(Qt.resolvedUrl("../pages/VideoPage.qml"), {"videoData": videoData});
} }
} }
} }
@ -476,7 +484,7 @@ MessageContentBase {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: positionText.top anchors.bottom: positionText.top
minimumValue: 0 minimumValue: 0
maximumValue: messageVideo.duration ? messageVideo.duration : 0.1 maximumValue: messageVideo.duration ? messageVideo.duration : 0
highlighted: videoMessageComponent.highlighted || down highlighted: videoMessageComponent.highlighted || down
stepSize: 1 stepSize: 1
@ -508,6 +516,7 @@ MessageContentBase {
} }
} }
} }

View file

@ -1,221 +0,0 @@
/*
Copyright (C) 2020-21 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
import "../components"
import "../js/twemoji.js" as Emoji
import "../js/debug.js" as Debug
Item {
id: voiceNoteOverlayItem
anchors.fill: parent
property int recordingState: fernschreiberUtils.getVoiceNoteRecordingState();
property int recordingDuration: 0;
property bool recordingDone: false;
function handleRecordingState() {
switch (recordingState) {
case FernschreiberUtilities.Unavailable:
recordingStateLabel.text = qsTr("Unavailable");
break;
case FernschreiberUtilities.Ready:
recordingStateLabel.text = qsTr("Ready");
break;
case FernschreiberUtilities.Starting:
recordingStateLabel.text = qsTr("Starting");
break;
case FernschreiberUtilities.Recording:
recordingStateLabel.text = qsTr("Recording");
break;
case FernschreiberUtilities.Stopping:
recordingStateLabel.text = qsTr("Stopping");
break;
}
}
function getTwoDigitString(numberToBeConverted) {
var numberString = "00";
if (numberToBeConverted > 0 && numberToBeConverted < 10) {
numberString = "0" + String(numberToBeConverted);
}
if (numberToBeConverted >= 10) {
numberString = String(numberToBeConverted);
}
return numberString;
}
function handleRecordingDuration() {
var minutes = Math.floor(recordingDuration / 60);
var seconds = recordingDuration % 60;
recordingDurationLabel.text = getTwoDigitString(minutes) + ":" + getTwoDigitString(seconds);
}
Component.onCompleted: {
handleRecordingState();
handleRecordingDuration();
}
Connections {
target: fernschreiberUtils
onVoiceNoteDurationChanged: {
Debug.log("New duration received: " + duration);
recordingDuration = Math.round(duration / 1000);
handleRecordingDuration();
}
onVoiceNoteRecordingStateChanged: {
Debug.log("New state received: " + state);
recordingState = state;
handleRecordingState();
}
}
Rectangle {
id: stickerPickerOverlayBackground
anchors.fill: parent
color: Theme.overlayBackgroundColor
opacity: Theme.opacityHigh
}
Flickable {
id: voiceNoteFlickable
anchors.fill: parent
anchors.margins: Theme.paddingMedium
Behavior on opacity { NumberAnimation {} }
contentHeight: voiceNoteColumn.height
clip: true
Column {
id: voiceNoteColumn
spacing: Theme.paddingMedium
width: voiceNoteFlickable.width
InfoLabel {
text: qsTr("Record a Voice Note")
}
Label {
wrapMode: Text.Wrap
width: parent.width - ( 2 * Theme.horizontalPageMargin )
horizontalAlignment: Text.AlignHCenter
text: qsTr("Press the button to start recording")
font.pixelSize: Theme.fontSizeMedium
anchors {
horizontalCenter: parent.horizontalCenter
}
}
Item {
width: Theme.iconSizeExtraLarge
height: Theme.iconSizeExtraLarge
anchors {
horizontalCenter: parent.horizontalCenter
}
Rectangle {
color: Theme.primaryColor
opacity: Theme.opacityOverlay
width: Theme.iconSizeExtraLarge
height: Theme.iconSizeExtraLarge
anchors.centerIn: parent
radius: width / 2
}
Rectangle {
id: recordButton
color: "red"
width: Theme.iconSizeExtraLarge * 0.6
height: Theme.iconSizeExtraLarge * 0.6
anchors.centerIn: parent
radius: width / 2
MouseArea {
anchors.fill: parent
onClicked: {
recordButton.visible = false;
recordingDone = false;
recordingDuration = 0;
handleRecordingDuration();
fernschreiberUtils.startRecordingVoiceNote();
}
}
}
Rectangle {
id: stopButton
visible: !recordButton.visible
color: Theme.overlayBackgroundColor
width: Theme.iconSizeExtraLarge * 0.4
height: Theme.iconSizeExtraLarge * 0.4
anchors.centerIn: parent
MouseArea {
anchors.fill: parent
onClicked: {
recordButton.visible = true;
fernschreiberUtils.stopRecordingVoiceNote();
recordingDone = true;
}
}
}
}
Label {
id: recordingStateLabel
wrapMode: Text.Wrap
width: parent.width - ( 2 * Theme.horizontalPageMargin )
horizontalAlignment: Text.AlignHCenter
font.pixelSize: Theme.fontSizeMedium
anchors {
horizontalCenter: parent.horizontalCenter
}
}
Label {
id: recordingDurationLabel
wrapMode: Text.Wrap
width: parent.width - ( 2 * Theme.horizontalPageMargin )
horizontalAlignment: Text.AlignHCenter
font.pixelSize: Theme.fontSizeMedium
anchors {
horizontalCenter: parent.horizontalCenter
}
}
Button {
visible: recordingDone
anchors {
horizontalCenter: parent.horizontalCenter
}
text: qsTr("Use recording")
onClicked: {
attachmentOptionsFlickable.isNeeded = false;
attachmentPreviewRow.isVoiceNote = true;
attachmentPreviewRow.attachmentDescription = qsTr("Voice Note (%1)").arg(recordingDurationLabel.text);
controlSendButton();
voiceNoteOverlayLoader.active = false;
}
}
}
}
}

View file

@ -19,92 +19,101 @@
import QtQuick 2.6 import QtQuick 2.6
import QtGraphicalEffects 1.0 import QtGraphicalEffects 1.0
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0 import "../components"
import "../" import "../js/twemoji.js" as Emoji
import "../../js/functions.js" as Functions import "../js/functions.js" as Functions
Column { Column {
id: webPagePreviewColumn id: webPagePreviewColumn
property var webPageData; property var webPageData;
property var pictureFileInformation;
property bool hasImage: false;
property bool largerFontSize: false; property bool largerFontSize: false;
property bool highlighted property bool highlighted
readonly property bool hasImage: picture.fileId !== 0
readonly property int fontSize: largerFontSize ? Theme.fontSizeSmall : Theme.fontSizeExtraSmall
spacing: Theme.paddingSmall spacing: Theme.paddingSmall
Component.onCompleted: updatePhoto() Component.onCompleted: {
updateWebPage();
}
onWebPageDataChanged: updatePhoto() function updateWebPage() {
function updatePhoto() {
if (webPageData) { if (webPageData) {
if (webPageData.photo) { if (typeof webPageData.photo !== "undefined") {
hasImage = true;
// Check first which size fits best... // Check first which size fits best...
var photo
for (var i = 0; i < webPageData.photo.sizes.length; i++) { for (var i = 0; i < webPageData.photo.sizes.length; i++) {
photo = webPageData.photo.sizes[i].photo; pictureFileInformation = webPageData.photo.sizes[i].photo;
if (webPageData.photo.sizes[i].width >= webPagePreviewColumn.width) { if (webPageData.photo.sizes[i].width >= webPagePreviewColumn.width) {
break; break;
} }
} }
if (photo) { if (pictureFileInformation.local.is_downloading_completed) {
picture.fileInformation = photo singleImage.source = pictureFileInformation.local.path;
} else {
tdLibWrapper.downloadFile(pictureFileInformation.id);
} }
} }
} }
} }
function clicked() { Connections {
descriptionText.toggleMaxLineCount() target: tdLibWrapper
onFileUpdated: {
if (typeof pictureFileInformation !== "undefined" && fileId === pictureFileInformation.id) {
if (fileInformation.local.is_downloading_completed) {
pictureFileInformation = fileInformation;
singleImage.source = fileInformation.local.path;
}
}
}
} }
TDLibFile { Label {
id: picture
tdlib: tdLibWrapper
autoLoad: true
}
MultilineEmojiLabel {
id: siteNameText id: siteNameText
width: parent.width width: parent.width
rawText: webPageData.site_name ? webPageData.site_name : "" text: webPageData.site_name ? Emoji.emojify(webPageData.site_name, font.pixelSize) : ""
font.pixelSize: webPagePreviewColumn.fontSize font.pixelSize: webPagePreviewColumn.largerFontSize ? Theme.fontSizeSmall : Theme.fontSizeExtraSmall
font.bold: true font.bold: true
color: Theme.secondaryHighlightColor color: Theme.secondaryHighlightColor
visible: (rawText !== "") truncationMode: TruncationMode.Fade
maxLineCount: 1 maximumLineCount: 1
textFormat: Text.StyledText
visible: (text !== "")
} }
MultilineEmojiLabel { Label {
id: titleText id: titleText
width: parent.width width: parent.width
rawText: webPageData.title ? webPageData.title : "" text: webPageData.title ? Emoji.emojify(webPageData.title, font.pixelSize) : ""
font.pixelSize: webPagePreviewColumn.fontSize font.pixelSize: webPagePreviewColumn.largerFontSize ? Theme.fontSizeSmall : Theme.fontSizeExtraSmall
font.bold: true font.bold: true
visible: (rawText !== "") truncationMode: TruncationMode.Fade
maxLineCount: 2 wrapMode: Text.Wrap
maximumLineCount: 2
textFormat: Text.StyledText
visible: (text !== "")
} }
MultilineEmojiLabel { Label {
id: descriptionText id: descriptionText
width: parent.width width: parent.width
rawText: webPageData.description ? Functions.enhanceMessageText(webPageData.description) : "" text: webPageData.description ? Emoji.emojify(Functions.enhanceMessageText(webPageData.description), font.pixelSize) : ""
font.pixelSize: webPagePreviewColumn.fontSize font.pixelSize: webPagePreviewColumn.largerFontSize ? Theme.fontSizeSmall : Theme.fontSizeExtraSmall
visible: (rawText !== "") truncationMode: TruncationMode.Fade
readonly property int defaultMaxLineCount: 3 wrapMode: Text.Wrap
maxLineCount: defaultMaxLineCount maximumLineCount: 3
textFormat: Text.StyledText
visible: (text !== "")
linkColor: Theme.highlightColor linkColor: Theme.highlightColor
onLinkActivated: { onLinkActivated: {
Functions.handleLink(link); Functions.handleLink(link);
} }
function toggleMaxLineCount() {
maxLineCount = maxLineCount > 0 ? 0 : defaultMaxLineCount
}
} }
Item { Item {
@ -124,35 +133,38 @@ Column {
fillMode: Image.PreserveAspectCrop fillMode: Image.PreserveAspectCrop
autoTransform: true autoTransform: true
asynchronous: true asynchronous: true
source: picture.isDownloadingCompleted ? picture.path : "" visible: hasImage && status === Image.Ready
visible: opacity > 0
opacity: hasImage && status === Image.Ready ? 1 : 0 opacity: hasImage && status === Image.Ready ? 1 : 0
layer.enabled: webPagePreviewColumn.highlighted layer.enabled: webPagePreviewColumn.highlighted
layer.effect: PressEffect { source: singleImage } layer.effect: PressEffect { source: singleImage }
Behavior on opacity { FadeAnimation {} } Behavior on opacity { NumberAnimation {} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: { onClicked: {
pageStack.push(Qt.resolvedUrl("../../pages/ImagePage.qml"), { "photoData" : webPageData.photo, "pictureFileInformation" : picture.fileInformation }); pageStack.push(Qt.resolvedUrl("../pages/ImagePage.qml"), { "photoData" : webPageData.photo, "pictureFileInformation" : pictureFileInformation });
} }
} }
} }
BackgroundImage { BackgroundImage {
id: backgroundImage
visible: hasImage && singleImage.status !== Image.Ready visible: hasImage && singleImage.status !== Image.Ready
layer.enabled: webPagePreviewColumn.highlighted layer.enabled: webPagePreviewColumn.highlighted
layer.effect: PressEffect { source: backgroundImage } layer.effect: PressEffect { source: singleImage }
} }
} }
Label { Label {
id: noPreviewAvailableText
width: parent.width width: parent.width
text: qsTr("Preview not supported for this link...") text: qsTr("Preview not supported for this link...")
font.pixelSize: webPagePreviewColumn.largerFontSize ? Theme.fontSizeExtraSmall : Theme.fontSizeTiny font.pixelSize: webPagePreviewColumn.largerFontSize ? Theme.fontSizeExtraSmall : Theme.fontSizeTiny
font.italic: true font.italic: true
color: Theme.secondaryColor color: Theme.secondaryColor
truncationMode: TruncationMode.Fade truncationMode: TruncationMode.Fade
wrapMode: Text.Wrap
maximumLineCount: 1
textFormat: Text.StyledText
visible: !siteNameText.visible && !titleText.visible && !descriptionText.visible && !webPagePreviewImageItem.visible visible: !siteNameText.visible && !titleText.visible && !descriptionText.visible && !webPagePreviewImageItem.visible
} }

View file

@ -1,5 +1,5 @@
/* /*
Copyright (C) 2020-21 Sebastian J. Wolf and other contributors Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber. This file is part of Fernschreiber.
@ -16,7 +16,6 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>. along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/ */
import QtQuick 2.6 import QtQuick 2.6
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
@ -28,7 +27,6 @@ Column {
property string emptyPlaceholderText property string emptyPlaceholderText
property string text property string text
property bool multiLine property bool multiLine
property bool headerLeftAligned
property bool isEditing property bool isEditing
property Item editItem: multiLine ? editAreaTextArea : editAreaTextField property Item editItem: multiLine ? editAreaTextArea : editAreaTextField
@ -43,7 +41,6 @@ Column {
id: editAreaHeader id: editAreaHeader
height: parent.visible && text !== "" ? Theme.itemSizeExtraSmall : 0 height: parent.visible && text !== "" ? Theme.itemSizeExtraSmall : 0
x: 0 x: 0
horizontalAlignment: headerLeftAligned ? Text.AlignLeft : Text.AlignRight
} }
Row { Row {
id: editAreaTextRow id: editAreaTextRow
@ -53,24 +50,20 @@ Column {
id: editAreaTextArea id: editAreaTextArea
visible: editAreaColumn.isEditing && editAreaColumn.multiLine visible: editAreaColumn.isEditing && editAreaColumn.multiLine
width: parent.width - editAreaButton.width width: parent.width - editAreaButton.width
textLeftMargin: 0
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
font.pixelSize: Theme.fontSizeMedium
} }
TextField { TextField {
id: editAreaTextField id: editAreaTextField
visible: editAreaColumn.isEditing && !editAreaColumn.multiLine visible: editAreaColumn.isEditing && !editAreaColumn.multiLine
width: parent.width - editAreaButton.width width: parent.width - editAreaButton.width
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
textLeftMargin: 0
EnterKey.onClicked: { EnterKey.onClicked: {
editAreaColumn.isEditing = false; editAreaColumn.isEditing = false;
editAreaColumn.saveButtonClicked(editAreaColumn.editItem.text); editAreaColumn.saveButtonClicked(editAreaColumn.editItem.text);
} }
EnterKey.iconSource: editAreaButton.icon.source EnterKey.iconSource: editAreaButton.icon.source
font.pixelSize: Theme.fontSizeMedium
} }
InformationTextItem { ChatInformationTextItem {
id: editAreaTextItem id: editAreaTextItem
visible: !editAreaColumn.isEditing visible: !editAreaColumn.isEditing
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter

View file

@ -98,7 +98,7 @@ SilicaFlickable {
if(groupFullInfo.members && groupFullInfo.members.length > 0) { if(groupFullInfo.members && groupFullInfo.members.length > 0) {
for(var memberIndex in groupFullInfo.members) { for(var memberIndex in groupFullInfo.members) {
var memberData = groupFullInfo.members[memberIndex]; var memberData = groupFullInfo.members[memberIndex];
var userInfo = tdLibWrapper.getUserInformation(memberData.member_id.user_id) || {user:{}, bot_info:{}}; var userInfo = tdLibWrapper.getUserInformation(memberData.user_id) || {user:{}, bot_info:{}};
memberData.user = userInfo; memberData.user = userInfo;
memberData.bot_info = memberData.bot_info || {}; memberData.bot_info = memberData.bot_info || {};
membersList.append(memberData); membersList.append(memberData);
@ -187,14 +187,6 @@ SilicaFlickable {
chatInformationPage.chatInformation = newInformation chatInformationPage.chatInformation = newInformation
} }
} }
onChatNotificationSettingsUpdated: {
if (chatInformationPage.chatInformation.id.toString() === chatId) {
// set whole object to trigger change
var newInformation = chatInformation;
newInformation.notification_settings = chatNotificationSettings;
chatInformationPage.chatInformation = newInformation;
}
}
} }
Component.onCompleted: { Component.onCompleted: {
@ -240,7 +232,7 @@ SilicaFlickable {
MenuItem { MenuItem {
visible: chatInformationPage.isPrivateChat visible: chatInformationPage.isPrivateChat
onClicked: { onClicked: {
tdLibWrapper.createNewSecretChat(chatInformationPage.chatPartnerGroupId, "openDirectly"); tdLibWrapper.createNewSecretChat(chatInformationPage.chatPartnerGroupId);
} }
text: qsTr("New Secret Chat") text: qsTr("New Secret Chat")
} }
@ -264,10 +256,6 @@ SilicaFlickable {
} }
return 1 - Math.max(0, Math.min(1, contentFlickable.contentY / maxDimension)) return 1 - Math.max(0, Math.min(1, contentFlickable.contentY / maxDimension))
} }
property bool thumbnailVisible: imageContainer.tweenFactor > 0.8
property bool thumbnailActive: imageContainer.tweenFactor === 1.0
property var thumbnailModel: chatInformationPage.chatPartnerProfilePhotos
property int thumbnailRadius: imageContainer.minDimension / 2
function getEased(min,max,factor) { function getEased(min,max,factor) {
return min + (max-min)*factor return min + (max-min)*factor
@ -283,25 +271,23 @@ SilicaFlickable {
replacementStringHint: headerItem.title replacementStringHint: headerItem.title
width: parent.width width: parent.width
height: width height: width
radius: imageContainer.thumbnailRadius radius: imageContainer.minDimension / 2
opacity: profilePictureLoader.status !== Loader.Ready || profilePictureLoader.item.opacity < 1 ? 1.0 : 0.0 opacity: profilePictureLoader.status !== Loader.Ready || profilePictureLoader.item.opacity < 1 ? 1.0 : 0.0
optimizeImageSize: false optimizeImageSize: false
} }
Loader { Loader {
id: profilePictureLoader id: profilePictureLoader
active: imageContainer.hasImage active: imageContainer.hasImage
asynchronous: true asynchronous: true
anchors.fill: chatPictureThumbnail anchors.fill: chatPictureThumbnail
source: ( chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) source: ( chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat)
? "../ProfilePictureList.qml" ? "ChatInformationProfilePictureList.qml"
: "ChatInformationProfilePicture.qml" : "ChatInformationProfilePicture.qml"
} }
} }
leftMargin: imageContainer.getEased((imageContainer.minDimension + Theme.paddingMedium), 0, imageContainer.tweenFactor) + Theme.horizontalPageMargin leftMargin: imageContainer.getEased((imageContainer.minDimension + Theme.paddingMedium), 0, imageContainer.tweenFactor) + Theme.horizontalPageMargin
title: chatInformationPage.chatInformation.title !== "" ? Emoji.emojify(chatInformationPage.chatInformation.title, Theme.fontSizeLarge) : qsTr("Unknown") title: chatInformationPage.chatInformation.title !== "" ? Emoji.emojify(chatInformationPage.chatInformation.title, Theme.fontSizeLarge) : qsTr("Unknown")
description: ((chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) && chatInformationPage.privateChatUserInformation.usernames.editable_username) description: (chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) ? ("@"+(chatInformationPage.privateChatUserInformation.username || chatInformationPage.chatPartnerGroupId)) : ""
? ("@"+chatInformationPage.privateChatUserInformation.usernames.editable_username) : ""
} }
SilicaFlickable { SilicaFlickable {
@ -364,28 +350,7 @@ SilicaFlickable {
height: imageContainer.hasImage ? imageContainer.maxDimension : 0 height: imageContainer.hasImage ? imageContainer.maxDimension : 0
} }
Label { ChatInformationEditArea {
id: copyIdText
x: Math.max(headerItem.x + imageContainer.x - groupInfoItem.x + (imageContainer.width - width)/2, 0)
text: chatInformationPage.chatPartnerGroupId
font.pixelSize: Theme.fontSizeSmall
color: copyIdMouseArea.pressed ? Theme.secondaryHighlightColor : Theme.highlightColor
visible: text !== ""
MouseArea {
id: copyIdMouseArea
anchors {
fill: parent
margins: -Theme.paddingLarge
}
onClicked: {
Clipboard.text = copyIdText.text
appNotification.show(qsTr("ID has been copied to the clipboard."));
}
}
}
InformationEditArea {
visible: canEdit visible: canEdit
canEdit: !(chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) && chatInformationPage.groupInformation.status && (chatInformationPage.groupInformation.status.can_change_info || chatInformationPage.groupInformation.status["@type"] === "chatMemberStatusCreator") canEdit: !(chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) && chatInformationPage.groupInformation.status && (chatInformationPage.groupInformation.status.can_change_info || chatInformationPage.groupInformation.status["@type"] === "chatMemberStatusCreator")
headerText: qsTr("Chat Title", "group title header") headerText: qsTr("Chat Title", "group title header")
@ -411,7 +376,7 @@ SilicaFlickable {
} }
} }
} }
InformationEditArea { ChatInformationEditArea {
canEdit: ((chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) && chatInformationPage.privateChatUserInformation.id === chatInformationPage.myUserId) || ((chatInformationPage.isBasicGroup || chatInformationPage.isSuperGroup) && chatInformationPage.groupInformation && (chatInformationPage.groupInformation.status.can_change_info || chatInformationPage.groupInformation.status["@type"] === "chatMemberStatusCreator")) canEdit: ((chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) && chatInformationPage.privateChatUserInformation.id === chatInformationPage.myUserId) || ((chatInformationPage.isBasicGroup || chatInformationPage.isSuperGroup) && chatInformationPage.groupInformation && (chatInformationPage.groupInformation.status.can_change_info || chatInformationPage.groupInformation.status["@type"] === "chatMemberStatusCreator"))
emptyPlaceholderText: qsTr("There is no information text available, yet.") emptyPlaceholderText: qsTr("There is no information text available, yet.")
headerText: qsTr("Info", "group or user infotext header") headerText: qsTr("Info", "group or user infotext header")
@ -426,7 +391,7 @@ SilicaFlickable {
} }
} }
InformationTextItem { ChatInformationTextItem {
headerText: qsTr("Phone Number", "user phone number header") headerText: qsTr("Phone Number", "user phone number header")
text: ((chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) && chatInformationPage.privateChatUserInformation.phone_number ? "+"+chatInformationPage.privateChatUserInformation.phone_number : "") || "" text: ((chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) && chatInformationPage.privateChatUserInformation.phone_number ? "+"+chatInformationPage.privateChatUserInformation.phone_number : "") || ""
isLinkedLabel: true isLinkedLabel: true
@ -443,7 +408,7 @@ SilicaFlickable {
Row { Row {
width: parent.width width: parent.width
visible: !!inviteLinkItem.text visible: !!inviteLinkItem.text
InformationTextItem { ChatInformationTextItem {
id: inviteLinkItem id: inviteLinkItem
text: !(chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) ? chatInformationPage.groupFullInformation.invite_link : "" text: !(chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) ? chatInformationPage.groupFullInformation.invite_link : ""
width: parent.width - inviteLinkButton.width width: parent.width - inviteLinkButton.width

View file

@ -22,8 +22,8 @@ import Sailfish.Silica 1.0
import "../" import "../"
Item { Item {
visible: parent.thumbnailVisible && chatPictureDetail.imageStatus === Image.Ready visible: imageContainer.tweenFactor > 0.8 && chatPictureDetail.imageStatus === Image.Ready
property bool isActive: parent.thumbnailActive property bool isActive: imageContainer.tweenFactor === 1.0
opacity: isActive ? 1.0 : 0.0 opacity: isActive ? 1.0 : 0.0
Behavior on opacity { FadeAnimation {} } Behavior on opacity { FadeAnimation {} }
ProfileThumbnail { ProfileThumbnail {

View file

@ -1,5 +1,5 @@
/* /*
Copyright (C) 2020-21 Sebastian J. Wolf and other contributors Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber. This file is part of Fernschreiber.
@ -18,25 +18,25 @@
*/ */
import QtQuick 2.6 import QtQuick 2.6
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import "../"
Item { Item {
id: profilePictureListItem visible: imageContainer.tweenFactor > 0.8 && bigProfilePictureList.count > 0
visible: imageContainer.thumbnailVisible && bigProfilePictureList.count > 0 property bool isActive: imageContainer.tweenFactor === 1.0
property bool isActive: imageContainer.thumbnailActive
readonly property int currentPictureIndex: bigProfilePictureList.currentIndex
opacity: isActive ? 1.0 : 0.0 opacity: isActive ? 1.0 : 0.0
Behavior on opacity { FadeAnimation {} } Behavior on opacity { FadeAnimation {} }
SlideshowView { SlideshowView {
id: bigProfilePictureList id: bigProfilePictureList
property bool isActive: imageContainer.tweenFactor === 1.0
width: parent.width width: parent.width
height: parent.height height: parent.height
clip: true clip: true
itemWidth: width itemWidth: width
itemHeight: height itemHeight: height
interactive: parent.isActive interactive: parent.isActive
model: imageContainer.thumbnailModel model: chatInformationPage.chatPartnerProfilePhotos
delegate: Item { delegate: Item {
width: bigProfilePictureList.itemWidth width: bigProfilePictureList.itemWidth
height: bigProfilePictureList.itemHeight height: bigProfilePictureList.itemHeight
@ -44,13 +44,13 @@ Item {
id: chatPictureDetail id: chatPictureDetail
photoData: modelData.sizes[modelData.sizes.length - 1].photo photoData: modelData.sizes[modelData.sizes.length - 1].photo
replacementStringHint: "" replacementStringHint: ""
radius: imageContainer.thumbnailRadius radius: chatPictureThumbnail.radius
anchors.fill: parent anchors.fill: parent
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: { onClicked: {
pageStack.push(Qt.resolvedUrl("../pages/ImagePage.qml"), { "photoData" : modelData }); pageStack.push(Qt.resolvedUrl("../../pages/ImagePage.qml"), { "photoData" : modelData });
} }
} }
} }
@ -58,18 +58,16 @@ Item {
Text { Text {
visible: bigProfilePictureList.count > 1 visible: bigProfilePictureList.count > 1
width: parent.width - Theme.paddingSmall width: parent.width
anchors { anchors {
bottomMargin: Theme.paddingSmall bottomMargin: Theme.paddingSmall
bottom: parent.bottom bottom: parent.bottom
} }
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
property var baseString: new Array(bigProfilePictureList.count+1).join(" ○ ") property var baseString: new Array(bigProfilePictureList.count+1).join(" ○ ")
text: (baseString.substring(0,bigProfilePictureList.currentIndex*3) + " ● " + baseString.substring((bigProfilePictureList.currentIndex+1)*3)).trim() text: baseString.substring(0,bigProfilePictureList.currentIndex*3) + " ● " + baseString.substring((bigProfilePictureList.currentIndex+1)*3)
font.pixelSize: Theme.fontSizeTiny
color: Theme.primaryColor color: Theme.primaryColor
style: Text.Raised style: Text.Raised
styleColor: Theme.highlightDimmerColor styleColor: Theme.highlightDimmerColor
} }
} }

View file

@ -38,18 +38,18 @@ ChatInformationTabItemBase {
width: tabBase.width - Theme.horizontalPageMargin * 2 width: tabBase.width - Theme.horizontalPageMargin * 2
x: Theme.horizontalPageMargin x: Theme.horizontalPageMargin
InformationTextItem { ChatInformationTextItem {
headerText: "chatInformation" headerText: "chatInformation"
text:chatInformationPage.chatInformation ? JSON.stringify(chatInformationPage.chatInformation, null, 2) : "" text:chatInformationPage.chatInformation ? JSON.stringify(chatInformationPage.chatInformation, null, 2) : ""
isLinkedLabel: true isLinkedLabel: true
} }
InformationTextItem { ChatInformationTextItem {
headerText: "groupInformation" headerText: "groupInformation"
text: chatInformationPage.groupInformation ? JSON.stringify(chatInformationPage.groupInformation, null, 2) : "" text: chatInformationPage.groupInformation ? JSON.stringify(chatInformationPage.groupInformation, null, 2) : ""
isLinkedLabel: true isLinkedLabel: true
} }
InformationTextItem { ChatInformationTextItem {
headerText: "groupFullInformation" headerText: "groupFullInformation"
text: chatInformationPage.groupFullInformation ? JSON.stringify(chatInformationPage.groupFullInformation, null, 2) : "" text: chatInformationPage.groupFullInformation ? JSON.stringify(chatInformationPage.groupFullInformation, null, 2) : ""
isLinkedLabel: true isLinkedLabel: true

View file

@ -72,14 +72,14 @@ ChatInformationTabItemBase {
} }
delegate: PhotoTextsListItem { delegate: PhotoTextsListItem {
pictureThumbnail { pictureThumbnail {
photoData: user.profile_photo ? user.profile_photo.small : null photoData: (typeof user.profile_photo !== "undefined") ? user.profile_photo.small : ""
} }
width: parent.width width: parent.width
// chat title // chat title
primaryText.text: Emoji.emojify(Functions.getUserName(user), primaryText.font.pixelSize) primaryText.text: Emoji.emojify(Functions.getUserName(user), primaryText.font.pixelSize)
// last user // last user
prologSecondaryText.text: "@"+(user.username ? user.username : member_id.user_id) + (member_id.user_id === chatInformationPage.myUserId ? " " + qsTr("You") : "") prologSecondaryText.text: "@"+(user.username !== "" ? user.username : user_id) + (user_id === chatInformationPage.myUserId ? " " + qsTr("You") : "")
secondaryText { secondaryText {
horizontalAlignment: Text.AlignRight horizontalAlignment: Text.AlignRight
property string statusText: Functions.getChatMemberStatusText(model.status["@type"]) property string statusText: Functions.getChatMemberStatusText(model.status["@type"])
@ -92,7 +92,7 @@ ChatInformationTabItemBase {
} }
onClicked: { onClicked: {
tdLibWrapper.createPrivateChat(member_id.user_id, "openDirectly"); tdLibWrapper.createPrivateChat(user_id);
} }
} }
footer: Component { footer: Component {
@ -154,6 +154,15 @@ ChatInformationTabItemBase {
pageStack.pop(pageStack.find( function(page){ return(page._depth === 0)} ), PageStackAction.Immediate); pageStack.pop(pageStack.find( function(page){ return(page._depth === 0)} ), PageStackAction.Immediate);
pageStack.push(Qt.resolvedUrl("../../pages/ChatPage.qml"), { "chatInformation" : display }); pageStack.push(Qt.resolvedUrl("../../pages/ChatPage.qml"), { "chatInformation" : display });
} }
Connections {
target: chatListModel
onChatChanged: {
if (changedChatId === chat_id) {
// Force update of some list item elements (currently only last message text seems to create problems). dataChanged() doesn't seem to trigger them all :(
secondaryText.text = last_message_text ? Emoji.emojify(Functions.enhanceHtmlEntities(last_message_text), Theme.fontSizeExtraSmall) : qsTr("Unknown")
}
}
}
} }
} }
@ -162,7 +171,7 @@ ChatInformationTabItemBase {
interval: 600 interval: 600
property int fetchLimit: 50 property int fetchLimit: 50
onTriggered: { onTriggered: {
if(chatInformationPage.isSuperGroup && (!chatInformationPage.isChannel || chatInformationPage.canGetMembers) && (chatInformationPage.groupInformation.member_count > membersView.count)) { if(chatInformationPage.isSuperGroup && !chatInformationPage.isChannel && (chatInformationPage.groupInformation.member_count > membersView.count)) { //
tabBase.loading = true tabBase.loading = true
tdLibWrapper.getSupergroupMembers(chatInformationPage.chatPartnerGroupId, fetchLimit, pageContent.membersList.count); tdLibWrapper.getSupergroupMembers(chatInformationPage.chatPartnerGroupId, fetchLimit, pageContent.membersList.count);
fetchLimit = 200 fetchLimit = 200
@ -179,10 +188,7 @@ ChatInformationTabItemBase {
if(members && members.length > 0 && chatInformationPage.groupInformation.member_count > membersView.count) { if(members && members.length > 0 && chatInformationPage.groupInformation.member_count > membersView.count) {
for(var memberIndex in members) { for(var memberIndex in members) {
var memberData = members[memberIndex]; var memberData = members[memberIndex];
var userInfo = tdLibWrapper.getUserInformation(memberData.member_id.user_id) || {user:{}, bot_info:{}}; var userInfo = tdLibWrapper.getUserInformation(memberData.user_id) || {user:{}, bot_info:{}};
if (!userInfo.username && userInfo.usernames && userInfo.usernames.active_usernames) {
userInfo.username = userInfo.usernames.active_usernames[0]
}
memberData.user = userInfo; memberData.user = userInfo;
memberData.bot_info = memberData.bot_info || {}; memberData.bot_info = memberData.bot_info || {};
pageContent.membersList.append(memberData); pageContent.membersList.append(memberData);

View file

@ -1,5 +1,5 @@
/* /*
Copyright (C) 2020-21 Sebastian J. Wolf and other contributors Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber. This file is part of Fernschreiber.
@ -16,12 +16,11 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>. along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/ */
import QtQuick 2.6 import QtQuick 2.6
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import "../js/twemoji.js" as Emoji import "../../js/twemoji.js" as Emoji
import "../js/functions.js" as Functions import "../../js/functions.js" as Functions
Column { Column {
id: textItem id: textItem
@ -48,7 +47,7 @@ Column {
id: labelComponent id: labelComponent
Label { Label {
wrapMode: Text.WrapAtWordBoundaryOrAnywhere wrapMode: Text.WrapAtWordBoundaryOrAnywhere
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeSmall
textFormat: Text.StyledText textFormat: Text.StyledText
color: Theme.primaryColor color: Theme.primaryColor
text: Emoji.emojify( Functions.replaceUrlsWithLinks(textItem.text).replace(/\n/g, "<br>"), Theme.fontSizeExtraSmall) text: Emoji.emojify( Functions.replaceUrlsWithLinks(textItem.text).replace(/\n/g, "<br>"), Theme.fontSizeExtraSmall)

View file

@ -1,33 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
BackgroundItem {
id: queryResultItem
function sendInlineQueryResultMessage() {
tdLibWrapper.sendInlineQueryResultMessage(inlineQueryLoader.chatId, 0, 0, inlineQueryComponent.inlineQueryId, model.id);
inlineQueryLoader.textField.text = "";
}
onClicked: {
sendInlineQueryResultMessage()
}
}

View file

@ -1,291 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import QtMultimedia 5.6
import WerkWolf.Fernschreiber 1.0
import QtGraphicalEffects 1.0
import Nemo.Thumbnailer 1.0
import "../"
import "../../js/twemoji.js" as Emoji
import "../../js/debug.js" as Debug
InlineQueryResult {
id: queryResultItem
property bool isAnimation: true
property bool loopPreview: isAnimation
property bool mutePreview: isAnimation
enabled: false // don't send on click
layer.enabled: mouseArea.pressed
layer.effect: PressEffect { source: queryResultItem }
property string animationKey: "animation"
property bool hasThumbnail: !!model[queryResultItem.animationKey].thumbnail
property string videoMimeType: "video/mp4"
TDLibFile {
id: file
tdlib: tdLibWrapper
autoLoad: true
fileInformation: hasThumbnail ? model[queryResultItem.animationKey].thumbnail.file : (queryResultItem.isAnimation ? model[queryResultItem.animationKey].animation : model[queryResultItem.animationKey].video)
}
Image {
id: miniThumbnail
asynchronous: true
source: model[queryResultItem.animationKey].minithumbnail ? "data:image/jpg;base64,"+model[queryResultItem.animationKey].minithumbnail.data : ""
anchors.fill: parent
fillMode: Image.PreserveAspectCrop
layer.enabled: queryResultItem.pressed
layer.effect: PressEffect { source: miniThumbnail }
}
Component {
id: videoThumbnail
Thumbnail {
id: thumbnail
source: file.path
sourceSize.width: width
sourceSize.height: height
mimeType: queryResultItem.videoMimeType
layer.enabled: queryResultItem.pressed
layer.effect: PressEffect { source: thumbnail }
opacity: status === Thumbnail.Ready ? 1.0 : 0.0
Behavior on opacity { FadeAnimation {} }
}
}
Component {
id: imageThumbnail
Image {
id: thumbnail
source: file.path
sourceSize.width: width
sourceSize.height: height
layer.enabled: queryResultItem.pressed
layer.effect: PressEffect { source: thumbnail }
fillMode: Image.PreserveAspectCrop
opacity: status === Image.Ready ? 1.0 : 0.0
Behavior on opacity { FadeAnimation {} }
onStatusChanged: {
// we don't get many hints what may be wrong, so we guess it may be a webp image ;)
if(status === Image.Error) {
Debug.log("Inline Query Video: Thumbnail invalid. Blindly trying webp, which might work.")
queryResultItem.videoMimeType = "image/webp";
thumbnailLoader.sourceComponent = videoThumbnail;
}
}
}
}
Loader {
id: thumbnailLoader
asynchronous: true
active: file.isDownloadingCompleted
anchors.fill: parent
sourceComponent: queryResultItem.hasThumbnail ? (model[queryResultItem.animationKey].thumbnail.format["@type"] === "thumbnailFormatMpeg4" ? videoThumbnail : imageThumbnail) : model[queryResultItem.animationKey].mime_type === "video/mp4" ? videoThumbnail : imageThumbnail
}
Column {
id: texts
anchors {
left: parent.left
margins: Theme.paddingSmall
right: parent.right
bottom: parent.bottom
}
Label {
id: titleLabel
width: parent.width
font.pixelSize: Theme.fontSizeTiny
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.Wrap
visible: text.length > 0
text: Emoji.emojify(model.title || "", font.pixelSize);
}
Label {
id: descriptionLabel
width: parent.width
font.pixelSize: Theme.fontSizeTiny
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.Wrap
visible: text.length > 0
text: Emoji.emojify(model.description || "", font.pixelSize);
}
}
Loader {
anchors.fill: texts
asynchronous: true
active: titleLabel.visible || descriptionLabel.visible
sourceComponent: Component {
DropShadow {
horizontalOffset: 0
verticalOffset: 0
radius: Theme.paddingSmall
spread: 0.5
samples: 17
color: Theme.overlayBackgroundColor
source: texts
}
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
onClicked: {
// dialog
var dialog = pageStack.push(dialogComponent,{})
dialog.accepted.connect(function() {
queryResultItem.sendInlineQueryResultMessage();
})
}
}
Component {
id: dialogComponent
Dialog {
TDLibFile {
id: previewFile
tdlib: tdLibWrapper
autoLoad: model[queryResultItem.animationKey].mime_type !== "text/html"
fileInformation: queryResultItem.isAnimation ? model[queryResultItem.animationKey].animation : model[queryResultItem.animationKey].video
}
DialogHeader { id: dialogHeader }
ProgressCircle {
value: previewFile.downloadedSize / previewFile.expectedSize
width: Theme.iconSizeMedium
height: Theme.iconSizeMedium
anchors.centerIn: parent
opacity: previewFile.isDownloadingActive ? 1.0 : 0.0
Behavior on opacity { FadeAnimation {} }
}
Column {
visible: !previewFile.autoLoad
spacing: Theme.paddingLarge
anchors {
left: parent.left
leftMargin: Theme.horizontalPageMargin
right: parent.right
rightMargin: Theme.horizontalPageMargin
verticalCenter: parent.verticalCenter
}
Label {
width: parent.width
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: Theme.secondaryHighlightColor
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
text: Emoji.emojify(model.title || "", font.pixelSize);
visible: text.length > 1
linkColor: Theme.primaryColor
}
Label {
width: parent.width
font.pixelSize: Theme.fontSizeLarge
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: Theme.highlightColor
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
text: '<a href="'+Emoji.emojify(previewFile.fileInformation.remote.id, font.pixelSize)+'">'+Emoji.emojify(previewFile.fileInformation.remote.id, font.pixelSize)+'</a> '
linkColor: Theme.primaryColor
}
Label {
width: parent.width
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: Theme.secondaryHighlightColor
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
text: Emoji.emojify(model.description || "", font.pixelSize)
visible: text.length > 1
linkColor: Theme.secondaryColor
}
}
Loader {
id: videoLoader
anchors {
top: dialogHeader.bottom
left: parent.left
right: parent.right
bottom: parent.bottom
}
active: previewFile.isDownloadingCompleted
asynchronous: true
sourceComponent: Component {
Item {
Connections {
target: resultView
onRequestPlayback: {
if(previewVideo.playbackState === MediaPlayer.PlayingState && previewVideo.source !== playbackSource) {
previewVideo.pause()
}
}
}
Timer {
id: loopTimer
interval: 0
onTriggered: previewVideo.play()
}
Video {
id: previewVideo
source: previewFile.path
autoPlay: true
muted: queryResultItem.mutePreview
anchors.fill: parent
onStatusChanged: {
if (status == MediaPlayer.EndOfMedia) {
if(queryResultItem.loopPreview) {
loopTimer.start()
}
}
}
onPlaybackStateChanged: {
if(playbackState === MediaPlayer.PlayingState) {
resultView.requestPlayback(source);
}
}
layer.enabled: playPauseMouseArea.pressed
layer.effect: PressEffect { source: previewVideo }
}
MouseArea {
id: playPauseMouseArea
anchors.fill: parent
onClicked: {
if(previewVideo.playbackState === MediaPlayer.PlayingState) {
previewVideo.pause();
} else {
previewVideo.play();
}
}
}
}
}
}
}
}
}

View file

@ -1,43 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
import "../../js/twemoji.js" as Emoji
InlineQueryResultDefaultBase {
id: queryResultItem
title: Emoji.emojify(model.title || "", titleLable.font.pixelSize)
description: Emoji.emojify(model.description || "", descriptionLabel.font.pixelSize)
descriptionLabel {
maximumLineCount: 3
wrapMode: extraText.length === 0 ? Text.Wrap : Text.NoWrap
}
extraText: model.url || ""
extraTextLabel.visible: !model.hide_url && extraText.length > 0
thumbnailFileInformation: model.thumbnail ? model.thumbnail.file : {}
icon.source: "image://theme/icon-m-link"
icon.visible: thumbnail.visible && thumbnail.opacity === 0
thumbnail.visible: model.thumbnail || !!model.url
}

View file

@ -1,183 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import QtMultimedia 5.6
import WerkWolf.Fernschreiber 1.0
import "../"
import "../../js/twemoji.js" as Emoji
InlineQueryResult {
id: queryResultItem
property var resultData: model.audio || model.voice_note
property var audioData: resultData.audio || resultData.voice
enabled: false // don't send on click
Connections {
target: resultView
onRequestPlayback: {
if(audioPlayer.playbackState === Audio.PlayingState && audioPlayer.source !== playbackSource) {
audioPlayer.pause()
}
}
}
TDLibFile {
id: file
tdlib: tdLibWrapper
autoLoad: false
fileInformation: queryResultItem.audioData
}
TDLibFile {
id: thumbnail
tdlib: tdLibWrapper
autoLoad: true
fileInformation: queryResultItem.resultData.album_cover_thumbnail ? queryResultItem.resultData.album_cover_thumbnail.file : {}
}
Loader {
id: thumbnailLoader
asynchronous: true
active: thumbnail.isDownloadingCompleted
height: parent.height
width: height
opacity: item && item.status === Image.Ready ? 0.5 : 0.0
Behavior on opacity { FadeAnimation {} }
sourceComponent: Component {
Image {
id: thumbnailImage
source: thumbnail.path
sourceSize.width: width
sourceSize.height: height
layer.enabled: playPauseButton.pressed
layer.effect: PressEffect { source: thumbnailImage }
}
}
}
IconButton {
id: playPauseButton
anchors.centerIn: thumbnailLoader
icon {
asynchronous: true
source: audioPlayer.playbackState === Audio.PlayingState || (file.isDownloadingActive && audioPlayer.autoPlay) ? "image://theme/icon-m-pause": "image://theme/icon-m-play"
}
onClicked: {
if(!file.isDownloadingCompleted && !file.isDownloadingActive) {
file.load();
audioPlayer.autoPlay = true
} else if(file.isDownloadingActive) {
// cancel playback intent?
audioPlayer.autoPlay = false
} else if(file.isDownloadingCompleted) {
//playPause
if(audioPlayer.playbackState === Audio.PlayingState) {
audioPlayer.pause();
} else {
audioPlayer.play();
}
}
}
}
ProgressCircle {
value: file.downloadedSize / file.expectedSize
width: Theme.iconSizeMedium
height: Theme.iconSizeMedium
anchors.centerIn: playPauseButton
opacity: file.isDownloadingActive ? 1.0 : 0.0
Behavior on opacity { FadeAnimation {} }
}
Audio {
id: audioPlayer
source: file.isDownloadingCompleted ? file.path : ""
autoPlay: false
onPlaybackStateChanged: {
if(playbackState === Audio.PlayingState) {
resultView.requestPlayback(source);
}
}
}
Column {
anchors {
left: thumbnailLoader.right
leftMargin: Theme.paddingSmall
right: sendButton.left
verticalCenter: parent.verticalCenter
}
Label {
width: parent.width
font.pixelSize: Theme.fontSizeSmall
color: Theme.highlightColor
text: Emoji.emojify(queryResultItem.resultData.performer || "", font.pixelSize)
visible: text.length > 0
truncationMode: TruncationMode.Fade
}
Label {
width: parent.width
font.pixelSize: Theme.fontSizeTiny
color: Theme.secondaryHighlightColor
text: Emoji.emojify(queryResultItem.resultData.title || model.title || "", font.pixelSize)
visible: text.length > 0
truncationMode: TruncationMode.Fade
}
Item {
height: sizeLabel.height
width: parent.width
Label {
id: durationLabel
font.pixelSize: Theme.fontSizeTiny
color: Theme.secondaryColor
text: (audioPlayer.position > 0 || audioPlayer.playbackState === Audio.PlayingState ? (Format.formatDuration(audioPlayer.position/1000, Formatter.DurationShort)+" / ") : "") + Format.formatDuration(queryResultItem.audioData.duration || (audioPlayer.duration/1000), Formatter.DurationShort)
visible: (queryResultItem.audioData.duration || (audioPlayer.duration/1000)) > 0
truncationMode: TruncationMode.Fade
}
Label {
id: sizeLabel
anchors.right: parent.right
font.pixelSize: Theme.fontSizeTiny
color: Theme.secondaryColor
text: Format.formatFileSize(file.expectedSize)
visible: file.expectedSize > 0
truncationMode: TruncationMode.Fade
}
}
}
IconButton {
id: sendButton
anchors {
right: parent.right
rightMargin: Theme.horizontalPageMargin
verticalCenter: parent.verticalCenter
}
icon {
asynchronous: true
source: "image://theme/icon-m-send"
}
onClicked: {
queryResultItem.sendInlineQueryResultMessage();
}
}
}

View file

@ -1,39 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
import "../../js/twemoji.js" as Emoji
InlineQueryResultDefaultBase {
id: queryResultItem
property string namesSeparator: model.contact.first_name && model.contact.last_name ? " " : ""
title: Emoji.emojify(model.contact.first_name + namesSeparator + model.contact.last_name || "", titleLable.font.pixelSize)
description: Emoji.emojify(model.contact.phone_number || "", descriptionLabel.font.pixelSize)
extraText: model.url || ""
extraTextLabel.visible: !model.hide_url && extraText.length > 0
thumbnailFileInformation: model.thumbnail ? model.thumbnail.file : {}
icon.source: "image://theme/icon-m-contact"
icon.visible: thumbnail.visible && thumbnail.opacity === 0
}

View file

@ -1,103 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
import "../"
InlineQueryResult {
id: queryResultItem
property alias title: titleLabel.text
property alias titleLable: titleLabel
property alias description: descriptionLabel.text
property alias descriptionLabel: descriptionLabel
property alias extraText: extraTextLabel.text
property alias extraTextLabel: extraTextLabel
property alias thumbnailFileInformation: thumbnailFile.fileInformation
property alias thumbnail: thumbnail
property alias icon: icon
Image {
id: thumbnail
source: thumbnailFile.isDownloadingCompleted ? thumbnailFile.path : ""
fillMode: Image.PreserveAspectCrop
asynchronous: true
width: visible ? Theme.itemSizeLarge : 0
height: width
opacity: status === Image.Ready ? 1.0 : 0.0
Behavior on opacity { FadeAnimation {} }
layer.enabled: queryResultItem.pressed
layer.effect: PressEffect { source: thumbnail }
TDLibFile {
id: thumbnailFile
tdlib: tdLibWrapper
autoLoad: true
}
}
Icon {
id: icon
asynchronous: true
anchors.centerIn: thumbnail
Behavior on opacity { FadeAnimation {} }
}
Column {
anchors {
left: thumbnail.right
leftMargin: thumbnail.visible ? Theme.paddingLarge : Theme.horizontalPageMargin
right: parent.right
rightMargin: Theme.horizontalPageMargin
verticalCenter: parent.verticalCenter
}
Label {
id: titleLabel
width: parent.width
font.pixelSize: Theme.fontSizeSmall
color: highlighted || !queryResultItem.enabled ? Theme.highlightColor : Theme.primaryColor
visible: text.length > 0
truncationMode: TruncationMode.Fade
}
Label {
id: descriptionLabel
width: parent.width
font.pixelSize: Theme.fontSizeTiny
color: highlighted || !queryResultItem.enabled ? Theme.secondaryColor : Theme.secondaryHighlightColor
visible: text.length > 0
truncationMode: TruncationMode.Fade
}
Label {
id: extraTextLabel
width: parent.width
font.pixelSize: Theme.fontSizeTiny
color: highlighted || !queryResultItem.enabled ? Theme.secondaryHighlightColor : Theme.secondaryColor
visible: text.length > 0
truncationMode: TruncationMode.Fade
}
}
}

View file

@ -1,49 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
import "../"
import "../../js/twemoji.js" as Emoji
Loader {
Component {
id: documentComponent
InlineQueryResultDefaultBase {
id: queryResultItem
title: Emoji.emojify(model.title || model.document.file_name || "", titleLable.font.pixelSize)
description: Emoji.emojify(model.description || model.document.file_name || "", descriptionLabel.font.pixelSize)
extraText: Format.formatFileSize(model.document.document.expected_size)
thumbnailFileInformation: model.thumbnail ? model.thumbnail.file : {}
icon.source: Theme.iconForMimeType(model.document.mime_type)
icon.visible: thumbnail.visible && thumbnail.opacity === 0
}
}
Component {
id: voiceNoteDocumentComponent
InlineQueryResultVoiceNote {
resultData: model.document
audioData: model.document.document
}
}
sourceComponent: model.document.mime_type === "audio/ogg" ? voiceNoteDocumentComponent : documentComponent
}

View file

@ -1,53 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
import "../../js/twemoji.js" as Emoji
InlineQueryResultDefaultBase {
id: queryResultItem
title: Emoji.emojify(model.game.title || "", titleLable.font.pixelSize)
description: Emoji.emojify(model.game.description || "", descriptionLabel.font.pixelSize)
descriptionLabel {
maximumLineCount: 3
wrapMode: Text.Wrap
}
icon.source: "image://theme/icon-m-game-controller"
icon.visible: thumbnail.opacity === 0
Component.onCompleted: {
if (model.game.photo) {
// Check first which size fits best...
var photo
for (var i = 0; i < model.game.photo.sizes.length; i++) {
photo = model.game.photo.sizes[i].photo
if (model.game.photo.sizes[i].width >= queryResultItem.width) {
break
}
}
if (photo) {
thumbnailFileInformation = photo
}
}
}
}

View file

@ -1,23 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
InlineQueryResultVenue {
resultData: model
}

View file

@ -1,29 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import "../"
InlineQueryResult {
id: queryResultItem
TDLibPhoto {
anchors.fill: parent
photo: model.photo
}
}

View file

@ -1,106 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
import Nemo.Thumbnailer 1.0
import "../"
InlineQueryResult {
id: queryResultItem
property bool animate
property bool animating: animate && model.sticker.is_animated
property url stickerId: "http://sticker/" + model.sticker.sticker.remote.id
onAnimatingChanged: {
if(animating) {
resultView.requestPlayback(stickerId);
}
}
Connections {
target: resultView
onRequestPlayback: {
if(queryResultItem.animating && queryResultItem.stickerId !== playbackSource) {
animate = false
}
}
}
onPressAndHold: {
animate = !animate
}
TDLibFile {
id: file
tdlib: tdLibWrapper
fileInformation: model.sticker.sticker
autoLoad: true
}
Loader {
id: animatedStickerLoader
anchors {
fill: parent
margins: Theme.paddingLarge
}
active: queryResultItem.animating
sourceComponent: Component {
AnimatedImage {
id: animatedSticker
anchors.fill: parent
source: file.path
asynchronous: true
paused: !Qt.application.active
cache: false
layer.enabled: highlighted
layer.effect: PressEffect { source: animatedSticker }
}
}
}
Image {
id: staticSticker
anchors {
fill: parent
margins: Theme.paddingLarge
}
source: file.path
fillMode: Image.PreserveAspectFit
autoTransform: true
asynchronous: true
visible: !queryResultItem.animating && opacity > 0
opacity: status === Image.Ready ? 1 : 0
Behavior on opacity { FadeAnimation {} }
layer.enabled: queryResultItem.highlighted
layer.effect: PressEffect { source: staticSticker }
}
Icon {
source: "image://theme/icon-m-video"
width: Theme.iconSizeExtraSmall
height: width
visible: model.sticker.is_animated
highlighted: queryResultItem.highlighted || queryResultItem.animating
anchors {
right: parent.right
bottom: parent.bottom
}
}
}

View file

@ -1,51 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
import "../../js/twemoji.js" as Emoji
InlineQueryResultDefaultBase {
id: queryResultItem
property string locationId
property var resultData: model.venue
title: Emoji.emojify(queryResultItem.resultData.title || (queryResultItem.resultData.location.latitude + ":" + queryResultItem.resultData.location.longitude), titleLable.font.pixelSize)
description: Emoji.emojify(queryResultItem.resultData.address || "", descriptionLabel.font.pixelSize)
extraText: Emoji.emojify(queryResultItem.resultData.type || "", extraTextLabel.font.pixelSize)
Connections {
target: tdLibWrapper
onFileUpdated: {
if(fileInformation["@extra"] === queryResultItem.locationId) {
thumbnailFileInformation = fileInformation
}
}
}
Component.onCompleted: {
var dimensions = [ Math.round(thumbnail.width), Math.round(thumbnail.height)];
locationId = "location:" + resultData.location.latitude + ":" + resultData.location.longitude + ":" + dimensions[0] + ":" + dimensions[1];
tdLibWrapper.getMapThumbnailFile(chatId, resultData.location.latitude, resultData.location.longitude, dimensions[0], dimensions[1], locationId);
}
}

View file

@ -1,25 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
InlineQueryResultAnimation {
isAnimation: false
animationKey: "video"
}

View file

@ -1,24 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
InlineQueryResultAudio {
}

View file

@ -1,27 +0,0 @@
/*
Copyright (C) 2020-21 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
import "../"
import "../../js/twemoji.js" as Emoji
MessageSticker {
stickerData: messageListItem ? messageListItem.myMessage.content.animated_emoji.sticker : overlayFlickable.overlayMessage.content.animated_emoji.sticker;
}

View file

@ -1,21 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
MessageVideo {}

View file

@ -1,96 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import QtMultimedia 5.6
import "../"
import "../../js/twemoji.js" as Emoji
import "../../js/functions.js" as Functions
import "../../js/debug.js" as Debug
MessageContentFileInfoBase {
id: contentItem
fileInformation: rawMessage.content.audio.audio
thumbnail: rawMessage.content.audio.album_cover_thumbnail
minithumbnail: rawMessage.content.audio.album_cover_minithumbnail
primaryText: Emoji.emojify(rawMessage.content.audio.performer, primaryLabel.font.pixelSize)
secondaryText: Emoji.emojify(rawMessage.content.audio.title, secondaryLabel.font.pixelSize)
tertiaryLabel.visible: (duration || (audioPlayer.duration/1000)) > 0
tertiaryText: (audioPlayer.position > 0 || audioPlayer.playbackState === Audio.PlayingState ? (Format.formatDuration(audioPlayer.position/1000, Formatter.DurationShort)+" / ") : "") + Format.formatDuration(contentItem.duration > 0 ? contentItem.duration : (audioPlayer.duration/1000), Formatter.DurationShort)
leftButton {
icon.source: audioPlayer.playbackState === Audio.PlayingState || (file.isDownloadingActive && audioPlayer.autoPlay) ? "image://theme/icon-m-pause": "image://theme/icon-m-play"
onClicked: {
if(!file.isDownloadingCompleted && !file.isDownloadingActive) {
file.load();
audioPlayer.autoPlay = true;
} else if(file.isDownloadingActive) {
audioPlayer.autoPlay = false;
file.cancel();
} else if(file.isDownloadingCompleted) {
//playPause
if(audioPlayer.playbackState === Audio.PlayingState) {
audioPlayer.pause();
} else {
audioPlayer.play();
}
}
}
}
property int duration: rawMessage.content.audio.duration
Audio {
id: audioPlayer
source: file.isDownloadingCompleted ? file.path : ""
autoPlay: false
}
Slider {
width: parent.width
anchors {
left: parent.left
leftMargin: -Screen.width/16
right: parent.right
rightMargin: -Screen.width/16
top: primaryItem.bottom
topMargin: -height/3
}
minimumValue: 0
maximumValue: audioPlayer.duration ? audioPlayer.duration : 0.1
stepSize: 1
value: audioPlayer.position
enabled: audioPlayer.seekable
visible: file.isDownloadingCompleted && audioPlayer.playbackState === Audio.PlayingState || audioPlayer.playbackState === Audio.PausedState
opacity: visible ? 1.0 : 0.0
Behavior on opacity { FadeAnimation {} }
height: visible ? implicitHeight : 0
Behavior on height { NumberAnimation { duration: 200 } }
highlighted: contentItem.highlighted || down
onReleased: {
audioPlayer.seek(Math.floor(value));
audioPlayer.play();
}
}
}

View file

@ -1,32 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import QtMultimedia 5.6
import "../"
import "../../js/functions.js" as Functions
import "../../js/debug.js" as Debug
Item {
property ListItem messageListItem
property MessageOverlayFlickable overlayFlickable
property var rawMessage: messageListItem ? messageListItem.myMessage : overlayFlickable.overlayMessage
property bool highlighted
signal clicked()
}

View file

@ -1,201 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import QtMultimedia 5.6
import WerkWolf.Fernschreiber 1.0
import QtGraphicalEffects 1.0
import "../"
import "../../js/functions.js" as Functions
import "../../js/twemoji.js" as Emoji
import "../../js/debug.js" as Debug
MessageContentBase {
id: contentItem
height: childrenRect.height
property alias fileInformation: file.fileInformation
property alias primaryLabel: primaryLabel
property alias primaryText: primaryLabel.text
property alias secondaryLabel: secondaryLabel
property alias secondaryText: secondaryLabel.text
property alias tertiaryLabel: tertiaryLabel
property alias tertiaryText: tertiaryLabel.text
property var thumbnail
property var minithumbnail
readonly property alias file: file
readonly property alias primaryItem: primaryItem
readonly property alias leftButton: leftButton
readonly property alias labelsColumn: labelsColumn
readonly property alias copyButton: copyButton
// readonly property alias downloadNeededIndicatorIcon: downloadNeededIndicatorIcon
TDLibFile {
id: file
tdlib: tdLibWrapper
autoLoad: false
}
Item {
id: primaryItem
width: parent.width
height: Theme.itemSizeLarge
Loader {
active: contentItem.thumbnail || contentItem.minithumbnail
visible: active
anchors.fill: leftButton
sourceComponent: Component {
TDLibThumbnail {
opacity: 0.3
thumbnail: contentItem.thumbnail
minithumbnail: contentItem.minithumbnail
}
}
}
IconButton {
id: leftButton
highlighted: down || contentItem.highlighted
anchors.verticalCenter: parent.verticalCenter
icon {
asynchronous: true
}
ProgressCircle {
value: file.downloadedSize / file.expectedSize
progressColor: Theme.highlightColor
backgroundColor: Theme.highlightDimmerColor
width: Theme.iconSizeMedium
height: Theme.iconSizeMedium
visible: opacity > 0
opacity: file.isDownloadingActive ? 1.0 : 0.0
anchors.centerIn: parent
Behavior on opacity { FadeAnimation {} }
}
Rectangle {
anchors.centerIn: downloadNeededIndicatorIcon
width: downloadNeededIndicatorIcon.width + Theme.paddingMedium
height: width
color: Theme.rgba(Theme.overlayBackgroundColor, 0.2)
opacity: file.isDownloadingActive ? 1.0 : 0.0
Behavior on opacity { FadeAnimation {} }
visible: opacity > 0
radius: width/2
}
Icon {
id: downloadNeededIndicatorIcon
source: file.isDownloadingActive || file.isDownloadingCompleted ? "image://theme/icon-s-clear-opaque-cross" : "image://theme/icon-s-cloud-download"
asynchronous: true
width: Theme.iconSizeExtraSmall
height: width
visible: opacity > 0
sourceSize.width: width
sourceSize.height: height
opacity: file.isDownloadingCompleted ? 0.0 : 1.0
Behavior on opacity { FadeAnimation {} }
anchors {
right: parent.right
bottom: parent.bottom
margins: Theme.paddingSmall
}
}
}
Column {
id: labelsColumn
anchors {
left: leftButton.right
leftMargin: Theme.paddingSmall
right: copyButton.left
verticalCenter: leftButton.verticalCenter
}
Label {
id: primaryLabel
width: parent.width
font.pixelSize: Theme.fontSizeSmall
fontSizeMode: Text.HorizontalFit
minimumPixelSize: Theme.fontSizeTiny
color: Theme.highlightColor
visible: text.length > 0
truncationMode: TruncationMode.Fade
}
Label {
id: secondaryLabel
width: parent.width
font.pixelSize: Theme.fontSizeExtraSmall
fontSizeMode: Text.HorizontalFit
minimumPixelSize: Theme.fontSizeTiny
color: Theme.secondaryHighlightColor
visible: text.length > 0
truncationMode: TruncationMode.Fade
}
Item {
height: sizeLabel.height
width: parent.width
Label {
id: tertiaryLabel
font.pixelSize: Theme.fontSizeTiny
color: highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor
visible: text.length > 0
truncationMode: TruncationMode.Fade
}
Label {
id: sizeLabel
anchors.right: parent.right
font.pixelSize: Theme.fontSizeTiny
color: tertiaryLabel.color
text: Format.formatFileSize(file.size || file.expectedSize)
visible: (file.size || file.expectedSize) > 0
truncationMode: TruncationMode.Fade
}
}
}
IconButton {
id: copyButton
anchors {
right: parent.right
verticalCenter: parent.verticalCenter
}
opacity: file.isDownloadingCompleted ? 1.0 : 0.0
width: file.isDownloadingCompleted ? Theme.itemSizeMedium : 0
visible: opacity > 0
Behavior on opacity { FadeAnimation {} }
Behavior on width { NumberAnimation { duration: 200 } }
icon {
asynchronous: true
source: "../../../images/icon-m-copy-to-folder.svg"
sourceSize {
width: Theme.iconSizeMedium
height: Theme.iconSizeMedium
}
}
onClicked: {
tdLibWrapper.copyFileToDownloads(file.path);
// not persistent:
opacity = 0;
width = 0;
}
}
}
}

View file

@ -1,82 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import "../../js/twemoji.js" as Emoji
MessageContentFileInfoBase {
id: contentItem
fileInformation: rawMessage.content.document.document
primaryText: Emoji.emojify(rawMessage.content.document.file_name || "", primaryLabel.font.pixelSize)
secondaryText: Emoji.emojify(Functions.enhanceMessageText(rawMessage.content.caption) || "", secondaryLabel.font.pixelSize)
minithumbnail: rawMessage.content.document.minithumbnail
thumbnail: rawMessage.content.document.thumbnail
leftButton {
icon.source: Theme.iconForMimeType(rawMessage.content.document.mime_type)
onClicked: {
if(file.isDownloadingCompleted) {
// in this case, the MouseArea should take over
tdLibWrapper.copyFileToDownloads(file.path, true);
} else if(!file.isDownloadingActive) {
file.load();
} else {
file.cancel()
}
}
}
states: [
State {
when: file.isDownloadingCompleted
PropertyChanges { target: openMouseArea; enabled: true }
PropertyChanges {
target: primaryLabel
color: (contentItem.highlighted || openMouseArea.pressed) ? Theme.highlightColor : Theme.primaryColor
}
PropertyChanges {
target: secondaryLabel
color: (contentItem.highlighted || openMouseArea.pressed) ? Theme.secondaryHighlightColor : Theme.secondaryColor
}
PropertyChanges {
target: tertiaryLabel
color: (contentItem.highlighted || openMouseArea.pressed) ? Theme.secondaryHighlightColor : Theme.secondaryColor
}
PropertyChanges {
target: leftButton
highlighted: contentItem.highlighted || openMouseArea.pressed
}
}
]
MouseArea {
id: openMouseArea
enabled: file.isDownloadingCompleted
visible: enabled
anchors {
fill: primaryItem
rightMargin: copyButton.width
}
onClicked: {
tdLibWrapper.copyFileToDownloads(file.path, true);
}
}
}

View file

@ -1,128 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
import "../"
import "../../js/functions.js" as Functions
import "../../js/twemoji.js" as Emoji
MessageContentBase {
id: messageContent
height: gamePreviewItem.height
Column {
id: gamePreviewItem
width: parent.width
height: childrenRect.height
Label {
width: parent.width
font.bold: true
font.pixelSize: Theme.fontSizeSmall
text: Emoji.emojify(rawMessage.content.game.title || "", font.pixelSize)
truncationMode: TruncationMode.Fade
textFormat: Text.StyledText
wrapMode: Text.Wrap
}
Label {
width: parent.width
font.pixelSize: Theme.fontSizeExtraSmall
text: Emoji.emojify(rawMessage.content.game.description || "", font.pixelSize)
truncationMode: TruncationMode.Fade
textFormat: Text.StyledText
wrapMode: Text.Wrap
}
Label {
width: parent.width
font.pixelSize: Theme.fontSizeExtraSmall
text: Emoji.emojify(Functions.enhanceMessageText(rawMessage.content.game.text) || "", font.pixelSize)
truncationMode: TruncationMode.Fade
wrapMode: Text.Wrap
textFormat: Text.StyledText
onLinkActivated: {
var chatCommand = Functions.handleLink(link);
if(chatCommand) {
tdLibWrapper.sendTextMessage(chatInformation.id, chatCommand);
}
}
}
Item {
width: parent.width
height: Theme.paddingLarge
}
Image {
id: thumbnail
source: thumbnailFile.isDownloadingCompleted ? thumbnailFile.path : ""
fillMode: Image.PreserveAspectCrop
asynchronous: true
visible: opacity > 0
opacity: status === Image.Ready ? 1.0 : 0.0
width: parent.width
Behavior on opacity { FadeAnimation {} }
layer.enabled: messageContent.highlighted
layer.effect: PressEffect { source: thumbnail }
TDLibFile {
id: thumbnailFile
tdlib: tdLibWrapper
autoLoad: true
}
Rectangle {
width: Theme.iconSizeMedium
height: width
anchors {
top: parent.top
topMargin: Theme.paddingSmall
left: parent.left
leftMargin: Theme.paddingSmall
}
color: Theme.rgba(Theme.overlayBackgroundColor, 0.2)
radius: Theme.paddingSmall
Icon {
id: icon
source: "image://theme/icon-m-game-controller"
asynchronous: true
}
}
}
Component.onCompleted: {
if (rawMessage.content.game.photo) {
// Check first which size fits best...
var photo
for (var i = 0; i < rawMessage.content.game.photo.sizes.length; i++) {
photo = rawMessage.content.game.photo.sizes[i].photo
if (rawMessage.content.game.photo.sizes[i].width >= gamePreviewItem.width) {
break
}
}
if (photo) {
thumbnailFile.fileInformation = photo
}
}
}
}
}

View file

@ -1,91 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import QtGraphicalEffects 1.0
import Sailfish.Silica 1.0
import "../"
MessageContentBase {
id: contentItem
height: width * 0.66666666;
property var locationData : rawMessage.content.location
property string fileExtra;
onClicked: {
Qt.openUrlExternally("geo:" + locationData.latitude + "," + locationData.longitude);
}
onLocationDataChanged: updatePicture()
onWidthChanged: updatePicture()
function updatePicture() {
if (locationData) {
fileExtra = "location:" + locationData.latitude + ":" + locationData.longitude + ":" + Math.round(contentItem.width) + ":" + Math.round(contentItem.height);
tdLibWrapper.getMapThumbnailFile(rawMessage.chat_id, locationData.latitude, locationData.longitude, Math.round(contentItem.width), Math.round(contentItem.height), fileExtra);
}
}
Connections {
target: tdLibWrapper
onFileUpdated: {
if(fileInformation["@extra"] === contentItem.fileExtra) {
if(fileInformation.id !== image.file.fileId) {
image.fileInformation = fileInformation
}
}
}
}
AppNotification {
id: imageNotification
}
TDLibImage {
id: image
anchors.fill: parent
cache: false
highlighted: contentItem.highlighted
Item {
anchors.centerIn: parent
width: markerImage.width
height: markerImage.height * 1.75 // 0.875 (vertical pin point) * 2
Icon {
id: markerImage
source: 'image://theme/icon-m-location'
}
DropShadow {
anchors.fill: markerImage
horizontalOffset: 3
verticalOffset: 3
radius: 8.0
samples: 17
color: Theme.colorScheme ? Theme.lightPrimaryColor : Theme.darkPrimaryColor
source: markerImage
}
}
}
BackgroundImage {
visible: image.status !== Image.Ready
}
Component.onCompleted: {
updatePicture();
}
}

View file

@ -1,57 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import "../"
MessageContentBase {
function calculateBiggest() {
var candidateBiggest = rawMessage.content.photo.sizes[rawMessage.content.photo.sizes.length - 1];
if (candidateBiggest.width === 0 && rawMessage.content.photo.sizes.length > 1) {
for (var i = (rawMessage.content.photo.sizes.length - 2); i >= 0; i--) {
candidateBiggest = rawMessage.content.photo.sizes[i];
if (candidateBiggest.width > 0) {
break;
}
}
}
return candidateBiggest;
}
height: Math.max(Theme.itemSizeExtraSmall, Math.min(defaultHeight, width / (biggest.width/biggest.height)))
readonly property int defaultHeight: Math.round(width * 0.66666666)
readonly property var biggest: calculateBiggest();
onClicked: {
pageStack.push(Qt.resolvedUrl("../../pages/ImagePage.qml"), {
"photoData" : photo.photo,
// "pictureFileInformation" : photo.fileInformation
})
}
TDLibPhoto {
id: photo
anchors.fill: parent
photo: rawMessage.content.photo
highlighted: parent.highlighted
}
BackgroundImage {
visible: !rawMessage.content.photo.minithumbnail && photo.image.status !== Image.Ready
}
}

View file

@ -1,24 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
MessageLocation {
locationData: rawMessage.content.venue.location
}

View file

@ -1,21 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
MessageVideo {}

View file

@ -1,28 +0,0 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
MessageAudio {
fileInformation: rawMessage.content.voice_note.voice
primaryText: qsTr("Voice Note")
secondaryText: ""
duration: rawMessage.content.voice_note.duration
thumbnail: null
minithumbnail: null
}

View file

@ -1,77 +0,0 @@
/*
Copyright (C) 2021 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import QtGraphicalEffects 1.0
import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
import "../"
import "../../js/functions.js" as Functions
Column {
id: sponsoredMessageColumn
property var sponsoredMessageData;
Connections {
target: tdLibWrapper
onMessageLinkInfoReceived: {
if (sponsoredMessageData.link.url === url) {
messageOverlayLoader.overlayMessage = messageLinkInfo.message;
messageOverlayLoader.active = true;
}
}
}
Component.onCompleted: {
if (sponsoredMessageData) {
if (typeof sponsoredMessageData.link === "undefined") {
sponsoredMessageButton.text = qsTr("Go to Channel");
sponsoredMessageButton.advertisesChannel = true;
} else if (sponsoredMessageData.link['@type'] === "internalLinkTypeMessage") {
sponsoredMessageButton.text = qsTr("Go to Message");
sponsoredMessageButton.advertisesMessage = true;
} else {
sponsoredMessageButton.text = qsTr("Start Bot");
sponsoredMessageButton.advertisesBot = true;
}
}
}
Button {
id: sponsoredMessageButton
property bool advertisesChannel: false;
property bool advertisesMessage: false;
property bool advertisesBot: false;
anchors {
horizontalCenter: parent.horizontalCenter
}
onClicked: {
if (advertisesChannel) {
tdLibWrapper.createSupergroupChat(tdLibWrapper.getChat(sponsoredMessageData.sponsor_chat_id).type.supergroup_id, "openDirectly");
}
if (advertisesMessage) {
tdLibWrapper.getMessageLinkInfo(sponsoredMessageData.link.url);
}
if (advertisesBot) {
tdLibWrapper.createPrivateChat(tdLibWrapper.getUserInformationByName(sponsoredMessageData.link.bot_username).id, "openAndSendStartToBot:" + sponsoredMessageData.link.start_parameter);
}
}
}
}

View file

@ -1,42 +0,0 @@
/*
Copyright (C) 2021 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
Column {
width: parent.width
property SilicaFlickable flickable
property bool animate: false
signal setActiveArea(string activeAreaTitle)
function scrollUpFlickable(amount) {
if(flickable) {
flickableAnimation.to = Math.max(0, flickable.contentY - amount);
flickableAnimation.start()
}
}
NumberAnimation {
id: flickableAnimation
target: flickable
property: "contentY"
duration: 200
}
}

View file

@ -1,106 +0,0 @@
/*
Copyright (C) 2021 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
Item {
id: area
width: parent.width
height: button.height + content.height
property alias icon: image
property alias text: label.text
property alias asynchronous: content.asynchronous
property bool expanded: false
default property alias els: content.sourceComponent
states: [
State {
when: area.expanded
PropertyChanges { target: image; rotation: 90 }
PropertyChanges { target: content; height: content.implicitHeight + Theme.paddingLarge; opacity: 1.0 }
}
]
transitions: Transition {
to: "*"
enabled: area.parent.animate
NumberAnimation { target: content; properties: "height, opacity"; duration: 200}
NumberAnimation { target: image; properties: "rotation"; duration: 200}
}
Connections {
target: area.parent
onSetActiveArea: {
var expand = (activeAreaTitle === area.text);
if(area.expanded && !expand && area.parent.scrollUpFlickable) {
area.parent.scrollUpFlickable(content.implicitHeight + Theme.paddingLarge);
}
area.expanded = expand;
}
}
BackgroundItem {
id: button
height: Theme.itemSizeMedium
onClicked: {
area.parent.animate = true;
area.parent.setActiveArea(area.expanded ? -1 : area.text)
}
Rectangle {
anchors.fill: parent
gradient: Gradient {
GradientStop { position: 0.0; color: Theme.rgba(Theme.highlightBackgroundColor, 0.15) }
GradientStop { position: 1.0; color: "transparent" }
}
}
Label {
id: label
anchors {
left: parent.left
right: image.left
verticalCenter: parent.verticalCenter
leftMargin: Theme.horizontalPageMargin + Theme.paddingLarge
rightMargin: Theme.paddingMedium
}
horizontalAlignment: Text.AlignRight
truncationMode: TruncationMode.Fade
color: button.highlighted ? Theme.highlightColor : Theme.primaryColor
textFormat: Text.PlainText
}
HighlightImage {
id: image
anchors {
right: parent.right
verticalCenter: parent.verticalCenter
rightMargin: Theme.horizontalPageMargin
}
width: visible ? Theme.iconSizeMedium : 0
highlighted: parent.highlighted
source: "image://theme/icon-m-left"
rotation: -90
}
}
Loader {
id: content
width: parent.width
height: 0
opacity: 0
anchors.top: button.bottom
asynchronous: true
clip: true
}
}

View file

@ -1,28 +0,0 @@
/*
Copyright (C) 2021 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import "../../js/functions.js" as Functions
Grid {
width: parent.width - ( 2 * x )
columns: Functions.isWidescreen(appWindow) ? 2 : 1
readonly property real columnWidth: width/columns
}

View file

@ -1,89 +0,0 @@
/*
Copyright (C) 2021 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
AccordionItem {
text: qsTr("Appearance")
clip: heightBehavior.enabled || heightAnimation.running
// One-shot behavior
Behavior on height {
id: heightBehavior
enabled: false
SequentialAnimation {
id: heightAnimation
SmoothedAnimation { duration: 200 }
ScriptAction { script: heightBehavior.enabled = false }
}
}
Component {
ResponsiveGrid {
bottomPadding: Theme.paddingMedium
TextSwitch {
width: parent.columnWidth
checked: appSettings.showStickersAsEmojis
text: qsTr("Show stickers as emojis")
description: qsTr("Only display emojis instead of the actual stickers")
automaticCheck: false
onClicked: {
heightBehavior.enabled = true
appSettings.showStickersAsEmojis = !checked
}
}
TextSwitch {
width: parent.columnWidth
checked: appSettings.showStickersAsImages
text: qsTr("Show stickers as images")
description: qsTr("Show background for stickers and align them centrally like images")
automaticCheck: false
onClicked: {
appSettings.showStickersAsImages = !checked
}
visible: !appSettings.showStickersAsEmojis
opacity: visible ? 1 : 0
Behavior on opacity { FadeAnimation { } }
}
Item {
// Placeholder to move the next switch to the second column
visible: parent.columns === 2
width: 1
height: 1
}
TextSwitch {
width: parent.columnWidth
checked: appSettings.animateStickers
text: qsTr("Animate stickers")
automaticCheck: false
onClicked: {
appSettings.animateStickers = !checked
}
visible: !appSettings.showStickersAsEmojis
opacity: visible ? 1 : 0
Behavior on opacity { FadeAnimation { } }
}
}
}
}

View file

@ -1,221 +0,0 @@
/*
Copyright (C) 2021 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
AccordionItem {
text: qsTr("Behavior")
Component {
ResponsiveGrid {
bottomPadding: Theme.paddingMedium
TextSwitch {
width: parent.columnWidth
checked: appSettings.sendByEnter
text: qsTr("Send message by enter")
description: qsTr("Send your message by pressing the enter key")
automaticCheck: false
onClicked: {
appSettings.sendByEnter = !checked
}
}
TextSwitch {
width: parent.columnWidth
checked: appSettings.focusTextAreaOnChatOpen
text: qsTr("Focus text input on chat open")
description: qsTr("Focus the text input area when entering a chat")
automaticCheck: false
onClicked: {
appSettings.focusTextAreaOnChatOpen = !checked
}
}
TextSwitch {
width: parent.columnWidth
checked: appSettings.focusTextAreaAfterSend
text: qsTr("Focus text input area after send")
description: qsTr("Focus the text input area after sending a message")
automaticCheck: false
onClicked: {
appSettings.focusTextAreaAfterSend = !checked
}
}
TextSwitch {
width: parent.columnWidth
checked: appSettings.delayMessageRead
text: qsTr("Delay before marking messages as read")
description: qsTr("Fernschreiber will wait a bit before messages are marked as read")
automaticCheck: false
onClicked: {
appSettings.delayMessageRead = !checked
}
}
TextSwitch {
width: parent.columnWidth
checked: appSettings.highlightUnreadConversations
text: qsTr("Highlight unread messages")
description: qsTr("Highlight Conversations with unread messages")
automaticCheck: false
onClicked: {
appSettings.highlightUnreadConversations = !checked
}
}
TextSwitch {
width: parent.columnWidth
checked: appSettings.useOpenWith
text: qsTr("Open-with menu integration")
description: qsTr("Integrate Fernschreiber into open-with menu of Sailfish OS")
automaticCheck: false
onClicked: {
appSettings.useOpenWith = !checked
}
}
TextSwitch {
width: parent.columnWidth
checked: appSettings.notificationAlwaysShowPreview
text: qsTr("Always append message preview to notifications")
description: qsTr("In addition to showing the number of unread messages, the latest message will also be appended to notifications.")
automaticCheck: false
onClicked: {
appSettings.notificationAlwaysShowPreview = !checked
}
}
TextSwitch {
width: parent.columnWidth
checked: appSettings.goToQuotedMessage
text: qsTr("Go to quoted message")
description: qsTr("When tapping a quoted message, open it in chat instead of showing it in an overlay.")
automaticCheck: false
onClicked: {
appSettings.goToQuotedMessage = !checked
}
}
ComboBox {
id: feedbackComboBox
width: parent.columnWidth
label: qsTr("Notification feedback")
description: qsTr("Use non-graphical feedback (sound, vibration) for notifications")
menu: ContextMenu {
id: feedbackMenu
x: 0
width: feedbackComboBox.width
MenuItem {
readonly property int value: AppSettings.NotificationFeedbackAll
text: qsTr("All events")
onClicked: {
appSettings.notificationFeedback = value
}
}
MenuItem {
readonly property int value: AppSettings.NotificationFeedbackNew
text: qsTr("Only new events")
onClicked: {
appSettings.notificationFeedback = value
}
}
MenuItem {
readonly property int value: AppSettings.NotificationFeedbackNone
text: qsTr("None")
onClicked: {
appSettings.notificationFeedback = value
}
}
}
Component.onCompleted: updateFeedbackSelection()
function updateFeedbackSelection() {
var menuItems = feedbackMenu.children
var n = menuItems.length
for (var i=0; i<n; i++) {
if (menuItems[i].value === appSettings.notificationFeedback) {
currentIndex = i
return
}
}
}
Connections {
target: appSettings
onNotificationFeedbackChanged: {
feedbackComboBox.updateFeedbackSelection()
}
}
}
Item {
// Occupies one grid cell so that the column ends up under the combo box
// in the landscape layout
visible: parent.columns === 2
width: 1
height: 1
}
Column {
enabled: appSettings.notificationFeedback !== AppSettings.NotificationFeedbackNone
width: parent.columnWidth
height: enabled ? implicitHeight: 0
clip: height < implicitHeight
visible: height > 0
Behavior on height { SmoothedAnimation { duration: 200 } }
TextSwitch {
checked: appSettings.notificationSuppressContent && enabled
text: qsTr("Hide content in notifications")
enabled: parent.enabled
automaticCheck: false
onClicked: {
appSettings.notificationSuppressContent = !checked
}
}
TextSwitch {
checked: appSettings.notificationTurnsDisplayOn && enabled
text: qsTr("Notification turns on the display")
enabled: parent.enabled
automaticCheck: false
onClicked: {
appSettings.notificationTurnsDisplayOn = !checked
}
}
TextSwitch {
checked: appSettings.notificationSoundsEnabled && enabled
text: qsTr("Enable notification sounds")
description: qsTr("When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.")
enabled: parent.enabled
automaticCheck: false
onClicked: {
appSettings.notificationSoundsEnabled = !checked
}
}
}
}
}
}

View file

@ -1,266 +0,0 @@
/*
Copyright (C) 2021 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
AccordionItem {
text: qsTr("Privacy")
Component {
Column {
bottomPadding: Theme.paddingMedium
Connections {
target: tdLibWrapper
onUserPrivacySettingUpdated: {
Debug.log("Received updated privacy setting: " + setting + ":" + rule);
switch (setting) {
case TelegramAPI.SettingAllowChatInvites:
allowChatInvitesComboBox.currentIndex = rule;
break;
case TelegramAPI.SettingAllowFindingByPhoneNumber:
allowFindingByPhoneNumberComboBox.currentIndex = rule;
break;
case TelegramAPI.SettingShowLinkInForwardedMessages:
showLinkInForwardedMessagesComboBox.currentIndex = rule;
break;
case TelegramAPI.SettingShowPhoneNumber:
showPhoneNumberComboBox.currentIndex = rule;
break;
case TelegramAPI.SettingShowProfilePhoto:
showProfilePhotoComboBox.currentIndex = rule;
break;
case TelegramAPI.SettingShowStatus:
showStatusComboBox.currentIndex = rule;
break;
}
}
}
ResponsiveGrid {
ComboBox {
id: allowChatInvitesComboBox
width: parent.columnWidth
label: qsTr("Allow chat invites")
description: qsTr("Privacy setting for managing whether you can be invited to chats.")
menu: ContextMenu {
x: 0
width: allowChatInvitesComboBox.width
MenuItem {
text: qsTr("Yes")
onClicked: {
tdLibWrapper.setUserPrivacySettingRule(TelegramAPI.SettingAllowChatInvites, TelegramAPI.RuleAllowAll);
}
}
MenuItem {
text: qsTr("Your contacts only")
onClicked: {
tdLibWrapper.setUserPrivacySettingRule(TelegramAPI.SettingAllowChatInvites, TelegramAPI.RuleAllowContacts);
}
}
MenuItem {
text: qsTr("No")
onClicked: {
tdLibWrapper.setUserPrivacySettingRule(TelegramAPI.SettingAllowChatInvites, TelegramAPI.RuleRestrictAll);
}
}
}
Component.onCompleted: {
currentIndex = tdLibWrapper.getUserPrivacySettingRule(TelegramAPI.SettingAllowChatInvites);
}
}
ComboBox {
id: allowFindingByPhoneNumberComboBox
width: parent.columnWidth
label: qsTr("Allow finding by phone number")
description: qsTr("Privacy setting for managing whether you can be found by your phone number.")
menu: ContextMenu {
x: 0
width: allowFindingByPhoneNumberComboBox.width
MenuItem {
text: qsTr("Yes")
onClicked: {
tdLibWrapper.setUserPrivacySettingRule(TelegramAPI.SettingAllowFindingByPhoneNumber, TelegramAPI.RuleAllowAll);
}
}
MenuItem {
text: qsTr("Your contacts only")
onClicked: {
tdLibWrapper.setUserPrivacySettingRule(TelegramAPI.SettingAllowFindingByPhoneNumber, TelegramAPI.RuleAllowContacts);
}
}
}
Component.onCompleted: {
currentIndex = tdLibWrapper.getUserPrivacySettingRule(TelegramAPI.SettingAllowFindingByPhoneNumber);
}
}
ComboBox {
id: showLinkInForwardedMessagesComboBox
width: parent.columnWidth
label: qsTr("Show link in forwarded messages")
description: qsTr("Privacy setting for managing whether a link to your account is included in forwarded messages.")
menu: ContextMenu {
x: 0
width: showLinkInForwardedMessagesComboBox.width
MenuItem {
text: qsTr("Yes")
onClicked: {
tdLibWrapper.setUserPrivacySettingRule(TelegramAPI.SettingShowLinkInForwardedMessages, TelegramAPI.RuleAllowAll);
}
}
MenuItem {
text: qsTr("Your contacts only")
onClicked: {
tdLibWrapper.setUserPrivacySettingRule(TelegramAPI.SettingShowLinkInForwardedMessages, TelegramAPI.RuleAllowContacts);
}
}
MenuItem {
text: qsTr("No")
onClicked: {
tdLibWrapper.setUserPrivacySettingRule(TelegramAPI.SettingShowLinkInForwardedMessages, TelegramAPI.RuleRestrictAll);
}
}
}
Component.onCompleted: {
currentIndex = tdLibWrapper.getUserPrivacySettingRule(TelegramAPI.SettingShowLinkInForwardedMessages);
}
}
ComboBox {
id: showPhoneNumberComboBox
width: parent.columnWidth
label: qsTr("Show phone number")
description: qsTr("Privacy setting for managing whether your phone number is visible.")
menu: ContextMenu {
x: 0
width: showPhoneNumberComboBox.width
MenuItem {
text: qsTr("Yes")
onClicked: {
tdLibWrapper.setUserPrivacySettingRule(TelegramAPI.SettingShowPhoneNumber, TelegramAPI.RuleAllowAll);
}
}
MenuItem {
text: qsTr("Your contacts only")
onClicked: {
tdLibWrapper.setUserPrivacySettingRule(TelegramAPI.SettingShowPhoneNumber, TelegramAPI.RuleAllowContacts);
}
}
MenuItem {
text: qsTr("No")
onClicked: {
tdLibWrapper.setUserPrivacySettingRule(TelegramAPI.SettingShowPhoneNumber, TelegramAPI.RuleRestrictAll);
}
}
}
Component.onCompleted: {
currentIndex = tdLibWrapper.getUserPrivacySettingRule(TelegramAPI.SettingShowPhoneNumber);
}
}
ComboBox {
id: showProfilePhotoComboBox
width: parent.columnWidth
label: qsTr("Show profile photo")
description: qsTr("Privacy setting for managing whether your profile photo is visible.")
menu: ContextMenu {
x: 0
width: showProfilePhotoComboBox.width
MenuItem {
text: qsTr("Yes")
onClicked: {
tdLibWrapper.setUserPrivacySettingRule(TelegramAPI.SettingShowProfilePhoto, TelegramAPI.RuleAllowAll);
}
}
MenuItem {
text: qsTr("Your contacts only")
onClicked: {
tdLibWrapper.setUserPrivacySettingRule(TelegramAPI.SettingShowProfilePhoto, TelegramAPI.RuleAllowContacts);
}
}
MenuItem {
text: qsTr("No")
onClicked: {
tdLibWrapper.setUserPrivacySettingRule(TelegramAPI.SettingShowProfilePhoto, TelegramAPI.RuleRestrictAll);
}
}
}
Component.onCompleted: {
currentIndex = tdLibWrapper.getUserPrivacySettingRule(TelegramAPI.SettingShowProfilePhoto);
}
}
ComboBox {
id: showStatusComboBox
width: parent.columnWidth
label: qsTr("Show status")
description: qsTr("Privacy setting for managing whether your online status is visible.")
menu: ContextMenu {
x: 0
width: showStatusComboBox.width
MenuItem {
text: qsTr("Yes")
onClicked: {
tdLibWrapper.setUserPrivacySettingRule(TelegramAPI.SettingShowStatus, TelegramAPI.RuleAllowAll);
}
}
MenuItem {
text: qsTr("Your contacts only")
onClicked: {
tdLibWrapper.setUserPrivacySettingRule(TelegramAPI.SettingShowStatus, TelegramAPI.RuleAllowContacts);
}
}
MenuItem {
text: qsTr("No")
onClicked: {
tdLibWrapper.setUserPrivacySettingRule(TelegramAPI.SettingShowStatus, TelegramAPI.RuleRestrictAll);
}
}
}
Component.onCompleted: {
currentIndex = tdLibWrapper.getUserPrivacySettingRule(TelegramAPI.SettingShowStatus);
}
}
}
TextSwitch {
checked: appSettings.allowInlineBotLocationAccess
text: qsTr("Allow sending Location to inline bots")
description: qsTr("Some inline bots request location data when using them")
automaticCheck: false
onClicked: {
appSettings.allowInlineBotLocationAccess = !checked
}
}
}
}
}

View file

@ -1,216 +0,0 @@
/*
Copyright (C) 2020-21 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
import "../../components"
import "../../js/functions.js" as Functions
AccordionItem {
text: qsTr("Sessions")
property SilicaFlickable flickable: parent.flickable
Component {
Column {
id: activeSessionsItem
bottomPadding: Theme.paddingMedium
property variant activeSessions
property int inactiveSessionsTtlDays
Component.onCompleted: {
if (!activeSessions) {
tdLibWrapper.getActiveSessions();
}
}
Connections {
target: tdLibWrapper
onSessionsReceived: {
activeSessionsItem.activeSessions = sessions
activeSessionsItem.inactiveSessionsTtlDays = inactive_session_ttl_days
}
onOkReceived: {
if (request === "terminateSession") {
appNotification.show(qsTr("Session was terminated"));
tdLibWrapper.getActiveSessions();
}
}
}
Loader {
active: tdLibWrapper.authorizationState === TelegramAPI.AuthorizationReady
width: parent.width
sourceComponent: Component {
Column {
BusyIndicator {
anchors.horizontalCenter: parent.horizontalCenter
running: !activeSessionsListView.count && !activeSessionsItem.inactiveSessionsTtlDays
size: BusyIndicatorSize.Medium
visible: opacity > 0
height: running ? implicitHeight : 0
}
SilicaListView {
id: activeSessionsListView
width: parent.width
height: contentHeight
model: activeSessionsItem.activeSessions
headerPositioning: ListView.OverlayHeader
header: Separator {
width: parent.width
color: Theme.primaryColor
horizontalAlignment: Qt.AlignHCenter
visible: activeSessionsListView.count > 0
}
delegate: ListItem {
id: activeSessionListItem
width: parent.width
contentHeight: activeSessionColumn.height + ( 2 * Theme.paddingMedium )
menu: ContextMenu {
hasContent: !modelData.is_current
onHeightChanged: {
if (parent && flickable) {
// Make sure we are inside the screen area
var bottom = parent.mapToItem(flickable, x, y).y + height
if (bottom > flickable.height) {
flickable.contentY += bottom - flickable.height
}
}
}
MenuItem {
onClicked: {
var sessionId = modelData.id;
Remorse.itemAction(activeSessionListItem, qsTr("Terminating session"), function() { tdLibWrapper.terminateSession(sessionId); });
}
text: qsTr("Terminate Session")
}
}
Column {
id: activeSessionColumn
width: parent.width - ( 2 * Theme.horizontalPageMargin )
spacing: Theme.paddingSmall
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
Label {
width: parent.width
text: qsTr("This app")
font.pixelSize: Theme.fontSizeMedium
font.bold: true
visible: modelData.is_current
color: Theme.highlightColor
}
Label {
width: parent.width
text: modelData.application_name + " " + modelData.application_version
font.pixelSize: Theme.fontSizeMedium
font.bold: true
maximumLineCount: 1
elide: Text.ElideRight
}
Label {
width: parent.width
text: modelData.device_model + ", " + (modelData.platform + " " + modelData.system_version).trim()
font.pixelSize: Theme.fontSizeSmall
maximumLineCount: 1
truncationMode: TruncationMode.Fade
}
Label {
width: parent.width
text: qsTr("Active since: %1, last online: %2").arg(Functions.getDateTimeTimepoint(modelData.log_in_date)).arg(Functions.getDateTimeElapsed(modelData.last_active_date))
font.pixelSize: Theme.fontSizeExtraSmall
maximumLineCount: 1
truncationMode: TruncationMode.Fade
}
}
Separator {
anchors {
bottom: parent.bottom
}
width: parent.width
color: Theme.primaryColor
horizontalAlignment: Qt.AlignHCenter
}
}
}
ComboBox {
readonly property int ttl: activeSessionsItem.inactiveSessionsTtlDays
label: qsTr("Session Timeout")
description: qsTr("Inactive sessions will be terminated after this timeframe")
value: (currentItem && currentItem.text) ? currentItem.text : qsTr("%1 day(s)", "", ttl).arg(ttl)
visible: ttl > 0
menu: ContextMenu {
id: ttlMenu
MenuItem {
readonly property int days: 7
text: qsTr("1 week")
onClicked: tdLibWrapper.setInactiveSessionTtl(days)
}
MenuItem {
readonly property int days: 30
text: qsTr("1 month")
onClicked: tdLibWrapper.setInactiveSessionTtl(days)
}
MenuItem {
readonly property int days: 90
text: qsTr("3 months")
onClicked: tdLibWrapper.setInactiveSessionTtl(days)
}
MenuItem {
readonly property int days: 180
text: qsTr("6 months")
onClicked: tdLibWrapper.setInactiveSessionTtl(days)
}
MenuItem {
readonly property int days: 365
text: qsTr("1 year")
onClicked: tdLibWrapper.setInactiveSessionTtl(days)
}
}
Component.onCompleted: updateSelection()
onTtlChanged: updateSelection()
function updateSelection() {
var menuItems = ttlMenu.children
var n = menuItems.length
for (var i = 0; i < n; i++) {
if (menuItems[i].days === ttl) {
currentIndex = i
return
}
}
currentIndex = -1
}
}
}
}
}
}
}
}

View file

@ -1,51 +0,0 @@
/*
Copyright (C) 2021 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
AccordionItem {
text: qsTr("Storage")
Component {
ResponsiveGrid {
bottomPadding: Theme.paddingMedium
TextSwitch {
width: parent.columnWidth
checked: appSettings.onlineOnlyMode
text: qsTr("Enable online-only mode")
description: qsTr("Disables offline caching. Certain features may be limited or missing in this mode. Changes require a restart of Fernschreiber to take effect.")
automaticCheck: false
onClicked: {
appSettings.onlineOnlyMode = !checked
}
}
TextSwitch {
width: parent.columnWidth
checked: appSettings.storageOptimizer
text: qsTr("Enable storage optimizer")
automaticCheck: false
onClicked: {
appSettings.storageOptimizer = !checked
}
}
}
}
}

View file

@ -1,346 +0,0 @@
/*
Copyright (C) 2021 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import Sailfish.Pickers 1.0
import WerkWolf.Fernschreiber 1.0
import "../"
import "../../pages/"
import "../../js/twemoji.js" as Emoji
import "../../js/functions.js" as Functions
AccordionItem {
text: qsTr("User Profile")
Component {
Column {
id: accordionContent
bottomPadding: Theme.paddingMedium
readonly property var userInformation: tdLibWrapper.getUserInformation()
property bool uploadInProgress: false
property bool contactSyncEnabled: false
Component.onCompleted: {
tdLibWrapper.getUserProfilePhotos(userInformation.id, 100, 0);
}
Connections {
target: tdLibWrapper
onOwnUserUpdated: {
firstNameEditArea.text = userInformation.first_name;
lastNameEditArea.text = userInformation.last_name;
userNameEditArea.text = userInformation.username;
}
onUserProfilePhotosReceived: {
if (extra === userInformation.id.toString()) {
imageContainer.thumbnailModel = photos;
}
}
onFileUpdated: {
if (uploadInProgress) {
profilePictureButtonColumn.visible = !fileInformation.remote.is_uploading_active;
uploadInProgress = fileInformation.remote.is_uploading_active;
if (!fileInformation.remote.is_uploading_active) {
uploadInProgress = false;
tdLibWrapper.getUserProfilePhotos(userInformation.id, 100, 0);
}
}
}
onOkReceived: {
if (request === "deleteProfilePhoto") {
tdLibWrapper.getUserProfilePhotos(userInformation.id, 100, 0);
}
if (request === "setProfilePhoto") {
tdLibWrapper.getUserProfilePhotos(userInformation.id, 100, 0);
profilePictureButtonColumn.visible = true;
uploadInProgress = false;
}
}
}
ResponsiveGrid {
x: Theme.horizontalPageMargin
InformationEditArea {
id: firstNameEditArea
visible: true
canEdit: true
headerText: qsTr("First Name", "first name of the logged-in profile - header")
text: userInformation.first_name
width: parent.columnWidth
headerLeftAligned: true
onSaveButtonClicked: {
if(!editItem.errorHighlight) {
tdLibWrapper.setName(textValue, lastNameEditArea.text);
} else {
isEditing = true;
}
}
onTextEdited: {
if(textValue.length > 0 && textValue.length < 65) {
editItem.errorHighlight = false;
editItem.label = "";
editItem.placeholderText = "";
} else {
editItem.label = qsTr("Enter 1-64 characters");
editItem.placeholderText = editItem.label;
editItem.errorHighlight = true;
}
}
}
InformationEditArea {
id: lastNameEditArea
visible: true
canEdit: true
headerText: qsTr("Last Name", "last name of the logged-in profile - header")
text: userInformation.last_name
width: parent.columnWidth
headerLeftAligned: true
onSaveButtonClicked: {
if(!editItem.errorHighlight) {
tdLibWrapper.setName(firstNameEditArea.text, textValue);
} else {
isEditing = true;
}
}
onTextEdited: {
if(textValue.length >= 0 && textValue.length < 65) {
editItem.errorHighlight = false;
editItem.label = "";
editItem.placeholderText = "";
} else {
editItem.label = qsTr("Enter 0-64 characters");
editItem.placeholderText = editItem.label;
editItem.errorHighlight = true;
}
}
}
InformationEditArea {
id: userNameEditArea
visible: true
canEdit: true
headerText: qsTr("Username", "user name of the logged-in profile - header")
text: userInformation.usernames.editable_username
width: parent.columnWidth
headerLeftAligned: true
onSaveButtonClicked: {
tdLibWrapper.setUsername(textValue);
}
}
Column {
id: contactSyncItem
width: parent.width
height: syncInProgress ? ( syncContactsBusyIndicator.height + Theme.paddingMedium ) : ( syncContactsButton.height + Theme.paddingMedium )
visible: accordionContent.contactSyncEnabled
property bool syncInProgress: false
Connections {
target: contactSyncLoader.item
onSyncError: {
contactSyncItem.syncInProgress = false;
}
}
Connections {
target: tdLibWrapper
onContactsImported: {
appNotification.show(qsTr("Contacts successfully synchronized with Telegram."));
}
}
Button {
id: syncContactsButton
text: qsTr("Synchronize Contacts with Telegram")
visible: !contactSyncItem.syncInProgress
anchors {
horizontalCenter: parent.horizontalCenter
}
onClicked: {
contactSyncLoader.item.synchronize();
}
}
BusyIndicator {
id: syncContactsBusyIndicator
anchors.horizontalCenter: parent.horizontalCenter
running: contactSyncItem.syncInProgress
size: BusyIndicatorSize.Small
visible: running
}
}
}
SectionHeader {
horizontalAlignment: Text.AlignLeft
text: qsTr("Profile Pictures")
}
Row {
width: parent.width - ( 2 * Theme.horizontalPageMargin )
spacing: Theme.paddingMedium
Item {
id: imageContainer
anchors.verticalCenter: parent.verticalCenter
width: parent.width / 2
height: profilePictureLoader.height
property var thumbnailModel: ({})
property bool thumbnailVisible: true
property bool thumbnailActive: thumbnailModel.length > 0
property int thumbnailRadius: imageContainer.width / 2
Loader {
id: profilePictureLoader
active: imageContainer.thumbnailActive
asynchronous: true
width: Theme.itemSizeExtraLarge
height: Theme.itemSizeExtraLarge
anchors.horizontalCenter: parent.horizontalCenter
source: "../ProfilePictureList.qml"
}
ProfileThumbnail {
id: chatPictureReplacement
visible: !profilePictureLoader.active
replacementStringHint: Functions.getUserName(accordionContent.userInformation)
radius: imageContainer.thumbnailRadius
anchors.horizontalCenter: parent.horizontalCenter
width: Theme.itemSizeExtraLarge
height: Theme.itemSizeExtraLarge
}
}
Column {
id: profilePictureButtonColumn
spacing: Theme.paddingSmall
width: parent.width / 2
Button {
id: addProfilePictureButton
text: qsTr("Add Picture")
anchors {
horizontalCenter: parent.horizontalCenter
}
onClicked: {
pageStack.push(imagePickerPage);
}
}
Button {
id: removeProfilePictureButton
text: qsTr("Delete Picture")
anchors {
horizontalCenter: parent.horizontalCenter
}
onClicked: {
var pictureIdForDeletion = imageContainer.thumbnailModel[profilePictureLoader.item.currentPictureIndex].id;
Remorse.popupAction(settingsPage, qsTr("Deleting profile picture"), function() { tdLibWrapper.deleteProfilePhoto(pictureIdForDeletion) });
}
}
}
Column {
id: uploadStatusColumn
visible: !profilePictureButtonColumn.visible
spacing: Theme.paddingMedium
width: parent.width / 2
Text {
id: uploadingText
font.pixelSize: Theme.fontSizeSmall
text: qsTr("Uploading...")
horizontalAlignment: Text.AlignHCenter
color: Theme.secondaryColor
width: parent.width
}
BusyIndicator {
anchors.horizontalCenter: parent.horizontalCenter
running: uploadStatusColumn.visible
size: BusyIndicatorSize.Medium
}
}
}
Loader {
id: contactSyncLoader
source: "../ContactSync.qml"
active: true
onLoaded: {
accordionContent.contactSyncEnabled = true;
}
}
Component {
id: imagePickerPage
ImagePickerPage {
onSelectedContentPropertiesChanged: {
profilePictureButtonColumn.visible = false;
uploadInProgress = true;
tdLibWrapper.setProfilePhoto(selectedContentProperties.filePath);
}
}
}
Column {
width: parent.width - ( 2 * Theme.horizontalPageMargin )
spacing: Theme.paddingMedium
Label {
width: parent.width
height: Theme.fontSizeExtraLarge
anchors.horizontalCenter: parent.horizontalCenter
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignBottom
text: qsTr("Phone number: +%1").arg(accordionContent.userInformation.phone_number)
font.pixelSize: Theme.fontSizeSmall
wrapMode: Text.Wrap
anchors {
horizontalCenter: parent.horizontalCenter
}
}
Button {
id: logOutButton
text: qsTr("Log Out")
anchors.horizontalCenter: parent.horizontalCenter
onClicked: Remorse.popupAction(settingsPage, qsTr("Logged out"), function() {
tdLibWrapper.logout();
pageStack.pop();
});
}
}
}
}
}

View file

@ -40,16 +40,6 @@ ApplicationWindow
} }
} }
Connections {
target: tdLibWrapper
onOpenFileExternally: {
Qt.openUrlExternally(filePath);
}
onTgUrlFound: {
Functions.handleLink(tgUrl);
}
}
AppNotification { AppNotification {
id: appNotification id: appNotification
parent: pageStack.currentPage parent: pageStack.currentPage

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" xml:space="preserve"><path fill="#141414" d="M7 5a4 4 0 0 0-4 4v18a4 4 0 0 0 4 4h6V5H7z"/><path fill="#FDDA24" d="M13 5h10v26H13z"/><path fill="#EF3340" d="M29 5h-6v26h6a4 4 0 0 0 4-4V9a4 4 0 0 0-4-4z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#141414" d="M4 5C1.791 5 0 6.791 0 9v18c0 2.209 1.791 4 4 4h8V5H4z"/><path fill="#FEE833" d="M12 5h12v26H12z"/><path fill="#EE232C" d="M32 5h-8v26h8c2.209 0 4-1.791 4-4V9c0-2.209-1.791-4-4-4z"/></svg>

Before

Width:  |  Height:  |  Size: 269 B

After

Width:  |  Height:  |  Size: 272 B

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" xml:space="preserve"><path fill="#138808" d="M0 27a4 4 0 0 0 4 4h28a4 4 0 0 0 4-4v-5H0v5z"/><path fill="#F93" d="M36 14V9a4 4 0 0 0-4-4H4a4 4 0 0 0-4 4v5h36z"/><path fill="#F7F7F7" d="M0 13.667h36v8.667H0z"/><circle fill="navy" cx="18" cy="18" r="4"/><circle fill="#F7F7F7" cx="18" cy="18" r="3.375"/><path d="m18.1 16.75-.1.65-.1-.65.1-1.95zm-.928-1.841.408 1.909.265.602-.072-.653zm-.772.32.888 1.738.412.513-.238-.613zm-.663.508 1.308 1.45.531.389-.389-.531zm-.508.663 1.638 1.062.613.238-.513-.412zm-.32.772 1.858.601.653.072-.602-.265zM14.8 18l1.95.1.65-.1-.65-.1zm.109.828 1.909-.408.602-.265-.653.072zm.32.772 1.738-.888.513-.412-.613.238zm.508.663 1.45-1.308.389-.531-.531.389zm.663.508 1.062-1.638.238-.613-.412.513zm.772.32.601-1.858.072-.653-.265.602zM18 21.2l.1-1.95-.1-.65-.1.65zm.828-.109-.408-1.909-.265-.602.072.653zm.772-.32-.888-1.738-.412-.513.238.613zm.663-.508-1.308-1.45-.531-.389.389.531zm.508-.663-1.638-1.062-.613-.238.513.412zm.32-.772-1.858-.601-.653-.072.602.265zM21.2 18l-1.95-.1-.65.1.65.1zm-.109-.828-1.909.408-.602.265.653-.072zm-.32-.772-1.738.888-.513.412.613-.238zm-.508-.663-1.45 1.308-.389.531.531-.389zm-.663-.508-1.062 1.638-.238.613.412-.513zm-.772-.32-.601 1.858-.072.653.265-.602z" fill="#6666B3"/><g fill="navy"><circle cx="17.56" cy="14.659" r=".2"/><circle cx="16.71" cy="14.887" r=".2"/><circle cx="15.948" cy="15.326" r=".2"/><circle cx="15.326" cy="15.948" r=".2"/><circle cx="14.887" cy="16.71" r=".2"/><circle cx="14.659" cy="17.56" r=".2"/><circle cx="14.659" cy="18.44" r=".2"/><circle cx="14.887" cy="19.29" r=".2"/><circle cx="15.326" cy="20.052" r=".2"/><circle cx="15.948" cy="20.674" r=".2"/><circle cx="16.71" cy="21.113" r=".2"/><circle cx="17.56" cy="21.341" r=".2"/><circle cx="18.44" cy="21.341" r=".2"/><circle cx="19.29" cy="21.113" r=".2"/><circle cx="20.052" cy="20.674" r=".2"/><circle cx="20.674" cy="20.052" r=".2"/><circle cx="21.113" cy="19.29" r=".2"/><circle cx="21.341" cy="18.44" r=".2"/><circle cx="21.341" cy="17.56" r=".2"/><circle cx="21.113" cy="16.71" r=".2"/><circle cx="20.674" cy="15.948" r=".2"/><circle cx="20.052" cy="15.326" r=".2"/><circle cx="19.29" cy="14.887" r=".2"/><circle cx="18.44" cy="14.659" r=".2"/><circle cx="18" cy="18" r=".9"/></g></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#138808" d="M0 27c0 2.209 1.791 4 4 4h28c2.209 0 4-1.791 4-4v-4H0v4z"/><path fill="#EEE" d="M0 13h36v10H0z"/><path fill="#F93" d="M36 13V9c0-2.209-1.791-4-4-4H4C1.791 5 0 6.791 0 9v4h36z"/><circle fill="navy" cx="18" cy="18" r="4"/><circle fill="#EEE" cx="18" cy="18" r="3"/><path fill="#6666B3" d="M18 15l.146 2.264 1.001-2.035-.73 2.147 1.704-1.498-1.497 1.705 2.147-.731-2.035 1.002L21 18l-2.264.146 2.035 1.001-2.147-.73 1.497 1.704-1.704-1.497.73 2.147-1.001-2.035L18 21l-.146-2.264-1.002 2.035.731-2.147-1.705 1.497 1.498-1.704-2.147.73 2.035-1.001L15 18l2.264-.146-2.035-1.002 2.147.731-1.498-1.705 1.705 1.498-.731-2.147 1.002 2.035z"/><circle fill="navy" cx="18" cy="18" r="1"/></svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 765 B

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#060" d="M36 27c0 2.209-1.791 4-4 4H4c-2.209 0-4-1.791-4-4V9c0-2.209 1.791-4 4-4h28c2.209 0 4 1.791 4 4v18z"/><path fill="#D52B1E" d="M32 5H15v26h17c2.209 0 4-1.791 4-4V9c0-2.209-1.791-4-4-4z"/><path fill="#FFCC4D" d="M15 10c-4.419 0-8 3.581-8 8 0 4.418 3.581 8 8 8 4.418 0 8-3.582 8-8 0-4.419-3.582-8-8-8zm-6.113 4.594l1.602 1.602-2.46 1.23c.083-1.022.383-1.981.858-2.832zm-.858 3.979l4.4 2.207-2.706 1.804.014.021c-.96-1.097-1.583-2.492-1.708-4.032zM14 24.92c-.937-.134-1.813-.453-2.592-.92H14v.92zM14 23h-3.099L14 20.934V23zm0-3.268l-.607.405L9.118 18l2.116-1.058L14 19.707v.025zm0-1.439l-3.543-3.543 3.543.59v2.953zm0-3.992l-4.432-.713c1.084-1.333 2.65-2.253 4.432-2.508v3.221zm7.113.293c.475.851.775 1.81.858 2.833l-2.46-1.23 1.602-1.603zM16 11.08c1.782.256 3.348 1.175 4.432 2.508L16 14.301V11.08zm0 4.26l3.543-.591L16 18.293V15.34zm0 4.367l2.765-2.765L20.882 18l-4.274 2.137-.608-.405v-.025zm0 5.213V24h2.592c-.779.467-1.655.786-2.592.92zM16 23v-2.066L19.099 23H16zm4.264-.395l.014-.021-2.706-1.804 4.4-2.207c-.126 1.54-.749 2.935-1.708 4.032z"/><path fill="#D52B1E" d="M11 13v7c0 2.209 1.791 4 4 4s4-1.791 4-4v-7h-8z"/><path fill="#FFF" d="M12 14v6c0 1.656 1.343 3 3 3s3-1.344 3-3v-6h-6z"/><path fill="#829ACD" d="M13 17h4v2h-4z"/><path fill="#829ACD" d="M14 16h2v4h-2z"/><path fill="#039" d="M12 17h1v2h-1zm2 0h2v2h-2zm3 0h1v2h-1zm-3 3h2v2h-2zm0-6h2v2h-2z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#060" d="M36 27c0 2.209-1.791 4-4 4H4c-2.209 0-4-1.791-4-4V9c0-2.209 1.791-4 4-4h28c2.209 0 4 1.791 4 4v18z"/><path fill="#D52B1E" d="M32 5H15v26h17c2.209 0 4-1.791 4-4V9c0-2.209-1.791-4-4-4z"/><path fill="#FFCC4D" d="M15 10c-4.418 0-8 3.582-8 8s3.582 8 8 8 8-3.582 8-8-3.582-8-8-8zm3.994 5.938l2.089-1.393c.491.863.803 1.839.888 2.881l-2.977-1.488zM16 24h2.592c-.779.467-1.655.786-2.592.92V24zm-7.971-6.574c.083-1.022.383-1.982.858-2.832l1.602 1.602-2.46 1.23zm0 1.147l3.747 1.874.447-.895L9.118 18l2.116-1.058 1.412 1.412.707-.707-1.176-1.176.046-.023-.447-.895-.344.172-.975-.975 1.461.244.164-.986-2.514-.419c1.084-1.333 2.65-2.253 4.432-2.508V23h-3.099l2.376-1.584-.555-.832-3 2 .014.021c-.959-1.097-1.582-2.492-1.707-4.032zM14 24.92c-.937-.135-1.813-.453-2.592-.92H14v.92zm6.287-2.34l-2.933-2.933-.707.707.471.471-.395.592L19.099 23H16V11.08c1.321.189 2.524.741 3.499 1.561l-2.657.886.316.948 3-1-.103-.308c.167.174.323.357.471.548l-2.804 1.869L18 16l-.224.447L20.882 18l-3.105 1.553.447.895 3.747-1.874c-.124 1.527-.737 2.913-1.684 4.006z"/><path fill="#D52B1E" d="M11 13v7c0 2.209 1.791 4 4 4s4-1.791 4-4v-7h-8z"/><path fill="#FFF" d="M12 14v6c0 1.656 1.343 3 3 3s3-1.344 3-3v-6h-6z"/><path fill="#829ACD" d="M13 17h4v2h-4z"/><path fill="#829ACD" d="M14 16h2v4h-2z"/><path fill="#039" d="M12 17h1v2h-1zm2 0h2v2h-2zm3 0h1v2h-1zm-3 3h2v2h-2zm0-6h2v2h-2z"/></svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#A7122D" d="M0 26.518V27c0 2.209 1.791 4 4 4h28c2.209 0 4-1.791 4-4v-.482H0z"/><path fill="#EEE" d="M0 22.181h36v4.485H0z"/><path fill="#292648" d="M0 13.513h36v8.821H0z"/><path fill="#EEE" d="M0 9.181h36v4.485H0z"/><path fill="#A7122D" d="M0 9.333V9c0-2.209 1.791-4 4-4h28c2.209 0 4 1.791 4 4v.333H0z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#ED1C24" d="M32 5H4C1.791 5 0 6.791 0 9h36c0-2.209-1.791-4-4-4z"/><path fill="#EEE" d="M0 9h36v4H0z"/><path fill="#ED1C24" d="M32 31H4c-2.209 0-4-1.791-4-4h36c0 2.209-1.791 4-4 4z"/><path fill="#EEE" d="M0 23h36v4H0z"/><path fill="#241D4F" d="M0 13h36v10H0z"/></svg>

Before

Width:  |  Height:  |  Size: 382 B

After

Width:  |  Height:  |  Size: 338 B

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><circle fill="#DD2E44" cx="18" cy="18" r="18"/><circle fill="#FFF" cx="18" cy="18" r="13.5"/><circle fill="#DD2E44" cx="18" cy="18" r="10"/><circle fill="#FFF" cx="18" cy="18" r="6"/><circle fill="#DD2E44" cx="18" cy="18" r="3"/><path opacity=".2" d="M18.24 18.282l13.144 11.754s-2.647 3.376-7.89 5.109L17.579 18.42l.661-.138z"/><path fill="#FFAC33" d="M18.294 19c-.255 0-.509-.097-.704-.292-.389-.389-.389-1.018 0-1.407l.563-.563c.389-.389 1.018-.389 1.408 0 .388.389.388 1.018 0 1.407l-.564.563c-.194.195-.448.292-.703.292z"/><path fill="#55ACEE" d="M24.016 6.981c-.403 2.079 0 4.691 0 4.691l7.054-7.388c.291-1.454-.528-3.932-1.718-4.238-1.19-.306-4.079.803-5.336 6.935zm5.003 5.003c-2.079.403-4.691 0-4.691 0l7.388-7.054c1.454-.291 3.932.528 4.238 1.718.306 1.19-.803 4.079-6.935 5.336z"/><path fill="#3A87C2" d="M32.798 4.485L21.176 17.587c-.362.362-1.673.882-2.51.046-.836-.836-.419-2.08-.057-2.443L31.815 3.501s.676-.635 1.159-.152-.176 1.136-.176 1.136z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><circle fill="#CCD6DD" cx="18" cy="18" r="18"/><circle fill="#3B88C3" cx="18" cy="18" r="14"/><circle fill="#DD2E44" cx="18" cy="18" r="10"/><circle fill="#FFAC33" cx="18" cy="18" r="6"/><path d="M34.864 29.199c-.42.306-1.257.592-1.934.592-1.965 0-4.654-.717-6.334-2.386l-2.954-3.872c-.274-.275-.357-.575-.21-.932.148-.359-.73-.601-.342-.601h5.058c1.867 0 4.308 1.256 5.925 3.018l.371.351c.772.843 1.183 1.629 1.182 2.386 0 .621-.272 1.087-.762 1.444z"/><path d="M28.305 35.204c-.771 0-1.632-.417-2.49-1.204l-.488-.378C23.532 31.977 22 29.491 22 27.59v-5.164c0-.396.5.514.865.363.363-.15.915-.066 1.195.214l3.166 3.124c1.699 1.711 3.061 4.619 3.061 6.62 0 .689-.143 1.255-.452 1.682-.364.499-.897.775-1.53.775z"/><path fill="#C1694F" d="M31.345 31.964c-.256 0-.487-.122-.683-.317l-14-14c-.391-.391-.391-1.023 0-1.415.391-.391 1.023-.39 1.414 0l14 14c.391.391.378 1.036-.013 1.427-.194.195-.461.305-.718.305z"/></svg>

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 976 B

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" xml:space="preserve"><path fill="#880082" d="M0 27a4 4 0 0 0 4 4h28a4 4 0 0 0 4-4v-.5H0v.5z"/><path fill="#3558A0" d="M0 22.07h36v4.6H0z"/><path fill="#138F3E" d="M0 17.83h36v4.5H0z"/><path fill="#FAD220" d="M0 13.5h36V18H0z"/><path fill="#FF7300" d="M0 9.17h36v4.5H0z"/><path fill="#FF000E" d="M32 5H4a4 4 0 0 0-4 4v.33h36V9a4 4 0 0 0-4-4z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#880082" d="M0 27c0 2.209 1.791 4 4 4h28c2.209 0 4-1.791 4-4v-.5H0v.5z"/><path fill="#3558A0" d="M0 22.07h36v4.6H0z"/><path fill="#138F3E" d="M0 17.83h36v4.5H0z"/><path fill="#FAD220" d="M0 13.5h36V18H0z"/><path fill="#FF5000" d="M0 9.17h36v4.5H0z"/><path fill="#FF000E" d="M32 5H4C1.791 5 0 6.791 0 9v.33h36V9c0-2.209-1.791-4-4-4z"/></svg>

Before

Width:  |  Height:  |  Size: 409 B

After

Width:  |  Height:  |  Size: 412 B

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#5BCEFA" d="M0 27c0 2.209 1.791 4 4 4h28c2.209 0 4-1.791 4-4v-1.3H0V27z"/><path fill="#F5A9B8" d="M.026 20.5L0 25.8h36v-5.3z"/><path fill="#EEE" d="M0 15.3h36v5.3H0z"/><path fill="#F5A9B8" d="M0 9.902h36V15.4H0z"/><path fill="#5BCEFA" d="M36 9c0-2.209-1.791-4-4-4H4C1.791 5 0 6.791 0 9v1.2h36V9z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#5BCEFA" d="M0 27c0 2.209 1.791 4 4 4h28c2.209 0 4-1.791 4-4v-1.3H0V27z"/><path fill="#F5A9B8" d="M.026 20.5L0 25.8h36v-5.3z"/><path fill="#EEE" d="M0 15.3h36v5.3H0z"/><path fill="#F5A9B8" d="M.026 10.1L0 15.4h36v-5.3z"/><path fill="#5BCEFA" d="M36 9c0-2.209-1.791-4-4-4H4C1.791 5 0 6.791 0 9v1.2h36V9z"/></svg>

Before

Width:  |  Height:  |  Size: 376 B

After

Width:  |  Height:  |  Size: 383 B

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#292F33" d="M11 11.844c-2.297-.669-3.315-3.565-3.734-5.369C6.313 7.952 4.23 10.155 0 11.28V.425C.955.154 1.959 0 3 0c6.075 0 11 4.925 11 11 0 3.009-1.211 5.733-3.168 7.719.107-.557.168-1.13.168-1.719v-5.156z"/><path fill="#F7DECE" d="M0 28.604L2 32l3-5v-1.523c2.968-1.051 5.222-3.607 5.832-6.757.107-.558.168-1.131.168-1.72v-5.156c-2.297-.669-3.315-3.565-3.734-5.369C6.313 7.952 4.23 10.155 0 11.28v17.324z"/><path fill="#3B94D9" d="M0 28.604L2 32l3-5h6c2.209 0 4 1.791 4 4v5H0v-7.396z"/><path fill="#1C6399" d="M10 32h1v4h-1z"/><path fill="#C1694F" d="M5 22h1s-1 2-4 2c-.809 0-1.462-.151-2-.363V22h5zm-2-2.5H1c-.276 0-.5-.224-.5-.5s.224-.5.5-.5h2c.276 0 .5.224.5.5s-.224.5-.5.5z"/><path fill="#662113" d="M6 16c-.553 0-1-.448-1-1v-1c0-.552.447-1 1-1s1 .448 1 1v1c0 .552-.447 1-1 1z"/><path fill="#292F33" d="M25 11.844c2.297-.669 3.315-3.565 3.734-5.369.953 1.477 3.036 3.68 7.266 4.805V.425C35.045.154 34.041 0 33 0c-6.075 0-11 4.925-11 11 0 3.009 1.211 5.733 3.168 7.719C25.061 18.162 25 17.589 25 17v-5.156z"/><path fill="#F7DECE" d="M36 11.28c-4.23-1.125-6.313-3.328-7.266-4.804-.42 1.804-1.438 4.699-3.734 5.369V17c0 .589.061 1.162.168 1.719.61 3.15 2.863 5.706 5.832 6.757V27l3 5 2-3.396V11.28z"/><path fill="#3B94D9" d="M36 28.604L34 32l-3-5h-6c-2.209 0-4 1.791-4 4v5h15v-7.396z"/><path fill="#1C6399" d="M25 32h1v4h-1z"/><path fill="#C1694F" d="M31 22h-1s1 2 4 2c.809 0 1.462-.151 2-.363V22h-5zm2-2.5h2c.276 0 .5-.224.5-.5s-.224-.5-.5-.5h-2c-.276 0-.5.224-.5.5s.224.5.5.5z"/><path fill="#662113" d="M30 16c.553 0 1-.448 1-1v-1c0-.552-.447-1-1-1s-1 .448-1 1v1c0 .552.447 1 1 1z"/><path fill="#DD2E44" d="M26.539 4.711c0-2.602-2.11-4.711-4.711-4.711C20.249 0 18.855.78 18 1.972 17.144.78 15.751 0 14.172 0c-2.601 0-4.711 2.109-4.711 4.711 0 .369.047.727.127 1.07.654 4.065 5.173 8.353 8.411 9.529 3.238-1.177 7.758-5.465 8.412-9.528.081-.344.128-.702.128-1.071z"/></svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

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