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
tdlibsecrets.h
#Convinience scripts
*.sh

View file

@ -1,7 +1,6 @@
# Fernschreiber
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
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.)
- 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)
- 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! :)
- 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)
### 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
- Chinese: [dashinfantry](https://github.com/dashinfantry)
- 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)
- Italian: [Matteo](https://github.com/iamnomeutente)
- Polish: [atlochowski](https://github.com/atlochowski)
- 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)
- 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
## 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:
```
@ -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).
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`.
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.
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`.
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
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.
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
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).
- 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).
- 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!

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
Exec=harbour-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
QT += core dbus sql multimedia positioning
QT += core dbus sql
DEFINES += QT_STATICPLUGIN
SOURCES += src/harbour-fernschreiber.cpp \
src/appsettings.cpp \
src/chatpermissionfiltermodel.cpp \
src/chatlistmodel.cpp \
src/chatmodel.cpp \
src/contactsmodel.cpp \
@ -39,89 +38,37 @@ SOURCES += src/harbour-fernschreiber.cpp \
src/tdlibfile.cpp \
src/tdlibreceiver.cpp \
src/tdlibwrapper.cpp \
src/textfiltermodel.cpp \
src/tgsplugin.cpp
DISTFILES += qml/harbour-fernschreiber.qml \
qml/components/AudioPreview.qml \
qml/components/BackgroundImage.qml \
qml/components/ChatListViewItem.qml \
qml/components/ContactSync.qml \
qml/components/DocumentPreview.qml \
qml/components/GamePreview.qml \
qml/components/ImagePreview.qml \
qml/components/InformationEditArea.qml \
qml/components/InformationTextItem.qml \
qml/components/InReplyToRow.qml \
qml/components/InlineQuery.qml \
qml/components/LocationPreview.qml \
qml/components/MessageListViewItem.qml \
qml/components/MessageListViewItemSimple.qml \
qml/components/MessageOverlayFlickable.qml \
qml/components/MessageViaLabel.qml \
qml/components/MultilineEmojiLabel.qml \
qml/components/PinnedMessageItem.qml \
qml/components/PollPreview.qml \
qml/components/PressEffect.qml \
qml/components/ProfilePictureList.qml \
qml/components/ReplyMarkupButtons.qml \
qml/components/StickerPicker.qml \
qml/components/PhotoTextsListItem.qml \
qml/components/StickerSetOverlay.qml \
qml/components/TDLibImage.qml \
qml/components/TDLibMinithumbnail.qml \
qml/components/TDLibPhoto.qml \
qml/components/TDLibThumbnail.qml \
qml/components/VoiceNoteOverlay.qml \
qml/components/WebPagePreview.qml \
qml/components/chatInformationPage/ChatInformationEditArea.qml \
qml/components/chatInformationPage/ChatInformationPageContent.qml \
qml/components/chatInformationPage/ChatInformationProfilePicture.qml \
qml/components/chatInformationPage/ChatInformationProfilePictureList.qml \
qml/components/chatInformationPage/ChatInformationTabItemBase.qml \
qml/components/chatInformationPage/ChatInformationTabItemDebug.qml \
qml/components/chatInformationPage/ChatInformationTabItemMembersGroups.qml \
qml/components/chatInformationPage/ChatInformationTabItemSettings.qml \
qml/components/chatInformationPage/ChatInformationTabView.qml \
qml/components/chatInformationPage/ChatInformationTextItem.qml \
qml/components/chatInformationPage/EditGroupChatPermissionsColumn.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/functions.js \
qml/pages/ChatInformationPage.qml \
@ -135,11 +82,11 @@ DISTFILES += qml/harbour-fernschreiber.qml \
qml/pages/AboutPage.qml \
qml/pages/PollCreationPage.qml \
qml/pages/PollResultsPage.qml \
qml/pages/SearchChatsPage.qml \
qml/pages/SettingsPage.qml \
qml/pages/VideoPage.qml \
rpm/harbour-fernschreiber.changes \
rpm/harbour-fernschreiber.spec \
rpm/harbour-fernschreiber.yaml \
translations/*.ts \
harbour-fernschreiber.desktop
@ -148,28 +95,19 @@ SAILFISHAPP_ICONS = 86x86 108x108 128x128 172x172 256x256
TRANSLATIONS += translations/harbour-fernschreiber-de.ts \
translations/harbour-fernschreiber-es.ts \
translations/harbour-fernschreiber-fi.ts \
translations/harbour-fernschreiber-fr.ts \
translations/harbour-fernschreiber-hu.ts \
translations/harbour-fernschreiber-it.ts \
translations/harbour-fernschreiber-pl.ts \
translations/harbour-fernschreiber-ru.ts \
translations/harbour-fernschreiber-sv.ts \
translations/harbour-fernschreiber-sk.ts \
translations/harbour-fernschreiber-en.ts \
translations/harbour-fernschreiber-zh_CN.ts
equals(QT_ARCH, arm) {
message(Building ARM)
contains(QT_ARCH, arm) {
TARGET_ARCHITECTURE = armv7hl
}
equals(QT_ARCH, i386) {
message(Building i486)
} else {
TARGET_ARCHITECTURE = i486
}
equals(QT_ARCH, arm64){
message(Building aarch64)
TARGET_ARCHITECTURE = aarch64
}
INCLUDEPATH += $$PWD/tdlib/include
DEPENDPATH += $$PWD/tdlib/include
@ -211,7 +149,6 @@ INSTALLS += telegram 86.png 108.png 128.png 172.png 256.png \
HEADERS += \
src/appsettings.h \
src/chatpermissionfiltermodel.h \
src/chatlistmodel.h \
src/chatmodel.h \
src/contactsmodel.h \
@ -231,7 +168,6 @@ HEADERS += \
src/tdlibreceiver.h \
src/tdlibsecrets.h \
src/tdlibwrapper.h \
src/textfiltermodel.h \
src/tgsplugin.h
# 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:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="114.667"
height="114.667"
version="1.1"
xml:space="preserve"
width="114.66667"
height="114.66667"
viewBox="0 0 114.66667 114.66667"
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
sodipodi:docname="background-black.svg"
id="svg60"><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1015"
id="namedview62"
showgrid="false"
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"
id="svg19">
<metadata
id="metadata23">
<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="defs9">
<linearGradient
id="linearGradient4649">
<stop
style="stop-color:#979797;stop-opacity:1"
offset="0"
id="stop5" /><stop
style="stop-opacity:1;stop-color:#898989;opacity:1"
offset="0.959184"
id="stop7" /><stop
style="stop-opacity:1;stop-color:#898989;opacity:1"
id="stop4645" />
<stop
style="stop-color:#797979;stop-opacity:1"
offset="1"
id="stop9" /></linearGradient><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-529"><stop
style="stop-opacity:1;stop-color:#727272;opacity:1"
offset="0"
id="stop74" /><stop
style="stop-opacity:1;stop-color:#898989;opacity:1"
offset="0.959184"
id="stop76" /><stop
style="stop-opacity:1;stop-color:#898989;opacity:1"
offset="1"
id="stop78" /></linearGradient><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-529-824"><stop
style="stop-opacity:1;stop-color:#8d8d8d;opacity:1"
offset="0"
id="stop290" /><stop
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>
id="stop4647" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient4649"
id="linearGradient4651"
x1="0.81535178"
y1="0.99882859"
x2="71.914337"
y2="74.307625"
gradientUnits="userSpaceOnUse" />
</defs>
<path
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"
transform="matrix(1.33333,0,0,-1.33333,0,114.667)"
id="path11"
style="fill:url(#linearGradient4651);fill-opacity:1" />
<path
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"
id="path13"
style="fill:#444444;fill-opacity:1" />
<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="path15"
style="fill:#000000;fill-opacity:1" />
<path
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="path17"
style="fill:#000000;fill-opacity:1" />
</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:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:xlink="http://www.w3.org/1999/xlink"
id="svg19"
version="1.1"
xml:space="preserve"
width="114.66667"
height="114.66667"
viewBox="0 0 114.66667 114.66667"
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
sodipodi:docname="background-white.svg"
id="svg60"><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1015"
id="namedview62"
showgrid="false"
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
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"
height="114.667"
width="114.667">
<metadata
id="metadata23">
<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="defs9">
<linearGradient
id="linearGradient4649">
<stop
id="stop4645"
offset="0"
style="stop-opacity:1;stop-color:#8d8d8d;opacity:1" /><stop
id="stop7"
offset="0.959184"
style="stop-opacity:1;stop-color:#767676;opacity:1" /><stop
id="stop9"
style="stop-color:#686868;stop-opacity:1" />
<stop
id="stop4647"
offset="1"
style="stop-opacity:1;stop-color:#767676;opacity:1" /></linearGradient><linearGradient
id="linearGradient30-529"
spreadMethod="pad"
gradientTransform="matrix(-72.476372,-72.476372,72.476372,-72.476372,73.193359,73.192871)"
style="stop-color:#868686;stop-opacity:1" />
</linearGradient>
<linearGradient
gradientUnits="userSpaceOnUse"
y2="0"
x2="1"
y1="0"
x1="0"><stop
id="stop74"
offset="0"
style="stop-opacity:1;stop-color:#8d8d8d;opacity:1" /><stop
id="stop76"
offset="0.959184"
style="stop-opacity:1;stop-color:#767676;opacity:1" /><stop
id="stop78"
offset="1"
style="stop-opacity:1;stop-color:#767676;opacity:1" /></linearGradient></defs><g
id="g67"
transform="matrix(1.3333333,0,0,-1.3333333,0,114.66667)"
inkscape:label="harbour-fernschreiber"
inkscape:groupmode="layer"><g
id="g18"><g
id="g16"
clip-path="url(#clipPath18)"><path
id="path14"
inkscape:connector-curvature="0"
style="fill:url(#linearGradient30-529);stroke:none;opacity:1"
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
id="g20"
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>
y2="74.307625"
x2="71.914337"
y1="0.99882859"
x1="0.81535178"
id="linearGradient4651"
xlink:href="#linearGradient4649" />
</defs>
<path
style="fill:url(#linearGradient4651);fill-opacity:1"
id="path11"
transform="matrix(1.33333,0,0,-1.33333,0,114.667)"
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" />
<path
style="fill:#bbbbbb;fill-opacity:1"
id="path13"
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" />
<path
style="fill:#f7f7f7;fill-opacity:1"
id="path15"
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" />
<path
style="fill:#fcfcfc;fill-opacity:1"
id="path17"
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" />
</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"?>
<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"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg19"
version="1.1"
xml:space="preserve"
width="114.66667"
height="114.66667"
viewBox="0 0 114.66667 114.66667"
inkscape:version="0.92.4 (unknown)"
sodipodi:docname="harbour-fernschreiber-3.svg">
<defs>
<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>
height="114.667"
width="114.667">
<metadata
id="metadata23">
<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="defs9">
<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)"
id="a"
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
style="stop-opacity:1;stop-color:#ec7221"
offset="0"
id="stop5" />
id="stop2"
stop-color="#ec7221"
offset="0" />
<stop
style="stop-opacity:1;stop-color:#e7454c"
offset="0.959184"
id="stop7" />
id="stop4"
stop-color="#e7454c"
offset=".959" />
<stop
style="stop-opacity:1;stop-color:#e7454c"
offset="1"
id="stop9" />
id="stop6"
stop-color="#e7454c"
offset="1" />
</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);stroke:none"
inkscape:connector-curvature="0"
id="path14" />
</g>
</g>
<g
transform="translate(75,43.1621)"
id="g20" />
id="path11"
transform="matrix(1.33333 0 0 -1.33333 0 114.667)"
fill="url(#a)"
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" />
<path
style="opacity:0.9;fill:#fcba02;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:#fffda9;fill-opacity:1;fill-rule:nonzero;stroke:none"
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:#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>
id="path13"
fill="#fcba02"
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" />
<path
style="fill:#fffda9"
id="path15"
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" />
<path
style="fill:#fffee3"
id="path17"
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" />
</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
pictureThumbnail {
photoData: photo_small || ({})
highlighted: listItem.highlighted && !listItem.menuOpen
}
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
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
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
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
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
unreadReactionCount: unread_reaction_count
unreadMentionCount: unread_mention_count
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
onPressAndHold: {
contextMenuLoader.active = true;
}
Loader {
id: contextMenuLoader
active: false
asynchronous: true
onStatusChanged: {
if(status === Loader.Ready) {
listItem.menu = item;
listItem.openMenu();
}
}
sourceComponent: Component {
ContextMenu {
menu: ContextMenu {
MenuItem {
visible: unread_count > 0 || unread_reaction_count > 0 || unread_mention_count > 0
visible: unread_count > 0
onClicked: {
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")
}
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 {
visible: chat_id != listItem.ownUserId
onClicked: {
@ -87,7 +45,7 @@ PhotoTextsListItem {
newNotificationSettings.use_default_mute_for = false;
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 {
@ -101,7 +59,5 @@ PhotoTextsListItem {
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 var inReplyToMessage;
property bool editable: false;
property bool inReplyToMessageDeleted: false;
signal clearRequested()
onInReplyToMessageChanged: {
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"));
inReplyToMessageText.text = Emoji.emojify(Functions.getMessageText(inReplyToRow.inReplyToMessage, true, inReplyToRow.myUserId, false), inReplyToMessageText.font.pixelSize);
}
}
onInReplyToMessageDeletedChanged: {
if (inReplyToMessageDeleted) {
inReplyToUserText.text = qsTr("Unknown")
inReplyToMessageText.text = "<i>" + qsTr("This message was deleted") + "</i>";
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.inReplyToMessage.sender.user_id === inReplyToRow.myUserId, false), inReplyToMessageText.font.pixelSize);
}
}

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 Sailfish.Silica 1.0
import "./messageContent"
import "../js/twemoji.js" as Emoji
import "../js/functions.js" as Functions
import "../js/debug.js" as Debug
ListItem {
id: messageListItem
contentHeight: messageBackground.height + Theme.paddingMedium + ( reactionsColumn.visible ? reactionsColumn.height : 0 )
Behavior on contentHeight { NumberAnimation { duration: 200 } }
contentHeight: messageBackground.height + Theme.paddingMedium
property var chatId
property var messageId
property int messageIndex
property int messageViewCount
property var myMessage
property var reactions
property bool canReplyToMessage
readonly property bool isAnonymous: myMessage.sender_id["@type"] === "messageSenderChat"
readonly property var userInformation: tdLibWrapper.getUserInformation(myMessage.sender_id.user_id)
readonly property var userInformation: tdLibWrapper.getUserInformation(myMessage.sender.user_id)
property QtObject precalculatedValues: ListView.view.precalculatedValues
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 bool isSelected: messageListItem.precalculatedValues.pageIsSelecting && page.selectedMessages.some(function(existingMessage) {
return existingMessage.id === messageId
});
readonly property bool isOwnMessage: page.myUserId === myMessage.sender_id.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 bool hasContentComponent
property bool additionalOptionsOpened
property bool wasNavigatedTo: false
readonly property bool isOwnMessage: page.myUserId === myMessage.sender.user_id
property string extraContentComponentName
readonly property var additionalItemsModel: (extraContentLoader.item && ("extraContextMenuItems" in extraContentLoader.item)) ?
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
highlighted: (down || isSelected) && !menuOpen
openMenuOnPressAndHold: !messageListItem.precalculatedValues.pageIsSelecting
signal replyToMessage()
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: {
if (messageListItem.precalculatedValues.pageIsSelecting) {
if(messageListItem.precalculatedValues.pageIsSelecting) {
page.toggleMessageSelection(myMessage);
} else {
if (messageOptionsDrawer.sourceItem !== messageListItem) {
messageOptionsDrawer.open = false
}
// Allow extra context to react to click
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()
} 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: {
if (openMenuOnPressAndHold) {
openContextMenu()
} else {
page.selectedMessages = []
if(messageListItem.precalculatedValues.pageIsSelecting) {
page.selectedMessages = [];
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 {
id: contextMenuLoader
active: false
@ -224,50 +81,53 @@ ListItem {
}
sourceComponent: Component {
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 {
visible: canReplyToMessage
onClicked: replyToMessage()
visible: messageListItem.canReplyToMessage
onClicked: messageListItem.replyToMessage()
text: qsTr("Reply to Message")
}
MenuItem {
visible: typeof myMessage.can_be_edited !== "undefined" && myMessage.can_be_edited
onClicked: editMessage()
visible: myMessage.can_be_edited
onClicked: messageListItem.editMessage()
text: qsTr("Edit Message")
}
MenuItem {
onClicked: page.toggleMessageSelection(myMessage)
text: qsTr("Select Message")
onClicked: {
Clipboard.text = Functions.getMessageText(myMessage, true, false, true);
}
MenuItem {
visible: showCopyMessageToClipboardMenuItem
onClicked: copyMessageToClipboard()
text: qsTr("Copy Message to Clipboard")
}
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: {
messageOptionsDrawer.myMessage = 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;
page.toggleMessageSelection(myMessage);
}
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 {
target: chatModel
onMessagesReceived: {
messageBackground.isUnread = index > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage";
messageBackground.isUnread = index > chatModel.getLastReadMessageIndex();
}
onMessagesIncrementalUpdate: {
messageBackground.isUnread = index > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage";
messageBackground.isUnread = index > chatModel.getLastReadMessageIndex();
}
onNewMessageReceived: {
messageBackground.isUnread = index > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage";
messageBackground.isUnread = index > chatModel.getLastReadMessageIndex();
}
onUnreadCountUpdated: {
messageBackground.isUnread = index > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage";
messageBackground.isUnread = index > chatModel.getLastReadMessageIndex();
}
onLastReadSentMessageUpdated: {
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);
}
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 {
target: tdLibWrapper
onReceivedMessage: {
if (messageId === myMessage.reply_to_message_id) {
if (messageId === myMessage.reply_to_message_id.toString()) {
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: {
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: {
Debug.log("[ChatModel] This message was updated, index", messageIndex, ", updating content...");
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;
if (myMessage.reply_to_message_id !== 0) {
tdLibWrapper.getMessage(page.chatInformation.id, myMessage.reply_to_message_id);
}
}
@ -382,10 +183,10 @@ ListItem {
repeat: false
running: false
onTriggered: {
if (messageListItem.hasContentComponent) {
var type = myMessage.content["@type"];
if (typeof myMessage.content !== "undefined") {
if (messageListItem.extraContentComponentName !== "") {
extraContentLoader.setSource(
"../components/messageContent/" + type.charAt(0).toUpperCase() + type.substring(1) + ".qml",
"../components/" +messageListItem.extraContentComponentName +".qml",
{
messageListItem: messageListItem
})
@ -396,15 +197,13 @@ ListItem {
}
}
}
}
Row {
id: messageTextRow
spacing: Theme.paddingSmall
width: precalculatedValues.entryWidth
anchors.horizontalCenter: Functions.isWidescreen(appWindow) ? undefined : parent.horizontalCenter
anchors.left: Functions.isWidescreen(appWindow) ? parent.left : undefined
y: Theme.paddingSmall
anchors.leftMargin: Functions.isWidescreen(appWindow) ? Theme.paddingMedium : undefined
anchors.centerIn: parent
Loader {
id: profileThumbnailLoader
@ -417,16 +216,16 @@ ListItem {
sourceComponent: Component {
ProfileThumbnail {
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
width: Theme.itemSizeSmall
height: Theme.itemSizeSmall
visible: precalculatedValues.showUserInfo
MouseArea {
anchors.fill: parent
enabled: !(messageListItem.precalculatedValues.pageIsSelecting || messageListItem.isAnonymous)
enabled: !messageListItem.precalculatedValues.pageIsSelecting
onClicked: {
tdLibWrapper.createPrivateChat(messageListItem.userInformation.id, "openDirectly");
tdLibWrapper.createPrivateChat(messageListItem.userInformation.id);
}
}
}
@ -444,16 +243,16 @@ ListItem {
anchors {
left: parent.left
leftMargin: page.isPrivateChat ? (messageListItem.isOwnMessage ? precalculatedValues.pageMarginDouble : 0) : 0 //левый марджин для собственных сообщений в приватных чатах. В остальных на полную ширину
leftMargin: messageListItem.isOwnMessage ? precalculatedValues.pageMarginDouble : 0
verticalCenter: parent.verticalCenter
}
height: messageTextColumn.height + precalculatedValues.paddingMediumDouble
width: precalculatedValues.backgroundWidth
property bool isUnread: index > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage"
color: Theme.colorScheme === Theme.LightOnDark ? (isOwnMessage ? Theme.highlightBackgroundColor : (isUnread ? Theme.secondaryHighlightColor : Theme.secondaryColor)) : (isOwnMessage ? Theme.highlightBackgroundColor : (isUnread ? Theme.backgroundGlowColor : Theme.overlayBackgroundColor))
property bool isUnread: index > chatModel.getLastReadMessageIndex()
color: isUnread ? Theme.secondaryHighlightColor : Theme.secondaryColor
radius: parent.width / 50
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 opacity { FadeAnimation {} }
}
@ -471,7 +270,7 @@ ListItem {
id: userText
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.weight: Font.ExtraBold
color: messageListItem.textColor
@ -479,28 +278,23 @@ ListItem {
truncationMode: TruncationMode.Fade
textFormat: Text.StyledText
horizontalAlignment: messageListItem.textAlign
visible: messageListItem.isOwnMessage ? false : (precalculatedValues.showUserInfo || myMessage['@type'] === "sponsoredMessage")
visible: precalculatedValues.showUserInfo
MouseArea {
anchors.fill: parent
enabled: !(messageListItem.precalculatedValues.pageIsSelecting || messageListItem.isAnonymous)
enabled: !messageListItem.precalculatedValues.pageIsSelecting
onClicked: {
tdLibWrapper.createPrivateChat(messageListItem.userInformation.id, "openDirectly");
tdLibWrapper.createPrivateChat(messageListItem.userInformation.id);
}
}
}
MessageViaLabel {
message: myMessage
}
Loader {
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
// text height ~= 1,28*font.pixelSize
height: active ? precalculatedValues.messageInReplyToHeight : 0
property var inReplyToMessage;
property bool inReplyToMessageDeleted: false;
sourceComponent: Component {
Item {
width: messageInReplyToRow.width
@ -508,31 +302,14 @@ ListItem {
InReplyToRow {
id: messageInReplyToRow
myUserId: page.myUserId
layer.enabled: messageInReplyToMouseArea.pressed && !messageListItem.highlighted && !messageListItem.menuOpen
layer.effect: PressEffect { source: messageInReplyToRow }
visible: true
inReplyToMessage: messageInReplyToLoader.inReplyToMessage
inReplyToMessageDeleted: messageInReplyToLoader.inReplyToMessageDeleted
}
MouseArea {
id: messageInReplyToMouseArea
anchors.fill: parent
onClicked: {
if (precalculatedValues.pageIsSelecting) {
page.toggleMessageSelection(myMessage)
} 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()
}
messageOverlayLoader.overlayMessage = messageInReplyToRow.inReplyToMessage;
messageOverlayLoader.active = true;
}
}
}
@ -552,12 +329,11 @@ ListItem {
width: parent.width
Component.onCompleted: {
var originType = myMessage.forward_info.origin["@type"]
if (originType === "messageOriginChannel" || originType === "messageForwardOriginChannel") {
if (myMessage.forward_info.origin["@type"] === "messageForwardOriginChannel") {
var otherChatInformation = tdLibWrapper.getChat(myMessage.forward_info.origin.chat_id);
forwardedThumbnail.photoData = (typeof otherChatInformation.photo !== "undefined") ? otherChatInformation.photo.small : {};
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);
forwardedThumbnail.photoData = (typeof otherUserInformation.profile_photo !== "undefined") ? otherUserInformation.profile_photo.small : {};
forwardedChannelText.text = Emoji.emojify(Functions.getUserName(otherUserInformation), Theme.fontSizeExtraSmall);
@ -603,46 +379,35 @@ ListItem {
Text {
id: messageText
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
color: messageListItem.textColor
wrapMode: Text.Wrap
textFormat: Text.StyledText
onLinkActivated: {
var chatCommand = Functions.handleLink(link);
if(chatCommand) {
tdLibWrapper.sendTextMessage(chatInformation.id, chatCommand);
}
Functions.handleLink(link);
}
horizontalAlignment: messageListItem.textAlign
linkColor: Theme.highlightColor
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 {
id: webPagePreviewLoader
active: false
asynchronous: true
width: parent.width * getContentWidthMultiplier()
height: (status === Loader.Ready) ? item.implicitHeight : myMessage.content.web_page ? precalculatedValues.webPagePreviewHeight : 0
width: parent.width
height: typeof myMessage.content.web_page !== "undefined" ? precalculatedValues.webPagePreviewHeight : 0
sourceComponent: Component {
id: webPagePreviewComponent
WebPagePreview {
id: webPagePreview
onImplicitHeightChanged: {
webPagePreviewLoader.height = webPagePreview.implicitHeight;
}
webPageData: myMessage.content.web_page
width: parent.width
highlighted: messageListItem.highlighted
@ -652,9 +417,9 @@ ListItem {
Loader {
id: extraContentLoader
width: parent.width * getContentWidthMultiplier()
width: parent.width
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 {
@ -664,15 +429,6 @@ ListItem {
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 {
id: messageDateUpdater
interval: 60000
@ -683,6 +439,7 @@ ListItem {
}
}
Text {
width: parent.width
@ -703,85 +460,10 @@ 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
}
}
}
}
}
}
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 "../js/twemoji.js" as Emoji
import "../js/functions.js" as Functions
import "../js/debug.js" as Debug
Item {
id: messageListItem
property var myMessage: display
property bool senderIsUser: myMessage.sender_id["@type"] === "messageSenderUser"
property var userInformation: senderIsUser ? tdLibWrapper.getUserInformation(myMessage.sender_id.user_id) : null
property bool isOwnMessage: senderIsUser && chatPage.myUserId === myMessage.sender_id.user_id
property var linkedMessage
property var userInformation: tdLibWrapper.getUserInformation(myMessage.sender.user_id)
property bool isOwnMessage: chatPage.myUserId === myMessage.sender.user_id
height: backgroundRectangle.height + Theme.paddingMedium
Rectangle {
@ -36,7 +33,7 @@ Item {
anchors.centerIn: parent
height: messageText.height + 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
}
Text {
@ -46,43 +43,11 @@ Item {
color: Theme.highlightColor
horizontalAlignment: Text.AlignHCenter
font.pixelSize: Theme.fontSizeExtraSmall
property string messageContentText: Functions.getMessageText(messageListItem.myMessage, false, chatPage.myUserId, false)
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)
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)
textFormat: Text.RichText
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
onLinkActivated: {
if(link === "linkedmessage" && linkedMessage) {
messageOverlayLoader.overlayMessage = linkedMessage;
messageOverlayLoader.active = true;
} else {
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 Sailfish.Silica 1.0
import "./messageContent"
import "../components"
import "../js/functions.js" as Functions
import "../js/twemoji.js" as Emoji
import "../js/debug.js" as Debug
Flickable {
id: messageOverlayFlickable
@ -32,21 +31,19 @@ Flickable {
property var overlayMessage;
property bool showHeader: true
readonly property var userInformation: tdLibWrapper.getUserInformation(overlayMessage.sender_id.user_id);
readonly property bool isOwnMessage: tdLibWrapper.getUserInformation().id === overlayMessage.sender_id.user_id;
readonly property bool isAnonymous: overlayMessage.sender_id["@type"] === "messageSenderChat"
property bool hasContentComponent: overlayMessage.content && chatView.delegateMessagesContent.indexOf(overlayMessage.content['@type']) > -1
readonly property var userInformation: tdLibWrapper.getUserInformation(overlayMessage.sender.user_id);
readonly property bool isOwnMessage: tdLibWrapper.getUserInformation().id === overlayMessage.sender.user_id;
readonly property string extraContentComponentName: (typeof overlayMessage.content !== "undefined" && typeof chatView.contentComponentNames[overlayMessage.content['@type']] !== "undefined" )
? chatView.contentComponentNames[overlayMessage.content['@type']] : ""
signal requestClose;
function getOriginalAuthor(forwardInformation, fontSize) {
switch (forwardInformation.origin["@type"]) {
case "messageOriginChannel":
case "messageForwardOriginChannel":
var otherChatInformation = tdLibWrapper.getChat(forwardInformation.origin.chat_id);
return Emoji.emojify(otherChatInformation.title, fontSize);
case "messageOriginUser":
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);
default:
return Emoji.emojify(forwardInformation.origin.sender_name, fontSize);
@ -63,18 +60,21 @@ Flickable {
repeat: false
running: false
onTriggered: {
if (messageOverlayFlickable.hasContentComponent) {
var type = overlayMessage.content["@type"];
if (typeof overlayMessage.content !== "undefined") {
if (messageOverlayFlickable.extraContentComponentName !== "") {
overlayExtraContentLoader.setSource(
"../components/messageContent/" + type.charAt(0).toUpperCase() + type.substring(1) + ".qml",
"../components/" + messageOverlayFlickable.extraContentComponentName + ".qml",
{
overlayFlickable: messageOverlayFlickable
})
} else if(overlayMessage.content && overlayMessage.content.web_page) {
} else {
if (typeof overlayMessage.content.web_page !== "undefined") {
overlayWebPagePreviewLoader.active = true;
}
}
}
}
}
Rectangle {
id: messageContentBackground
@ -104,7 +104,7 @@ Flickable {
spacing: Theme.paddingMedium
ProfileThumbnail {
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
width: Theme.itemSizeLarge
height: Theme.itemSizeLarge
@ -114,7 +114,7 @@ Flickable {
width: parent.width - overlayMessagePictureThumbnail.width
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.weight: Font.ExtraBold
maximumLineCount: 1
@ -123,10 +123,6 @@ Flickable {
}
}
MessageViaLabel {
message: overlayMessage
}
Text {
id: overlayForwardedInfoText
width: parent.width
@ -142,7 +138,7 @@ Flickable {
Text {
id: overlayMessageText
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
color: Theme.primaryColor
wrapMode: Text.Wrap
@ -182,16 +178,6 @@ Flickable {
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 {
id: messageDateUpdater
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 Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
import "../js/functions.js" as Functions
ListItem {
id: chatListViewItem
@ -12,32 +11,36 @@ ListItem {
property alias tertiaryText: tertiaryText //usually last message date
property int unreadCount: 0
property int unreadMentionCount: 0
property int unreadReactionCount: 0
property bool isSecret: false
property bool isVerified: false
property bool isMarkedAsUnread: false
property bool isPinned: false
property bool isMuted: false
property alias pictureThumbnail: pictureThumbnail
contentHeight: Theme.itemSizeExtraLarge
contentHeight: mainRow.height + separator.height + 2 * Theme.paddingMedium
contentWidth: parent.width
ShaderEffectSource {
id: pictureItem
height: Theme.itemSizeLarge
width: height
Column {
id: mainColumn
width: parent.width - ( 2 * Theme.horizontalPageMargin )
spacing: Theme.paddingSmall
anchors {
left: parent.left
leftMargin: Theme.horizontalPageMargin
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
}
sourceItem: Item {
width: pictureItem.width
height: pictureItem.width
Row {
id: mainRow
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 {
id: pictureThumbnail
@ -46,54 +49,33 @@ ListItem {
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 {
id: chatSecretBackground
color: Theme.rgba(Theme.overlayBackgroundColor, Theme.opacityFaint)
width: Theme.fontSizeLarge
height: Theme.fontSizeLarge
color: Theme.overlayBackgroundColor
width: Theme.fontSizeExtraLarge
height: Theme.fontSizeExtraLarge
anchors.bottom: parent.bottom
radius: parent.width / 2
visible: chatListViewItem.isSecret
}
Icon {
Image {
source: "image://theme/icon-s-secure"
height: Theme.iconSizeExtraSmall
width: Theme.iconSizeExtraSmall
highlighted: chatListViewItem.highlighted
height: Theme.fontSizeMedium
width: Theme.fontSizeMedium
anchors.centerIn: chatSecretBackground
visible: chatListViewItem.isSecret
}
Rectangle {
id: chatUnreadMessagesCountBackground
color: isMuted ? ((Theme.colorScheme === Theme.DarkOnLight) ? "lightgray" : "dimgray") : Theme.highlightBackgroundColor
width: chatUnreadMessagesCount.width + Theme.fontSizeLarge / 2
color: Theme.highlightBackgroundColor
width: Theme.fontSizeLarge
height: Theme.fontSizeLarge
anchors.right: parent.right
anchors.bottom: parent.bottom
radius: parent.width / 2
visible: chatListViewItem.unreadCount > 0 || chatListViewItem.isMarkedAsUnread
visible: chatListViewItem.unreadCount > 0
}
Text {
@ -102,54 +84,16 @@ ListItem {
font.bold: true
color: Theme.primaryColor
anchors.centerIn: chatUnreadMessagesCountBackground
visible: chatListViewItem.unreadCount > 0
opacity: isMuted ? Theme.opacityHigh : 1.0
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: "@"
}
visible: chatUnreadMessagesCountBackground.visible
text: chatListViewItem.unreadCount > 99 ? "99+" : chatListViewItem.unreadCount
}
}
}
Column {
id: contentColumn
anchors {
verticalCenter: parent.verticalCenter
left: pictureItem.right
leftMargin: Theme.paddingSmall
right: parent.right
rightMargin: Theme.horizontalPageMargin
}
spacing: Theme.paddingSmall / 2
width: mainColumn.width - pictureColumn.width - mainRow.spacing
spacing: Theme.paddingSmall
Row {
id: primaryTextRow
@ -161,29 +105,15 @@ ListItem {
font.pixelSize: Theme.fontSizeMedium
truncationMode: TruncationMode.Fade
anchors.verticalCenter: parent.verticalCenter
width: Math.min(contentColumn.width - (verifiedImage.visible ? (verifiedImage.width + primaryTextRow.spacing) : 0) - (mutedImage.visible ? (mutedImage.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
width: Math.min(contentColumn.width - (verifiedImage.visible ? (verifiedImage.width + primaryTextRow.spacing) : 0), implicitWidth)
}
Image {
id: verifiedImage
anchors.verticalCenter: parent.verticalCenter
source: chatListViewItem.isVerified ? "../../images/icon-verified.svg" : ""
sourceSize: Qt.size(Theme.iconSizeExtraSmall, Theme.iconSizeExtraSmall)
width: Theme.iconSizeSmall
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
sourceSize.width: Theme.iconSizeExtraSmall
width: Theme.iconSizeExtraSmall
visible: status === Image.Ready
}
}
@ -217,12 +147,14 @@ ListItem {
truncationMode: TruncationMode.Fade
}
}
}
}
Separator {
id: separator
anchors {
bottom: parent.bottom
bottomMargin: -1
top: mainColumn.bottom
topMargin: Theme.paddingMedium
}
width: parent.width

View file

@ -33,9 +33,9 @@ Item {
onPinnedMessageChanged: {
if (pinnedMessage) {
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 );
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;
} else {
pinnedMessageItem.visible = false;
@ -123,7 +123,7 @@ Item {
id: unpinMessageIconButton
icon.source: "image://theme/icon-m-remove"
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(); });
}

View file

@ -21,13 +21,15 @@ import QtQuick 2.6
import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
import "../../js/functions.js" as Functions
import "../../js/twemoji.js" as Emoji
import "../js/functions.js" as Functions
import "../js/twemoji.js" as Emoji
MessageContentBase {
Item {
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 bool isOwnMessage: messageListItem ? messageListItem.isOwnMessage : overlayFlickable.isOwnMessage
readonly property string messageId: rawMessage.id
@ -42,6 +44,9 @@ MessageContentBase {
}
readonly property bool canAnswer: !hasAnswered && !pollData.is_closed
readonly property bool isQuiz: pollData.type['@type'] === "pollTypeQuiz"
property bool highlighted
width: parent.width
height: pollColumn.height
property list<NamedAction> extraContextMenuItems: [
NamedAction {
visible: !pollData.is_closed && pollMessageComponent.canEdit
@ -230,24 +235,6 @@ MessageContentBase {
width: 1
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 {
x: -Theme.horizontalPageMargin/2
@ -277,7 +264,7 @@ MessageContentBase {
visible: !pollMessageComponent.canAnswer && !pollData.is_anonymous && pollData.total_voter_count > 0
icon.source: "image://theme/icon-m-media-artists"
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 {
opacity: 0.8

View file

@ -22,6 +22,7 @@ import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
Item {
id: profileThumbnail
property alias photoData: file.fileInformation
@ -29,10 +30,6 @@ Item {
property int radius: width / 2
property int imageStatus: -1
property bool optimizeImageSize: true
property bool highlighted
layer.enabled: highlighted
layer.effect: PressEffect { source: profileThumbnail }
function getReplacementString() {
if (replacementStringHint.length > 2) {
@ -69,6 +66,7 @@ Item {
id: singleImage
width: parent.width - Theme.paddingSmall
height: width
anchors.centerIn: parent
source: file.path
sourceSize.width: optimizeImageSize ? width : 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
anchors.fill: parent
property var recentStickers: stickerManager.getRecentStickers();
property var installedStickerSets: stickerManager.getInstalledStickerSets();
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)
}
}
}
property var recentStickers: stickerManager.getRecentStickers()
property var installedStickerSets: stickerManager.getInstalledStickerSets()
property bool pickerLoaded: false
signal stickerPicked(var stickerId)
Timer {
id: stickerPickerLoadedTimer
interval: 100
running: true
repeat: false
onTriggered: {
stickerPickerOverlayItem.pickerLoaded = true;
}
}
Rectangle {
id: stickerPickerOverlayBackground
anchors.fill: parent
@ -79,32 +49,35 @@ Item {
opacity: 0.7
}
SilicaListView {
id: stickerPickerListView
Flickable {
id: stickerPickerFlickable
anchors.fill: parent
anchors.margins: Theme.paddingMedium
opacity: stickerPickerOverlayItem.pickerLoaded ? 1 : 0
Behavior on opacity { NumberAnimation {} }
visible: stickerPickerOverlayItem.pickerLoaded
contentHeight: stickerPickerColumn.height
clip: true
model: stickerPickerOverlayItem.installedStickerSets
header: Column {
spacing: Theme.paddingSmall
width: stickerPickerListView.width
height: recentStickersGridView.count > 0 ? ( Theme.fontSizeLarge + Theme.itemSizeExtraLarge + 4 * Theme.paddingSmall ) : 0
topPadding: Theme.paddingSmall
Column {
id: stickerPickerColumn
spacing: Theme.paddingMedium
width: stickerPickerFlickable.width
Label {
font.pixelSize: Theme.fontSizeLarge
font.pixelSize: Theme.fontSizeMedium
font.bold: true
width: recentStickersGridView.width
leftPadding: Theme.paddingMedium
visible: recentStickersGridView.count > 0
width: parent.width
maximumLineCount: 1
truncationMode: TruncationMode.Fade
text: qsTr("Recently used")
}
SilicaGridView {
id: recentStickersGridView
width: stickerPickerListView.width
height: Theme.itemSizeExtraLarge + Theme.paddingSmall
width: parent.width
height: Theme.itemSizeExtraLarge
cellWidth: Theme.itemSizeExtraLarge;
cellHeight: Theme.itemSizeExtraLarge;
visible: count > 0
@ -112,132 +85,119 @@ Item {
flow: GridView.FlowTopToBottom
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 {}
}
}
delegate: Column {
id: stickerSetColumn
property bool isExpanded: false
function toggleDisplaySet() {
stickerSetColumn.isExpanded = !stickerSetColumn.isExpanded;
if (stickerSetColumn.isExpanded) {
stickerSetLoader.myStickerSet = modelData.stickers;
}
}
spacing: Theme.paddingSmall
width: parent.width
Row {
id: stickerSetTitleRow
width: parent.width
height: Theme.itemSizeMedium + ( 2 * Theme.paddingSmall )
Repeater {
model: stickerPickerOverlayItem.installedStickerSets
width: stickerPickerFlickable.width
Column {
spacing: Theme.paddingMedium
BackgroundItem {
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
}
width: parent.width
Label {
id: setTitleText
font.pixelSize: Theme.fontSizeLarge
font.pixelSize: Theme.fontSizeMedium
font.bold: true
anchors {
left: stickerSetThumbnail.right
right: expandSetButton.left
verticalCenter: parent.verticalCenter
margins: Theme.paddingSmall
}
width: parent.width
maximumLineCount: 1
truncationMode: TruncationMode.Fade
text: modelData.title
}
Icon {
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 {
SilicaGridView {
id: installedStickerSetGridView
width: stickerSetLoader.width
height: stickerSetLoader.height
orientation: Qt.Horizontal
width: parent.width
height: Theme.itemSizeExtraLarge
cellWidth: Theme.itemSizeExtraLarge;
cellHeight: Theme.itemSizeExtraLarge;
visible: count > 0
clip: true
flow: GridView.FlowTopToBottom
model: stickerSetLoader.myStickerSet
delegate: stickerComponent
model: modelData.stickers
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 {}
}
}
}
}
}
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.
@ -19,23 +19,25 @@
import QtQuick 2.6
import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
import "../"
import "../../js/twemoji.js" as Emoji
MessageContentBase {
id: thisItem
Item {
property ListItem messageListItem
property MessageOverlayFlickable overlayFlickable
property var stickerData: messageListItem ? messageListItem.myMessage.content.sticker : overlayFlickable.overlayMessage.content.sticker;
readonly property bool asEmoji: appSettings.showStickersAsEmojis
readonly property bool animated: stickerData.format["@type"] === "stickerFormatTgs" && appSettings.animateStickers
readonly property var stickerData: messageListItem ? messageListItem.myMessage.content.sticker : overlayFlickable.overlayMessage.content.sticker;
readonly property bool animated: stickerData.is_animated && appSettings.animateStickers
readonly property bool stickerVisible: staticStickerLoader.item ? staticStickerLoader.item.visible :
animatedStickerLoader.item ? animatedStickerLoader.item.visible : false
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
implicitHeight: stickerData.height
layer.enabled: highlighted
layer.effect: PressEffect { source: singleImage }
TDLibFile {
id: file
tdlib: tdLibWrapper
@ -44,7 +46,6 @@ MessageContentBase {
}
Item {
width: Math.min( stickerData.width, parent.width )
height: width * aspectRatio
// (centered in image mode, text-like in sticker mode)
@ -55,17 +56,14 @@ MessageContentBase {
Loader {
id: animatedStickerLoader
anchors.fill: parent
active: animated && !asEmoji
active: animated
sourceComponent: Component {
AnimatedImage {
id: animatedSticker
anchors.fill: parent
source: file.path
asynchronous: true
paused: !Qt.application.active
cache: false
layer.enabled: thisItem.highlighted
layer.effect: PressEffect { source: animatedSticker }
}
}
}
@ -73,24 +71,17 @@ MessageContentBase {
Loader {
id: staticStickerLoader
anchors.fill: parent
active: !animated || asEmoji
active: !animated
sourceComponent: Component {
Image {
id: staticSticker
anchors.fill: parent
source: asEmoji ? Emoji.getEmojiPath(stickerData.emoji) : file.path
sourceSize {
width: width
height: height
}
source: file.path
fillMode: Image.PreserveAspectFit
autoTransform: true
asynchronous: true
visible: opacity > 0
opacity: status === Image.Ready ? 1 : 0
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 {
id: placeHolderDelayTimer
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 Sailfish.Silica 1.0
import QtMultimedia 5.6
import "../"
import "../../js/functions.js" as Functions
import "../../js/debug.js" as Debug
import "../js/functions.js" as Functions
import "../js/debug.js" as Debug
MessageContentBase {
Item {
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 string videoUrl;
property int previewFileId;
@ -35,7 +38,10 @@ MessageContentBase {
property bool onScreen: messageListItem ? messageListItem.page.status === PageStatus.Active : true;
property string videoType : "video";
property bool playRequested: false;
property bool highlighted;
signal clicked();
width: parent.width
height: videoMessageComponent.isVideoNote ? width : Functions.getVideoHeight(width, videoData)
Timer {
@ -83,7 +89,7 @@ MessageContentBase {
videoMessageComponent.videoType = videoMessageComponent.isVideoNote ? "video" : videoData['@type'];
videoFileId = videoData[videoType].id;
if (typeof rawMessage !== "undefined" && rawMessage.content['@type'] === "messageAnimation") {
if (rawMessage.content['@type'] === "messageAnimation") {
playButton.visible = true;
fullscreenButton.visible = !videoMessageComponent.fullscreen;
handlePlay();
@ -95,7 +101,7 @@ MessageContentBase {
tdLibWrapper.downloadFile(previewFileId);
}
} else {
placeholderImage.source = "image://theme/icon-m-video?white";
placeholderImage.source = "image://theme/icon-l-video?white";
placeholderImage.width = Theme.itemSizeLarge
placeholderImage.height = Theme.itemSizeLarge
}
@ -147,7 +153,7 @@ MessageContentBase {
asynchronous: true
visible: status === Image.Ready ? true : false
layer.enabled: videoMessageComponent.highlighted
layer.effect: PressEffect { source: placeholderImage }
layer.effect: PressEffect { source: singleImage }
}
BackgroundImage {
@ -155,6 +161,7 @@ MessageContentBase {
}
Rectangle {
id: placeholderBackground
color: "black"
opacity: 0.3
height: parent.height
@ -209,7 +216,7 @@ MessageContentBase {
height: Theme.iconSizeLarge
icon {
asynchronous: true
source: "../../../images/icon-l-fullscreen.svg"
source: "../../images/icon-l-fullscreen.svg"
sourceSize {
width: Theme.iconSizeLarge
height: Theme.iconSizeLarge
@ -218,7 +225,7 @@ MessageContentBase {
highlighted: videoMessageComponent.highlighted || down
visible: ( placeholderImage.status === Image.Ready && !videoMessageComponent.fullscreen ) ? true : false
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 {
id: videoErrorShade
width: parent.width
height: parent.height
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 {
id: messageVideo
@ -346,7 +369,7 @@ MessageContentBase {
height: parent.height
source: videoUrl
layer.enabled: videoMessageComponent.highlighted
layer.effect: PressEffect { source: messageVideo }
layer.effect: PressEffect { source: singleImage }
onStopped: {
enableScreensaver();
messageVideo.visible = false;
@ -355,21 +378,6 @@ MessageContentBase {
videoComponentLoader.active = false;
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 {
@ -456,7 +464,7 @@ MessageContentBase {
highlighted: videoMessageComponent.highlighted || down
icon {
asynchronous: true
source: "../../../images/icon-l-fullscreen.svg"
source: "../../images/icon-l-fullscreen.svg"
sourceSize {
width: Theme.iconSizeLarge
height: Theme.iconSizeLarge
@ -464,7 +472,7 @@ MessageContentBase {
}
visible: ( videoComponentLoader.active && messageVideo.playbackState === MediaPlayer.PausedState ) ? true : false
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.bottom: positionText.top
minimumValue: 0
maximumValue: messageVideo.duration ? messageVideo.duration : 0.1
maximumValue: messageVideo.duration ? messageVideo.duration : 0
highlighted: videoMessageComponent.highlighted || down
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 QtGraphicalEffects 1.0
import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
import "../"
import "../../js/functions.js" as Functions
import "../components"
import "../js/twemoji.js" as Emoji
import "../js/functions.js" as Functions
Column {
id: webPagePreviewColumn
property var webPageData;
property var pictureFileInformation;
property bool hasImage: false;
property bool largerFontSize: false;
property bool highlighted
readonly property bool hasImage: picture.fileId !== 0
readonly property int fontSize: largerFontSize ? Theme.fontSizeSmall : Theme.fontSizeExtraSmall
spacing: Theme.paddingSmall
Component.onCompleted: updatePhoto()
Component.onCompleted: {
updateWebPage();
}
onWebPageDataChanged: updatePhoto()
function updatePhoto() {
function updateWebPage() {
if (webPageData) {
if (webPageData.photo) {
if (typeof webPageData.photo !== "undefined") {
hasImage = true;
// Check first which size fits best...
var photo
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) {
break;
}
}
if (photo) {
picture.fileInformation = photo
if (pictureFileInformation.local.is_downloading_completed) {
singleImage.source = pictureFileInformation.local.path;
} else {
tdLibWrapper.downloadFile(pictureFileInformation.id);
}
}
}
}
function clicked() {
descriptionText.toggleMaxLineCount()
Connections {
target: tdLibWrapper
onFileUpdated: {
if (typeof pictureFileInformation !== "undefined" && fileId === pictureFileInformation.id) {
if (fileInformation.local.is_downloading_completed) {
pictureFileInformation = fileInformation;
singleImage.source = fileInformation.local.path;
}
}
}
}
TDLibFile {
id: picture
tdlib: tdLibWrapper
autoLoad: true
}
MultilineEmojiLabel {
Label {
id: siteNameText
width: parent.width
rawText: webPageData.site_name ? webPageData.site_name : ""
font.pixelSize: webPagePreviewColumn.fontSize
text: webPageData.site_name ? Emoji.emojify(webPageData.site_name, font.pixelSize) : ""
font.pixelSize: webPagePreviewColumn.largerFontSize ? Theme.fontSizeSmall : Theme.fontSizeExtraSmall
font.bold: true
color: Theme.secondaryHighlightColor
visible: (rawText !== "")
maxLineCount: 1
truncationMode: TruncationMode.Fade
maximumLineCount: 1
textFormat: Text.StyledText
visible: (text !== "")
}
MultilineEmojiLabel {
Label {
id: titleText
width: parent.width
rawText: webPageData.title ? webPageData.title : ""
font.pixelSize: webPagePreviewColumn.fontSize
text: webPageData.title ? Emoji.emojify(webPageData.title, font.pixelSize) : ""
font.pixelSize: webPagePreviewColumn.largerFontSize ? Theme.fontSizeSmall : Theme.fontSizeExtraSmall
font.bold: true
visible: (rawText !== "")
maxLineCount: 2
truncationMode: TruncationMode.Fade
wrapMode: Text.Wrap
maximumLineCount: 2
textFormat: Text.StyledText
visible: (text !== "")
}
MultilineEmojiLabel {
Label {
id: descriptionText
width: parent.width
rawText: webPageData.description ? Functions.enhanceMessageText(webPageData.description) : ""
font.pixelSize: webPagePreviewColumn.fontSize
visible: (rawText !== "")
readonly property int defaultMaxLineCount: 3
maxLineCount: defaultMaxLineCount
text: webPageData.description ? Emoji.emojify(Functions.enhanceMessageText(webPageData.description), font.pixelSize) : ""
font.pixelSize: webPagePreviewColumn.largerFontSize ? Theme.fontSizeSmall : Theme.fontSizeExtraSmall
truncationMode: TruncationMode.Fade
wrapMode: Text.Wrap
maximumLineCount: 3
textFormat: Text.StyledText
visible: (text !== "")
linkColor: Theme.highlightColor
onLinkActivated: {
Functions.handleLink(link);
}
function toggleMaxLineCount() {
maxLineCount = maxLineCount > 0 ? 0 : defaultMaxLineCount
}
}
Item {
@ -124,35 +133,38 @@ Column {
fillMode: Image.PreserveAspectCrop
autoTransform: true
asynchronous: true
source: picture.isDownloadingCompleted ? picture.path : ""
visible: opacity > 0
visible: hasImage && status === Image.Ready
opacity: hasImage && status === Image.Ready ? 1 : 0
layer.enabled: webPagePreviewColumn.highlighted
layer.effect: PressEffect { source: singleImage }
Behavior on opacity { FadeAnimation {} }
Behavior on opacity { NumberAnimation {} }
MouseArea {
anchors.fill: parent
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 {
id: backgroundImage
visible: hasImage && singleImage.status !== Image.Ready
layer.enabled: webPagePreviewColumn.highlighted
layer.effect: PressEffect { source: backgroundImage }
layer.effect: PressEffect { source: singleImage }
}
}
Label {
id: noPreviewAvailableText
width: parent.width
text: qsTr("Preview not supported for this link...")
font.pixelSize: webPagePreviewColumn.largerFontSize ? Theme.fontSizeExtraSmall : Theme.fontSizeTiny
font.italic: true
color: Theme.secondaryColor
truncationMode: TruncationMode.Fade
wrapMode: Text.Wrap
maximumLineCount: 1
textFormat: Text.StyledText
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.
@ -16,7 +16,6 @@
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
@ -28,7 +27,6 @@ Column {
property string emptyPlaceholderText
property string text
property bool multiLine
property bool headerLeftAligned
property bool isEditing
property Item editItem: multiLine ? editAreaTextArea : editAreaTextField
@ -43,7 +41,6 @@ Column {
id: editAreaHeader
height: parent.visible && text !== "" ? Theme.itemSizeExtraSmall : 0
x: 0
horizontalAlignment: headerLeftAligned ? Text.AlignLeft : Text.AlignRight
}
Row {
id: editAreaTextRow
@ -53,24 +50,20 @@ Column {
id: editAreaTextArea
visible: editAreaColumn.isEditing && editAreaColumn.multiLine
width: parent.width - editAreaButton.width
textLeftMargin: 0
anchors.verticalCenter: parent.verticalCenter
font.pixelSize: Theme.fontSizeMedium
}
TextField {
id: editAreaTextField
visible: editAreaColumn.isEditing && !editAreaColumn.multiLine
width: parent.width - editAreaButton.width
anchors.verticalCenter: parent.verticalCenter
textLeftMargin: 0
EnterKey.onClicked: {
editAreaColumn.isEditing = false;
editAreaColumn.saveButtonClicked(editAreaColumn.editItem.text);
}
EnterKey.iconSource: editAreaButton.icon.source
font.pixelSize: Theme.fontSizeMedium
}
InformationTextItem {
ChatInformationTextItem {
id: editAreaTextItem
visible: !editAreaColumn.isEditing
anchors.verticalCenter: parent.verticalCenter

View file

@ -98,7 +98,7 @@ SilicaFlickable {
if(groupFullInfo.members && groupFullInfo.members.length > 0) {
for(var memberIndex in groupFullInfo.members) {
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.bot_info = memberData.bot_info || {};
membersList.append(memberData);
@ -187,14 +187,6 @@ SilicaFlickable {
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: {
@ -240,7 +232,7 @@ SilicaFlickable {
MenuItem {
visible: chatInformationPage.isPrivateChat
onClicked: {
tdLibWrapper.createNewSecretChat(chatInformationPage.chatPartnerGroupId, "openDirectly");
tdLibWrapper.createNewSecretChat(chatInformationPage.chatPartnerGroupId);
}
text: qsTr("New Secret Chat")
}
@ -264,10 +256,6 @@ SilicaFlickable {
}
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) {
return min + (max-min)*factor
@ -283,25 +271,23 @@ SilicaFlickable {
replacementStringHint: headerItem.title
width: parent.width
height: width
radius: imageContainer.thumbnailRadius
radius: imageContainer.minDimension / 2
opacity: profilePictureLoader.status !== Loader.Ready || profilePictureLoader.item.opacity < 1 ? 1.0 : 0.0
optimizeImageSize: false
}
Loader {
id: profilePictureLoader
active: imageContainer.hasImage
asynchronous: true
anchors.fill: chatPictureThumbnail
source: ( chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat)
? "../ProfilePictureList.qml"
? "ChatInformationProfilePictureList.qml"
: "ChatInformationProfilePicture.qml"
}
}
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")
description: ((chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) && chatInformationPage.privateChatUserInformation.usernames.editable_username)
? ("@"+chatInformationPage.privateChatUserInformation.usernames.editable_username) : ""
description: (chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) ? ("@"+(chatInformationPage.privateChatUserInformation.username || chatInformationPage.chatPartnerGroupId)) : ""
}
SilicaFlickable {
@ -364,28 +350,7 @@ SilicaFlickable {
height: imageContainer.hasImage ? imageContainer.maxDimension : 0
}
Label {
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 {
ChatInformationEditArea {
visible: canEdit
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")
@ -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"))
emptyPlaceholderText: qsTr("There is no information text available, yet.")
headerText: qsTr("Info", "group or user infotext header")
@ -426,7 +391,7 @@ SilicaFlickable {
}
}
InformationTextItem {
ChatInformationTextItem {
headerText: qsTr("Phone Number", "user phone number header")
text: ((chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) && chatInformationPage.privateChatUserInformation.phone_number ? "+"+chatInformationPage.privateChatUserInformation.phone_number : "") || ""
isLinkedLabel: true
@ -443,7 +408,7 @@ SilicaFlickable {
Row {
width: parent.width
visible: !!inviteLinkItem.text
InformationTextItem {
ChatInformationTextItem {
id: inviteLinkItem
text: !(chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) ? chatInformationPage.groupFullInformation.invite_link : ""
width: parent.width - inviteLinkButton.width

View file

@ -22,8 +22,8 @@ import Sailfish.Silica 1.0
import "../"
Item {
visible: parent.thumbnailVisible && chatPictureDetail.imageStatus === Image.Ready
property bool isActive: parent.thumbnailActive
visible: imageContainer.tweenFactor > 0.8 && chatPictureDetail.imageStatus === Image.Ready
property bool isActive: imageContainer.tweenFactor === 1.0
opacity: isActive ? 1.0 : 0.0
Behavior on opacity { FadeAnimation {} }
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.
@ -18,25 +18,25 @@
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import "../"
Item {
id: profilePictureListItem
visible: imageContainer.thumbnailVisible && bigProfilePictureList.count > 0
property bool isActive: imageContainer.thumbnailActive
readonly property int currentPictureIndex: bigProfilePictureList.currentIndex
visible: imageContainer.tweenFactor > 0.8 && bigProfilePictureList.count > 0
property bool isActive: imageContainer.tweenFactor === 1.0
opacity: isActive ? 1.0 : 0.0
Behavior on opacity { FadeAnimation {} }
SlideshowView {
id: bigProfilePictureList
property bool isActive: imageContainer.tweenFactor === 1.0
width: parent.width
height: parent.height
clip: true
itemWidth: width
itemHeight: height
interactive: parent.isActive
model: imageContainer.thumbnailModel
model: chatInformationPage.chatPartnerProfilePhotos
delegate: Item {
width: bigProfilePictureList.itemWidth
height: bigProfilePictureList.itemHeight
@ -44,13 +44,13 @@ Item {
id: chatPictureDetail
photoData: modelData.sizes[modelData.sizes.length - 1].photo
replacementStringHint: ""
radius: imageContainer.thumbnailRadius
radius: chatPictureThumbnail.radius
anchors.fill: parent
}
MouseArea {
anchors.fill: parent
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 {
visible: bigProfilePictureList.count > 1
width: parent.width - Theme.paddingSmall
width: parent.width
anchors {
bottomMargin: Theme.paddingSmall
bottom: parent.bottom
}
horizontalAlignment: Text.AlignHCenter
property var baseString: new Array(bigProfilePictureList.count+1).join(" ○ ")
text: (baseString.substring(0,bigProfilePictureList.currentIndex*3) + " ● " + baseString.substring((bigProfilePictureList.currentIndex+1)*3)).trim()
font.pixelSize: Theme.fontSizeTiny
text: baseString.substring(0,bigProfilePictureList.currentIndex*3) + " ● " + baseString.substring((bigProfilePictureList.currentIndex+1)*3)
color: Theme.primaryColor
style: Text.Raised
styleColor: Theme.highlightDimmerColor
}
}

View file

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

View file

@ -72,14 +72,14 @@ ChatInformationTabItemBase {
}
delegate: PhotoTextsListItem {
pictureThumbnail {
photoData: user.profile_photo ? user.profile_photo.small : null
photoData: (typeof user.profile_photo !== "undefined") ? user.profile_photo.small : ""
}
width: parent.width
// chat title
primaryText.text: Emoji.emojify(Functions.getUserName(user), primaryText.font.pixelSize)
// 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 {
horizontalAlignment: Text.AlignRight
property string statusText: Functions.getChatMemberStatusText(model.status["@type"])
@ -92,7 +92,7 @@ ChatInformationTabItemBase {
}
onClicked: {
tdLibWrapper.createPrivateChat(member_id.user_id, "openDirectly");
tdLibWrapper.createPrivateChat(user_id);
}
}
footer: Component {
@ -154,6 +154,15 @@ ChatInformationTabItemBase {
pageStack.pop(pageStack.find( function(page){ return(page._depth === 0)} ), PageStackAction.Immediate);
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
property int fetchLimit: 50
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
tdLibWrapper.getSupergroupMembers(chatInformationPage.chatPartnerGroupId, fetchLimit, pageContent.membersList.count);
fetchLimit = 200
@ -179,10 +188,7 @@ ChatInformationTabItemBase {
if(members && members.length > 0 && chatInformationPage.groupInformation.member_count > membersView.count) {
for(var memberIndex in members) {
var memberData = members[memberIndex];
var userInfo = tdLibWrapper.getUserInformation(memberData.member_id.user_id) || {user:{}, bot_info:{}};
if (!userInfo.username && userInfo.usernames && userInfo.usernames.active_usernames) {
userInfo.username = userInfo.usernames.active_usernames[0]
}
var userInfo = tdLibWrapper.getUserInformation(memberData.user_id) || {user:{}, bot_info:{}};
memberData.user = userInfo;
memberData.bot_info = memberData.bot_info || {};
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.
@ -16,12 +16,11 @@
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/twemoji.js" as Emoji
import "../../js/functions.js" as Functions
Column {
id: textItem
@ -48,7 +47,7 @@ Column {
id: labelComponent
Label {
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
font.pixelSize: Theme.fontSizeMedium
font.pixelSize: Theme.fontSizeSmall
textFormat: Text.StyledText
color: Theme.primaryColor
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 {
id: appNotification
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