Merge branch 'dev' into 'main'
Merge version 0.7.3 See merge request mx-moment/moment!6
34
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
@ -1,34 +0,0 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: 'Report an unexpected behavior '
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Description
|
||||
|
||||
Describe your issue in details, provide error logs or screenshots if possible.
|
||||
|
||||
### Your environment
|
||||
|
||||
- OS or distribution (e.g. Arch Linux, macOS 10.15, Windows 7...)
|
||||
- Architecture (e.g. x86 64bit)
|
||||
- For Linux users: your desktop environment or window manager (e.g. GNOME 3.34 Wayland, i3 4.17, etc)
|
||||
- How did you install Mirage? (e.g. manual build, distribution repository, AppImage, Flatpak...)
|
||||
- For manual installations: your Qt version
|
||||
- For manual installations: your Python version
|
||||
|
||||
### Steps to reproduce
|
||||
|
||||
1. Do this...
|
||||
2. Do that...
|
||||
|
||||
### Expected behavior
|
||||
|
||||
Tell us what should happen
|
||||
|
||||
### Actual behavior
|
||||
|
||||
Tell us what happens instead
|
10
.github/ISSUE_TEMPLATE/feature_request.md
vendored
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for the application or project
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
10
.github/ISSUE_TEMPLATE/question.md
vendored
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
name: Question
|
||||
about: Ask a question about the application or project
|
||||
title: ''
|
||||
labels: question
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
2
.gitignore
vendored
|
@ -16,6 +16,8 @@ dist
|
|||
Makefile
|
||||
mirage
|
||||
mirage.pro.user
|
||||
moment
|
||||
moment.pro.user
|
||||
*.AppImage
|
||||
|
||||
tags
|
||||
|
|
17
README.md
|
@ -1,5 +1,4 @@
|
|||
# Moment
|
||||
https://img.shields.io/gitlab/v/release/mx-moment/moment
|
||||
[![Latest release](https://img.shields.io/gitlab/v/release/mx-moment/moment)](https://gitlab.com/mx-moment/moment/-/releases)
|
||||
[![Built with matrix-nio](https://img.shields.io/badge/built%20with-matrix--nio-brightgreen)](https://github.com/poljar/matrix-nio)
|
||||
[![#moment-client:matrix.org](https://img.shields.io/matrix/moment-client:matrix.org?color=blueviolet)](https://matrix.to/#/#moment-client:matrix.org)
|
||||
|
@ -20,7 +19,7 @@ Written in Qt/QML and Python, **currently in alpha**.
|
|||
Moment is based on [Mirage](https://github.com/mirukana/mirage),
|
||||
see differences [here](docs/MIRAGEDIFF.md).
|
||||
|
||||
![Chat screenshot](docs/screenshots/01-chat.png?raw=true)
|
||||
![Chat screenshot](docs/screenshots/m01-chat.png?raw=true)
|
||||
|
||||
## Currently Implemented Features
|
||||
|
||||
|
@ -96,10 +95,10 @@ see differences [here](docs/MIRAGEDIFF.md).
|
|||
|
||||
## Screenshots
|
||||
|
||||
![Sign-in](docs/screenshots/02-sign-in.png)
|
||||
![Account settings](docs/screenshots/03-account-settings.png)
|
||||
![Room creation](docs/screenshots/04-create-room.png)
|
||||
![Chat](docs/screenshots/01-chat.png?raw=true)
|
||||
![Main pane in small window](docs/screenshots/05-main-pane-small.png)
|
||||
![Chat in small window](docs/screenshots/06-chat-small.png)
|
||||
![Room pane in small window](docs/screenshots/07-room-pane-small.png)
|
||||
![Sign-in](docs/screenshots/m02-sign-in.png)
|
||||
![Account settings](docs/screenshots/m03-account-settings.png)
|
||||
![Room creation](docs/screenshots/m04-create-room.png)
|
||||
![Chat](docs/screenshots/m01-chat.png?raw=true)
|
||||
![Main pane in small window](docs/screenshots/m05-main-pane-small.png)
|
||||
![Chat in small window](docs/screenshots/m06-chat-small.png)
|
||||
![Room pane in small window](docs/screenshots/m07-room-pane-small.png)
|
||||
|
|
|
@ -6,6 +6,7 @@ The format is based on
|
|||
and this project adheres to
|
||||
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
- [0.7.3 (2022-01-24)](#073-2022-01-24)
|
||||
- [0.7.2 (2021-07-26)](#072-2021-07-26)
|
||||
- [0.7.1 (2021-03-04)](#071-2021-03-04)
|
||||
- [0.7.0 (2021-02-28)](#070-2021-02-28)
|
||||
|
@ -23,6 +24,44 @@ and this project adheres to
|
|||
- [0.4.0 (2020-03-21)](#040-2020-03-21)
|
||||
|
||||
|
||||
## 0.7.3 (2022-01-24)
|
||||
|
||||
### Added
|
||||
|
||||
- [Keybindings page](KEYBINDINGS.md)
|
||||
|
||||
- When first starting Moment, offer to migrate config
|
||||
|
||||
- Foliage theme
|
||||
|
||||
### Changed
|
||||
|
||||
- Renamed Mirage to Moment
|
||||
|
||||
- Default config, cache and data directories
|
||||
|
||||
- Default keybinds:
|
||||
- quit is now Ctrl+Q
|
||||
- reply is now Ctrl+R
|
||||
- remove is now Ctrl+Shift+R
|
||||
- "focus filter" is now Ctrl+K
|
||||
- "previous message" is now Ctrl+I
|
||||
|
||||
- In-app links lead to
|
||||
[the Moment repository](https://gitlab.com/mx-moment/moment)
|
||||
|
||||
- Default theme is now Foliage.qpl
|
||||
|
||||
### Removed
|
||||
|
||||
- Appimage: remove Appimage installation method
|
||||
|
||||
### Fixed
|
||||
|
||||
- Compatibility with Python 3.10
|
||||
|
||||
- Minor UI fixes
|
||||
|
||||
## 0.7.2 (2021-07-26)
|
||||
|
||||
### Added
|
||||
|
|
|
@ -42,7 +42,7 @@ By sending your changes, you agree to license them under the LGPL 3.0 or later.
|
|||
|
||||
### Procedure
|
||||
|
||||
Start by forking the main repository from GitHub, then
|
||||
Start by forking the main repository from GitLab, then
|
||||
clone your fork and switch to a new branch based on `dev`, in which
|
||||
you will make your changes:
|
||||
|
||||
|
@ -62,7 +62,7 @@ You will then be able to make a pull request by going
|
|||
to the [main repo](https://gitlab.com/mx-moment/moment).
|
||||
|
||||
Once your pull request is merged, you can update `dev`, and delete your
|
||||
GitHub and local branch:
|
||||
GitLab and local branch:
|
||||
|
||||
```sh
|
||||
git fetch upstream
|
||||
|
|
|
@ -5,7 +5,6 @@ but compiling on Windows and macOS should be possible with the right tools.
|
|||
|
||||
- [Packages](#packages)
|
||||
- [Linux](#linux)
|
||||
- [AppImage](#appimage)
|
||||
- [Flatpak](#flatpak)
|
||||
- [Alpine Linux / postmarketOS](#alpine-linux--postmarketOS)
|
||||
- [Arch Linux](#arch-linux)
|
||||
|
@ -37,22 +36,9 @@ but compiling on Windows and macOS should be possible with the right tools.
|
|||
|
||||
For developement, or if none of the package options are satisfying,
|
||||
see [manual installation](#manual-installation).
|
||||
Packages other than the AppImage and Flatpak are not maintained by the Mirage
|
||||
Packages other than the Flatpak are not maintained by the Mirage
|
||||
authors, and thus might be outdated.
|
||||
|
||||
#### AppImage (Leftover instructions from Mirage; not supported for Moment)
|
||||
|
||||
For **x86 64bit glibc-based systems**, Mirage is available as an AppImage
|
||||
on the [release page](https://github.com/mirukana/mirage/releases).
|
||||
|
||||
AppImages are single executable files that contain the app and all
|
||||
its dependencies.
|
||||
Mirage images are built in Ubuntu 16.04, and should therefore run on any distro
|
||||
released in April 2016 or later.
|
||||
|
||||
[How to start AppImages](https://docs.appimage.org/introduction/quickstart.html#how-to-run-an-appimage)
|
||||
(TL;DR: `chmod +x Mirage-*.AppImage && ./Mirage-*.AppImage`)
|
||||
|
||||
#### Flatpak (Leftover instructions from Mirage; not supported for Moment)
|
||||
|
||||
Mirage is also available as a Flatpak.
|
||||
|
|
|
@ -6,114 +6,114 @@ Keybindings as defined in [the default configuration file](src/config/settings.p
|
|||
|
||||
Key | Function
|
||||
------ | ------
|
||||
<kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>C</kbd> | Toggle compact interface
|
||||
<kbd>Ctrl</kbd> + <kbd>+</kbd> | Zoom in
|
||||
<kbd>Ctrl</kbd> + <kbd>-</kbd> | Zoom out
|
||||
<kbd>Ctrl</kbd> + <kbd>=</kbd> | Reset zoom
|
||||
<kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>Left</kbd> <br> <kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>H</kbd> | Previous tab
|
||||
<kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>Right</kbd> <br> <kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>L</kbd> | Next tab
|
||||
<kbd>Ctrl</kbd> + <kbd>Tab</kbd> | Switch to the last opened page
|
||||
<kbd>Ctrl</kbd> + <kbd>H</kbd> | Earlier page in history (page back)
|
||||
<kbd>Ctrl</kbd> + <kbd>L</kbd> | Later page in history (page forward)
|
||||
<kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>H</kbd> | Toggle notifications, except highlights
|
||||
<kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>N</kbd> | Toggle notifications
|
||||
<kbd>Ctrl + Alt + C</kbd> | Toggle compact interface
|
||||
<kbd>Ctrl + +</kbd> | Zoom in
|
||||
<kbd>Ctrl + -</kbd> | Zoom out
|
||||
<kbd>Ctrl + =</kbd> | Reset zoom
|
||||
<kbd>Alt + Shift + Left</kbd> <br> <kbd>Alt + Shift + H</kbd> | Previous tab
|
||||
<kbd>Alt + Shift + Right</kbd> <br> <kbd>Alt + Shift + L</kbd> | Next tab
|
||||
<kbd>Ctrl + Tab</kbd> | Switch to the last opened page
|
||||
<kbd>Ctrl + H</kbd> | Earlier page in history (page back)
|
||||
<kbd>Ctrl + L</kbd> | Later page in history (page forward)
|
||||
<kbd>Ctrl + Alt + H</kbd> | Toggle notifications, except highlights
|
||||
<kbd>Ctrl + Alt + N</kbd> | Toggle notifications
|
||||
<kbd>F1</kbd> | QML developer console
|
||||
<kbd>Shift</kbd> + <kbd>F1</kbd> | Python debugger
|
||||
<kbd>Alt</kbd> + <kbd>F1</kbd> | Python remote debugger
|
||||
<kbd>Ctrl</kbd> + <kbd>Q</kbd> | Quit Moment *
|
||||
<kbd>Shift + F1</kbd> | Python debugger
|
||||
<kbd>Alt + F1</kbd> | Python remote debugger
|
||||
<kbd>Ctrl + Q</kbd> | Quit Moment *
|
||||
|
||||
## Scrolling bindings
|
||||
|
||||
Key | Function
|
||||
------ | ------
|
||||
<kbd>Alt</kbd> + <kbd>Up</kbd> <br> <kbd>Alt</kbd> + <kbd>K</kbd> | Scroll up
|
||||
<kbd>Alt</kbd> + <kbd>Down</kbd> <br> <kbd>Alt</kbd> + <kbd>J</kbd> | Scroll down
|
||||
<kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>Up</kbd> <br> <kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>K</kbd> <br> <kbd>PgUp</kbd> | Page up
|
||||
<kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>Down</kbd> <br> <kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>J</kbd> <br> <kbd>PgDown</kbd> | Page down
|
||||
<kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>Up</kbd> <br> <kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>K</kbd> <br> <kbd>Home</kbd> | Scroll to top
|
||||
<kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>Down</kbd> <br> <kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>J</kbd> <br> <kbd>End</kbd> | Scroll to bottom
|
||||
<kbd>Alt + Up</kbd> <br> <kbd>Alt + K</kbd> | Scroll up
|
||||
<kbd>Alt + Down</kbd> <br> <kbd>Alt + J</kbd> | Scroll down
|
||||
<kbd>Ctrl + Alt + Up</kbd> <br> <kbd>Ctrl + Alt + K</kbd> <br> <kbd>PgUp</kbd> | Page up
|
||||
<kbd>Ctrl + Alt + Down</kbd> <br> <kbd>Ctrl + Alt + J</kbd> <br> <kbd>PgDown</kbd> | Page down
|
||||
<kbd>Ctrl + Alt + Shift + Up</kbd> <br> <kbd>Ctrl + Alt + Shift + K</kbd> <br> <kbd>Home</kbd> | Scroll to top
|
||||
<kbd>Ctrl + Alt + Shift + Down</kbd> <br> <kbd>Ctrl + Alt + Shift + J</kbd> <br> <kbd>End</kbd> | Scroll to bottom
|
||||
|
||||
## Account bindings
|
||||
|
||||
Key | Function
|
||||
------ | ------
|
||||
<kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>A</kbd> | Add new account
|
||||
<kbd>Alt</kbd> + <kbd>O</kbd> | Collapse current account
|
||||
<kbd>Alt</kbd> + <kbd>A</kbd> | Current account settings
|
||||
<kbd>Alt</kbd> + <kbd>P</kbd> | Current account context menu
|
||||
<kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>U</kbd> <br> <kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>A</kbd> | Unavailable status
|
||||
<kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>I</kbd> | Invisible status
|
||||
<kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>O</kbd> | Offline status
|
||||
<kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>N</kbd> | Previous account
|
||||
<kbd>Alt</kbd> + <kbd>N</kbd> | Next account
|
||||
<kbd>Ctrl</kbd> + <kbd>1</kbd> | Switch to account 1
|
||||
<kbd>Ctrl</kbd> + <kbd>2</kbd> | Switch to account 2
|
||||
<kbd>Ctrl</kbd> + <kbd>3</kbd> | Switch to account 3
|
||||
<kbd>Ctrl</kbd> + <kbd>4</kbd> | Switch to account 4
|
||||
<kbd>Ctrl</kbd> + <kbd>5</kbd> | Switch to account 5
|
||||
<kbd>Ctrl</kbd> + <kbd>6</kbd> | Switch to account 6
|
||||
<kbd>Ctrl</kbd> + <kbd>7</kbd> | Switch to account 7
|
||||
<kbd>Ctrl</kbd> + <kbd>8</kbd> | Switch to account 8
|
||||
<kbd>Ctrl</kbd> + <kbd>9</kbd> | Switch to account 9
|
||||
<kbd>Ctrl</kbd> + <kbd>0</kbd> | Switch to account 10
|
||||
<kbd>Alt + Shift + A</kbd> | Add new account
|
||||
<kbd>Alt + O</kbd> | Collapse current account
|
||||
<kbd>Alt + A</kbd> | Current account settings
|
||||
<kbd>Alt + P</kbd> | Current account context menu
|
||||
<kbd>Ctrl + Alt + U</kbd> <br> <kbd>Ctrl + Alt + A</kbd> | Unavailable status
|
||||
<kbd>Ctrl + Alt + I</kbd> | Invisible status
|
||||
<kbd>Ctrl + Alt + O</kbd> | Offline status
|
||||
<kbd>Alt + Shift + N</kbd> | Previous account
|
||||
<kbd>Alt + N</kbd> | Next account
|
||||
<kbd>Ctrl + 1</kbd> | Switch to account 1
|
||||
<kbd>Ctrl + 2</kbd> | Switch to account 2
|
||||
<kbd>Ctrl + 3</kbd> | Switch to account 3
|
||||
<kbd>Ctrl + 4</kbd> | Switch to account 4
|
||||
<kbd>Ctrl + 5</kbd> | Switch to account 5
|
||||
<kbd>Ctrl + 6</kbd> | Switch to account 6
|
||||
<kbd>Ctrl + 7</kbd> | Switch to account 7
|
||||
<kbd>Ctrl + 8</kbd> | Switch to account 8
|
||||
<kbd>Ctrl + 9</kbd> | Switch to account 9
|
||||
<kbd>Ctrl + 0</kbd> | Switch to account 10
|
||||
|
||||
## Room bindings
|
||||
|
||||
Key | Function
|
||||
------ | ------
|
||||
<kbd>Alt</kbd> + <kbd>C</kbd> | Create a new room (start chat)
|
||||
<kbd>Alt</kbd> + <kbd>F</kbd> | Focus filter
|
||||
<kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>F</kbd> | Clear filter
|
||||
<kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>Up</kbd> <br> <kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>K</kbd> | Previous room
|
||||
<kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>Down</kbd> <br> <kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>J</kbd> | Next room
|
||||
<kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>U</kbd> | Previous unread
|
||||
<kbd>Alt</kbd> + <kbd>U</kbd> | Next unread
|
||||
<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>U</kbd> | Oldest unread
|
||||
<kbd>Ctrl</kbd> + <kbd>U</kbd> | Latest unread
|
||||
<kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>M</kbd> | Previous highlight
|
||||
<kbd>Alt</kbd> + <kbd>M</kbd> | Next highlight
|
||||
<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>M</kbd> | Oldest highlight
|
||||
<kbd>Ctrl</kbd> + <kbd>M</kbd> | Latest highlight
|
||||
<kbd>Alt</kbd> + <kbd>1</kbd> | Room number 1 in account
|
||||
<kbd>Alt</kbd> + <kbd>2</kbd> | Room number 2 in account
|
||||
<kbd>Alt</kbd> + <kbd>3</kbd> | Room number 3 in account
|
||||
<kbd>Alt</kbd> + <kbd>4</kbd> | Room number 4 in account
|
||||
<kbd>Alt</kbd> + <kbd>5</kbd> | Room number 5 in account
|
||||
<kbd>Alt</kbd> + <kbd>6</kbd> | Room number 6 in account
|
||||
<kbd>Alt</kbd> + <kbd>7</kbd> | Room number 7 in account
|
||||
<kbd>Alt</kbd> + <kbd>8</kbd> | Room number 8 in account
|
||||
<kbd>Alt</kbd> + <kbd>9</kbd> | Room number 9 in account
|
||||
<kbd>Alt</kbd> + <kbd>0</kbd> | Room number 10 in account
|
||||
<kbd>Alt + C</kbd> | Create a new room (start chat)
|
||||
<kbd>Alt + F</kbd> <br> <kbd>Ctrl + K</kbd> | Focus filter *
|
||||
<kbd>Alt + Shift + F</kbd> | Clear filter
|
||||
<kbd>Alt + Shift + Up</kbd> <br> <kbd>Alt + Shift + K</kbd> | Previous room
|
||||
<kbd>Alt + Shift + Down</kbd> <br> <kbd>Alt + Shift + J</kbd> | Next room
|
||||
<kbd>Alt + Shift + U</kbd> | Previous unread
|
||||
<kbd>Alt + U</kbd> | Next unread
|
||||
<kbd>Ctrl + Shift + U</kbd> | Oldest unread
|
||||
<kbd>Ctrl + U</kbd> | Latest unread
|
||||
<kbd>Alt + Shift + M</kbd> | Previous highlight
|
||||
<kbd>Alt + M</kbd> | Next highlight
|
||||
<kbd>Ctrl + Shift + M</kbd> | Oldest highlight
|
||||
<kbd>Ctrl + M</kbd> | Latest highlight
|
||||
<kbd>Alt + 1</kbd> | Room number 1 in account
|
||||
<kbd>Alt + 2</kbd> | Room number 2 in account
|
||||
<kbd>Alt + 3</kbd> | Room number 3 in account
|
||||
<kbd>Alt + 4</kbd> | Room number 4 in account
|
||||
<kbd>Alt + 5</kbd> | Room number 5 in account
|
||||
<kbd>Alt + 6</kbd> | Room number 6 in account
|
||||
<kbd>Alt + 7</kbd> | Room number 7 in account
|
||||
<kbd>Alt + 8</kbd> | Room number 8 in account
|
||||
<kbd>Alt + 9</kbd> | Room number 9 in account
|
||||
<kbd>Alt + 0</kbd> | Room number 10 in account
|
||||
(no binding) | Jump to specific room by ID
|
||||
|
||||
## Chat bindings
|
||||
|
||||
Key | Function
|
||||
------ | ------
|
||||
<kbd>Alt</kbd> + <kbd>R</kbd> | Focus room pane
|
||||
<kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>R</kbd> | Hide room pane
|
||||
<kbd>Alt</kbd> + <kbd>I</kbd> | Invite members
|
||||
<kbd>Alt</kbd> + <kbd>Escape</kbd> | Leave current chat
|
||||
<kbd>Alt</kbd> + <kbd>S</kbd> | Upload file
|
||||
<kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>S</kbd> | Send file at clipboard path
|
||||
<kbd>Alt + R</kbd> | Focus room pane
|
||||
<kbd>Ctrl + Alt + R</kbd> | Hide room pane
|
||||
<kbd>Alt + I</kbd> | Invite members
|
||||
<kbd>Alt + Escape</kbd> | Leave current chat
|
||||
<kbd>Alt + S</kbd> | Upload file
|
||||
<kbd>Alt + Shift + S</kbd> | Send file at clipboard path
|
||||
|
||||
## Message bindings
|
||||
|
||||
Key | Function
|
||||
------ | ------
|
||||
<kbd>Ctrl</kbd> + <kbd>Up</kbd> <br> <kbd>Ctrl</kbd> + <kbd>K</kbd> | Focus previous message
|
||||
<kbd>Ctrl</kbd> + <kbd>Down</kbd> <br> <kbd>Ctrl</kbd> + <kbd>J</kbd> | Focus next message
|
||||
<kbd>Ctrl</kbd> + <kbd>Space</kbd> | Select focused message
|
||||
<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>Space</kbd> | Select messages until here
|
||||
<kbd>Ctrl</kbd> + <kbd>D</kbd> | Unfocus or deselect
|
||||
<kbd>Ctrl</kbd> + <kbd>S</kbd> | Display seen tooltips
|
||||
<kbd>Ctrl</kbd> + <kbd>R</kbd> <br> <kbd>Alt</kbd> + <kbd>Del</kbd> | Remove message
|
||||
<kbd>Ctrl</kbd> + <kbd>Q</kbd> | Reply
|
||||
<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>D</kbd> | Debug message
|
||||
<kbd>Ctrl</kbd> + <kbd>O</kbd> | Open link/file in message
|
||||
<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>O</kbd> | Open link/file externally
|
||||
<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>C</kbd> | Copy downloaded file path
|
||||
<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>L</kbd> | Clear messages
|
||||
<kbd>Ctrl + Up</kbd> <br> <kbd>Ctrl + I</kbd> | Focus previous message *
|
||||
<kbd>Ctrl + Down</kbd> <br> <kbd>Ctrl + J</kbd> | Focus next message
|
||||
<kbd>Ctrl + Space</kbd> | Select focused message
|
||||
<kbd>Ctrl + Shift + Space</kbd> | Select messages until here
|
||||
<kbd>Ctrl + D</kbd> | Unfocus or deselect
|
||||
<kbd>Ctrl + S</kbd> | Display seen tooltips
|
||||
<kbd>Ctrl + Shift + R</kbd> <br> <kbd>Alt + Del</kbd> | Remove message *
|
||||
<kbd>Ctrl + R</kbd> | Reply *
|
||||
<kbd>Ctrl + Shift + D</kbd> | Debug message
|
||||
<kbd>Ctrl + O</kbd> | Open link/file in message
|
||||
<kbd>Ctrl + Shift + O</kbd> | Open link/file externally
|
||||
<kbd>Ctrl + Shift + C</kbd> | Copy downloaded file path
|
||||
<kbd>Ctrl + Shift + L</kbd> | Clear messages
|
||||
|
||||
## Image viewer bindings
|
||||
|
||||
|
@ -121,20 +121,20 @@ Key | Function
|
|||
------ | ------
|
||||
<kbd>X</kbd> <br> <kbd>Q</kbd> | Close image viewer
|
||||
<kbd>E</kbd> | Expand image viewer
|
||||
<kbd>F</kbd> <br> <kbd>F11</kbd> <br> <kbd>Alt</kbd> + <kbd>Return</kbd> <br> <kbd>Alt</kbd> + <kbd>Enter</kbd> | Fullscreen image viewer
|
||||
<kbd>H</kbd> <br> <kbd>Left</kbd> <br> <kbd>Alt</kbd> + <kbd>H</kbd> <br> <kbd>Alt</kbd> + <kbd>Left</kbd> | Pan image left
|
||||
<kbd>J</kbd> <br> <kbd>Down</kbd> <br> <kbd>Alt</kbd> + <kbd>J</kbd> <br> <kbd>Alt</kbd> + <kbd>Down</kbd> | Pan image down
|
||||
<kbd>K</kbd> <br> <kbd>Up</kbd> <br> <kbd>Alt</kbd> + <kbd>K</kbd> <br> <kbd>Alt</kbd> + <kbd>Up</kbd> | Pan image up
|
||||
<kbd>L</kbd> <br> <kbd>Right</kbd> <br> <kbd>Alt</kbd> + <kbd>L</kbd> <br> <kbd>Alt</kbd> + <kbd>Right</kbd> | Pan image right
|
||||
<kbd>Z</kbd> <br> <kbd>+</kbd> <br> <kbd>Ctrl</kbd> + <kbd>+</kbd> | Zoom in
|
||||
<kbd>Shift</kbd> + <kbd>Z</kbd> <br> <kbd>-</kbd> <br> <kbd>Ctrl</kbd> + <kbd>-</kbd> | Zoom out
|
||||
<kbd>Alt</kbd> + <kbd>Z</kbd> <br> <kbd>=</kbd> <br> <kbd>Ctrl</kbd> + <kbd>=</kbd> | Reset zoom
|
||||
<kbd>F</kbd> <br> <kbd>F11</kbd> <br> <kbd>Alt + Return</kbd> <br> <kbd>Alt + Enter</kbd> | Fullscreen image viewer
|
||||
<kbd>H</kbd> <br> <kbd>Left</kbd> <br> <kbd>Alt + H</kbd> <br> <kbd>Alt + Left</kbd> | Pan image left
|
||||
<kbd>J</kbd> <br> <kbd>Down</kbd> <br> <kbd>Alt + J</kbd> <br> <kbd>Alt + Down</kbd> | Pan image down
|
||||
<kbd>K</kbd> <br> <kbd>Up</kbd> <br> <kbd>Alt + K</kbd> <br> <kbd>Alt + Up</kbd> | Pan image up
|
||||
<kbd>L</kbd> <br> <kbd>Right</kbd> <br> <kbd>Alt + L</kbd> <br> <kbd>Alt + Right</kbd> | Pan image right
|
||||
<kbd>Z</kbd> <br> <kbd>+</kbd> <br> <kbd>Ctrl + +</kbd> | Zoom in
|
||||
<kbd>Shift + Z</kbd> <br> <kbd>-</kbd> <br> <kbd>Ctrl + -</kbd> | Zoom out
|
||||
<kbd>Alt + Z</kbd> <br> <kbd>=</kbd> <br> <kbd>Ctrl + =</kbd> | Reset zoom
|
||||
<kbd>R</kbd> | Rotate image right
|
||||
<kbd>Shift</kbd> + <kbd>R</kbd> | Rotate image left
|
||||
<kbd>Alt</kbd> + <kbd>R</kbd> | Reset image rotation
|
||||
<kbd>Shift + R</kbd> | Rotate image left
|
||||
<kbd>Alt + R</kbd> | Reset image rotation
|
||||
<kbd>S</kbd> | Speed up gif
|
||||
<kbd>Shift</kbd> + <kbd>S</kbd> | Slow down gif
|
||||
<kbd>Alt</kbd> + <kbd>S</kbd> | Reset gif speed
|
||||
<kbd>Shift + S</kbd> | Slow down gif
|
||||
<kbd>Alt + S</kbd> | Reset gif speed
|
||||
<kbd>Space</kbd> | Pause gif
|
||||
|
||||
## Security tab bindings
|
||||
|
@ -142,8 +142,10 @@ Key | Function
|
|||
Key | Function
|
||||
------ | ------
|
||||
<kbd>Tab</kbd> | Navigate next
|
||||
<kbd>Shift</kbd> + <kbd>Tab</kbd> | Navigate previous
|
||||
<kbd>Shift + Tab</kbd> | Navigate previous
|
||||
<kbd>Space</kbd> | Toggle check
|
||||
<kbd>Menu</kbd> | Session context menu
|
||||
<kbd>Alt</kbd> + <kbd>R</kbd> <br> <kbd>F5</kbd> | Refresh session list
|
||||
<kbd>Alt</kbd> + <kbd>S</kbd> <br> <kbd>Delete</kbd> | Sign out session
|
||||
<kbd>Alt + R</kbd> <br> <kbd>F5</kbd> | Refresh session list
|
||||
<kbd>Alt + S</kbd> <br> <kbd>Delete</kbd> | Sign out session
|
||||
|
||||
*Binding different than in Mirage
|
||||
|
|
69
docs/MIRAGEDIFF.md
Normal file
|
@ -0,0 +1,69 @@
|
|||
# Differences between Moment and Mirage
|
||||
|
||||
## Maintenance
|
||||
|
||||
Due to access issues, it is unlikely
|
||||
<a href="https://github.com/mirukana/mirage">Mirage</a>
|
||||
will continue being maintained. You should check the
|
||||
<a href="https://github.com/mirukana/mirage/commits/master">
|
||||
date of the last commit</a> to make sure.
|
||||
|
||||
## UI
|
||||
|
||||
Moment adds a new default theme. If you would rather have the default
|
||||
Mirage theme instead, add this to `~/.config/moment/settings.py`:
|
||||
``` python
|
||||
class General:
|
||||
theme: str = "Midnight.qpl"
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
There are currently no differences in features,
|
||||
although Moment does have some bug fixes that Mirage does not.
|
||||
|
||||
## Configuration
|
||||
|
||||
Moment has a different configuration directory
|
||||
(you will get an option to migrate your Mirage
|
||||
config automatically on first startup).
|
||||
|
||||
Moment has different default keybindings:
|
||||
- <kbd>Ctrl + Q</kbd> is `Quit`
|
||||
- `Reply` is <kbd>Ctrl + R</kbd> instead of <kbd>Ctrl + Q</kbd>
|
||||
- `Remove` is <kbd>Ctrl + Shift + R</kbd> instead of <kbd>Ctrl + R</kbd>
|
||||
- <kbd>Ctrl + K</kbd> is `Focus filter`
|
||||
- `Focus previous message` is <kbd>Ctrl + I</kbd> instead of <kbd>Ctrl + K</kbd>
|
||||
|
||||
If you wish to have `Focus previous message` and `Focus next message`
|
||||
adjacent on <kbd>Ctrl + U</kbd> and <kbd>Ctrl + I</kbd>,
|
||||
we recommend swapping <kbd>Ctrl + U</kbd> and <kbd>Ctrl + J</kbd>
|
||||
by adding this to `~/.config/moment/settings.py`:
|
||||
``` python
|
||||
class Keys:
|
||||
|
||||
class Rooms:
|
||||
latest_unread = ["Ctrl+J"]
|
||||
|
||||
class Messages:
|
||||
next = ["Ctrl+Down", "Ctrl+U"]
|
||||
```
|
||||
|
||||
## Reverting to default Mirage bindings
|
||||
|
||||
If you wish to revert to default Mirage bindings,
|
||||
add this to `~/.config/moment/settings.py`:
|
||||
``` python
|
||||
class Keys:
|
||||
|
||||
quit = []
|
||||
|
||||
class Rooms:
|
||||
focus_filter = ["Alt+F"]
|
||||
latest_unread = ["Ctrl+J"]
|
||||
|
||||
class Messages:
|
||||
reply = ["Ctrl+Q"]
|
||||
remove = ["Ctrl+R"]
|
||||
previous = ["Ctrl+Up", "Ctrl+K"]
|
||||
```
|
|
@ -11,7 +11,7 @@ for example:
|
|||
Or for Flatpak users:
|
||||
|
||||
```sh
|
||||
cp mirage/src/themes/Midnight.qpl \
|
||||
cp mirage/src/themes/Foliage.qpl \
|
||||
~/.var/app/io.github.mirukana.mirage/data/mirage/themes/MyTheme.qpl
|
||||
```
|
||||
|
||||
|
|
BIN
docs/screenshots/m01-chat.png
Normal file
After Width: | Height: | Size: 359 KiB |
BIN
docs/screenshots/m02-sign-in.png
Normal file
After Width: | Height: | Size: 390 KiB |
BIN
docs/screenshots/m03-account-settings.png
Normal file
After Width: | Height: | Size: 388 KiB |
BIN
docs/screenshots/m04-create-room.png
Normal file
After Width: | Height: | Size: 374 KiB |
BIN
docs/screenshots/m05-main-pane-small.png
Normal file
After Width: | Height: | Size: 84 KiB |
BIN
docs/screenshots/m06-chat-small.png
Normal file
After Width: | Height: | Size: 94 KiB |
BIN
docs/screenshots/m07-room-pane-small.png
Normal file
After Width: | Height: | Size: 80 KiB |
|
@ -27,7 +27,7 @@ QRC_FILE = $$BUILD_DIR/resources.qrc
|
|||
RESOURCES += $$QRC_FILE
|
||||
HEADERS += $$glob_filenames(*.h) submodules/hsluv-c/src/hsluv.h
|
||||
SOURCES += $$glob_filenames(*.cpp) submodules/hsluv-c/src/hsluv.c
|
||||
TARGET = mirage
|
||||
TARGET = moment
|
||||
|
||||
unix:!macx {
|
||||
LIBS += -lX11 -lXss
|
||||
|
@ -61,12 +61,12 @@ no-x11 {
|
|||
executables.files = $$TARGET
|
||||
|
||||
shortcuts.path = $$PREFIX/share/applications
|
||||
shortcuts.files = packaging/mirage.desktop
|
||||
shortcuts.files = packaging/moment.desktop
|
||||
|
||||
icons256.path = $$PREFIX/share/icons/hicolor/256x256/apps
|
||||
icons256.files = packaging/mirage.png
|
||||
icons256.files = packaging/moment.png
|
||||
|
||||
examples.path = $$PREFIX/share/examples/mirage
|
||||
examples.path = $$PREFIX/share/examples/moment
|
||||
examples.files = src/config/settings.py
|
||||
|
||||
INSTALLS += executables shortcuts icons256 examples
|
||||
|
@ -101,7 +101,7 @@ for(file, $$list($$glob_filenames(*.py))) {
|
|||
}
|
||||
|
||||
QMAKE_CLEAN *= $$MOC_DIR $$OBJECTS_DIR $$RCC_DIR $$PYCACHE_DIRS $$QRC_FILE
|
||||
QMAKE_CLEAN *= $$BUILD_DIR $$TARGET Makefile mirage.pro.user .qmake.stash
|
||||
QMAKE_CLEAN *= $$BUILD_DIR $$TARGET Makefile moment.pro.user .qmake.stash
|
||||
QMAKE_CLEAN *= $$glob_filenames(*.pyc, *.qmlc, *.jsc, *.egg-info)
|
||||
QMAKE_CLEAN *= packaging/flatpak/flatpak-env
|
||||
QMAKE_CLEAN *= packaging/flatpak/flatpak-pip-generator
|
|
@ -1,16 +0,0 @@
|
|||
#!/usr/bin/env sh
|
||||
set -e
|
||||
|
||||
here="$(dirname "$(readlink -f "$0")")"
|
||||
|
||||
export RESTORE_LD_LIBRARY_PATH="$LD_LIBRARY_PATH"
|
||||
export RESTORE_PYTHONHOME="$PYTHONHOME"
|
||||
export RESTORE_PYTHONUSERBASE="$PYTHONUSERBASE"
|
||||
|
||||
export SSL_CERT_FILE="$here/usr/lib/python$PY_XY/site-packages/certifi/cacert.pem"
|
||||
export LD_LIBRARY_PATH="$here/usr/lib:$LD_LIBRARY_PATH"
|
||||
export PYTHONHOME="$here/usr"
|
||||
export PYTHONUSERBASE="$here/usr"
|
||||
|
||||
cd "$here"
|
||||
exec "$here/usr/bin/mirage" "$@"
|
|
@ -1,32 +0,0 @@
|
|||
# AppImage building
|
||||
|
||||
The image must be built on Ubuntu 16.04 Xenial, to ensure compatibility with
|
||||
older systems.
|
||||
|
||||
LXD can be used to setup a suitable container from any distro.
|
||||
|
||||
If not done already (all default settings are usually fine):
|
||||
|
||||
lxd init
|
||||
|
||||
Initialize a new container named `ubuntu`:
|
||||
|
||||
lxc launch images:ubuntu/xenial/amd64 ubuntu
|
||||
|
||||
Now, you can either clone the repo from inside the container...:
|
||||
|
||||
lxc exec ubuntu -- apt install -y git
|
||||
lxc exec ubuntu -- git pull https://github.com/mirukana/mirage
|
||||
|
||||
...or directly copy a repository from your local filesystem inside:
|
||||
|
||||
lxc exec ubuntu -- /bin/mkdir -p /root/mirage
|
||||
lxc file push -vr <path to repo root>/* ubuntu/root/mirage
|
||||
|
||||
Run the build script inside the container:
|
||||
|
||||
lxc exec ubuntu -- /root/mirage/packaging/appimage/build.sh
|
||||
|
||||
You can also start a shell inside (e.g. if something goes wrong):
|
||||
|
||||
lxc exec ubuntu -- /bin/bash
|
|
@ -1,252 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
|
||||
HERE="$(dirname "$(readlink -f "$0")")"
|
||||
MIRAGE_REPO_URL='https://github.com/mirukana/mirage'
|
||||
PY_XYZ=3.9.6
|
||||
PY_XY="$(cut -d . -f 1-2 <<< "$PY_XYZ")"
|
||||
|
||||
|
||||
check_distro() {
|
||||
if grep -q '^\s*Ubuntu\s*16.04' /etc/issue; then return; fi
|
||||
|
||||
echo "Not running on expected distribution or version, aborting!" >&2
|
||||
echo "See <repo root>/packaging/appimage/README.md for more info." >&2
|
||||
exit 99
|
||||
}
|
||||
|
||||
|
||||
parse_cli_arguments() {
|
||||
if [ "$1" = --skip-install-prerequisites ] || [ "$1" = -s ]; then
|
||||
skip_pre=true
|
||||
else
|
||||
skip_pre=false
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
setup_dns() {
|
||||
if ! grep -q 'dns-nameservers 9.9.9.9' /etc/network/interfaces; then
|
||||
sed -i '/iface eth0 inet dhcp/a dns-nameservers 9.9.9.9' \
|
||||
/etc/network/interfaces
|
||||
|
||||
invoke-rc.d networking restart
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
install_apt_packages() {
|
||||
apt install -y software-properties-common
|
||||
add-apt-repository -y ppa:beineri/opt-qt-5.12.9-xenial
|
||||
add-apt-repository -y ppa:beineri/opt-qt-5.12.9-xenial
|
||||
apt update -y
|
||||
|
||||
apt install -y \
|
||||
qt512base qt512declarative qt512graphicaleffects \
|
||||
qt512imageformats qt512quickcontrols2 qt512svg \
|
||||
zip git wget cmake ccache \
|
||||
build-essential mesa-common-dev libglu1-mesa-dev freeglut3-dev \
|
||||
libglfw3-dev libgles2-mesa-dev libssl-dev \
|
||||
python3-dev python3-setuptools python3-pip libgdbm-dev libc6-dev \
|
||||
libsqlite3-dev libffi-dev openssl libreadline-dev \
|
||||
libjpeg-turbo8-dev zlib1g-dev \
|
||||
libtiff5-dev liblcms2-dev libwebp-dev libopenjp2-7-dev \
|
||||
libx11-dev libxss-dev libasound2-dev \
|
||||
pkg-config libdbus-1-dev libglib2.0-dev \
|
||||
appstream-util desktop-file-utils # for appimage-lint.sh
|
||||
|
||||
/usr/sbin/update-ccache-symlinks
|
||||
}
|
||||
|
||||
|
||||
setup_env() {
|
||||
set +euo pipefail
|
||||
# shellcheck disable=SC1091
|
||||
source /opt/qt512/bin/qt512-env.sh
|
||||
set -euo pipefail
|
||||
|
||||
export PATH="/usr/lib/ccache:$PATH"
|
||||
export LD_LIBRARY_PATH="$HOME/.local/lib/python$PY_XY/site-packages/PIL/.libs/:$HOME/.local/lib/python$PY_XY/site-packages/.libs_cffi_backend/:/usr/lib/x86_64-linux-gnu/:/usr/lib:$LD_LIBRARY_PATH"
|
||||
export PREFIX=/usr
|
||||
|
||||
export CFLAGS="-march=x86-64 -O2 -pipe -fPIC"
|
||||
export CXXFLAGS="$CFLAGS"
|
||||
export MAKEFLAGS="-j$(($(nproc) + 1))"
|
||||
}
|
||||
|
||||
|
||||
install_python() {
|
||||
cd ~
|
||||
|
||||
if ! [ -d ~/.pyenv ]; then
|
||||
wget -O - https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash
|
||||
fi
|
||||
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
|
||||
set +euo pipefail
|
||||
eval "$(pyenv init --path)"
|
||||
set -euo pipefail
|
||||
|
||||
export PYTHON_CFLAGS="$CFLAGS"
|
||||
export PYTHON_CONFIGURE_OPTS='--enable-shared --enable-optimizations --with-lto'
|
||||
|
||||
pyenv update
|
||||
pyenv install --verbose --skip-existing $PY_XYZ
|
||||
pyenv global $PY_XYZ
|
||||
}
|
||||
|
||||
|
||||
install_olm() {
|
||||
cd ~
|
||||
|
||||
rm -rf olm-master.tar.gz olm-master
|
||||
wget 'https://gitlab.matrix.org/matrix-org/olm/-/archive/master/olm-master.tar.gz'
|
||||
tar xf olm-master.tar.gz
|
||||
|
||||
cd olm-master
|
||||
make clean
|
||||
cmake . -Bbuild
|
||||
cmake --build build
|
||||
make install
|
||||
}
|
||||
|
||||
|
||||
install_pyotherside() {
|
||||
cd ~
|
||||
|
||||
if ! [ -f 1.5.9.tar.gz ]; then
|
||||
wget 'https://github.com/thp/pyotherside/archive/1.5.9.tar.gz'
|
||||
fi
|
||||
|
||||
tar xf 1.5.9.tar.gz
|
||||
|
||||
cd pyotherside-1.5.9
|
||||
make clean
|
||||
find . -name Makefile -delete
|
||||
qmake
|
||||
make install
|
||||
}
|
||||
|
||||
|
||||
get_app_and_pip_dependencies() {
|
||||
cd ~
|
||||
|
||||
if ! [ -d mirage ]; then
|
||||
git clone --recursive "$MIRAGE_REPO_URL"
|
||||
fi
|
||||
|
||||
cd mirage
|
||||
if pip3 show Pillow; then pip3 uninstall Pillow --yes; fi
|
||||
pip3 install Pillow --no-binary :all:
|
||||
pip3 install --user -Ur requirements.txt
|
||||
pip3 install --user -U certifi
|
||||
}
|
||||
|
||||
|
||||
initialize_appdir() {
|
||||
cd ~/mirage
|
||||
rm -rf .qmake.stash Makefile build
|
||||
|
||||
qmake mirage.pro PREFIX=/usr
|
||||
make install INSTALL_ROOT=build/appdir
|
||||
}
|
||||
|
||||
|
||||
complete_appdir() {
|
||||
cd ~/mirage/build
|
||||
|
||||
cp -r ~/.pyenv/versions/$PY_XYZ/* appdir/usr
|
||||
cp -r "$HOME/.local/lib/python$PY_XY/site-packages/"* \
|
||||
"appdir/usr/lib/python$PY_XY/site-packages"
|
||||
|
||||
cd ~/mirage/build/appdir/usr/lib
|
||||
ln -s "python$PY_XY/site-packages/Pillow.libs/"* .
|
||||
cd ~/mirage/build
|
||||
|
||||
if ! [ -f ~/linuxdeployqt.AppImage ]; then
|
||||
wget 'https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage' \
|
||||
-O ~/linuxdeployqt.AppImage
|
||||
fi
|
||||
chmod +x ~/linuxdeployqt.AppImage
|
||||
|
||||
~/linuxdeployqt.AppImage appdir/usr/share/applications/mirage.desktop \
|
||||
-bundle-non-qt-libs -qmldir=../src/gui
|
||||
|
||||
mkdir -p appdir/usr/share/metainfo
|
||||
cp ~/mirage/packaging/mirage.appdata.xml appdir/usr/share/metainfo
|
||||
|
||||
cp /opt/qt512/qml/io/thp/pyotherside/qmldir \
|
||||
appdir/usr/qml/io/thp/pyotherside
|
||||
|
||||
# Remove useless heavy test data
|
||||
rm -rf "appdir/usr/lib/python$PY_XY/test"
|
||||
rm -rf "appdir/usr/lib/python$PY_XY/site-packages/Crypto/SelfTest/"
|
||||
|
||||
# Remove python cache files
|
||||
find appdir -name '*.pyc' -delete
|
||||
}
|
||||
|
||||
|
||||
fix_apprun_launcher() {
|
||||
cd ~/mirage/build/appdir
|
||||
rm -f AppRun # because it's a symlink
|
||||
sed "s/\\\$PY_XY/$PY_XY/" "$HERE/AppRun.sh" > AppRun
|
||||
chmod +x AppRun
|
||||
}
|
||||
|
||||
|
||||
generate_appimage() {
|
||||
cd ~/mirage/build
|
||||
|
||||
if ! [ -f ~/appimagetool.AppImage ]; then
|
||||
wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" \
|
||||
-O ~/appimagetool.AppImage
|
||||
fi
|
||||
|
||||
chmod +x ~/appimagetool.AppImage
|
||||
~/appimagetool.AppImage --no-appstream appdir
|
||||
}
|
||||
|
||||
|
||||
lint_appdir() {
|
||||
cd ~
|
||||
|
||||
cat << 'EOF' > /usr/local/bin/mimetype
|
||||
#!/usr/bin/env sh
|
||||
file --mime-type "$@" | tr -d ';'
|
||||
EOF
|
||||
chmod +x /usr/local/bin/mimetype
|
||||
|
||||
if ! [ -d pkg2appimage ]; then
|
||||
git clone https://github.com/AppImage/pkg2appimage
|
||||
fi
|
||||
chmod +x pkg2appimage/appdir-lint.sh
|
||||
|
||||
cd ~/mirage/build
|
||||
echo -e "\e[34m\nAppDir linting result:\n\e[0m"
|
||||
~/pkg2appimage/appdir-lint.sh appdir
|
||||
}
|
||||
|
||||
|
||||
check_distro
|
||||
parse_cli_arguments "$@"
|
||||
setup_dns
|
||||
|
||||
if [ "$skip_pre" = false ]; then install_apt_packages; fi
|
||||
|
||||
setup_env
|
||||
|
||||
if [ "$skip_pre" = false ]; then
|
||||
install_python
|
||||
install_olm
|
||||
install_pyotherside
|
||||
get_app_and_pip_dependencies
|
||||
fi
|
||||
|
||||
initialize_appdir
|
||||
complete_appdir
|
||||
fix_apprun_launcher
|
||||
generate_appimage
|
||||
lint_appdir
|
|
@ -19,4 +19,4 @@ async_generator >= 1.10, < 2; python_version < "3.7"
|
|||
dataclasses >= 0.6, < 0.7; python_version < "3.7"
|
||||
pyfastcopy >= 1.0.3, < 2; python_version < "3.8"
|
||||
|
||||
git+https://github.com/mirukana/matrix-nio#egg-matrix-nio[e2e]
|
||||
git+https://github.com/MRAAGH/matrix-nio#egg-matrix-nio[e2e]
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
# Copyright Mirage authors & contributors <https://github.com/mirukana/mirage>
|
||||
# and Moment contributors <https://gitlab.com/mx-moment/moment>
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
"""This package provides Mirage's backend side that can interact with the UI.
|
||||
"""This package provides Moment's backend side that can interact with the UI.
|
||||
|
||||
To learn more about how this package works, you might want to check the
|
||||
documentation in the following modules first:
|
||||
|
@ -12,7 +13,7 @@ documentation in the following modules first:
|
|||
- `nio_callbacks`
|
||||
"""
|
||||
|
||||
__app_name__ = "mirage"
|
||||
__display_name__ = "Mirage"
|
||||
__reverse_dns__ = "io.github.mirukana.mirage"
|
||||
__version__ = "0.7.2"
|
||||
__app_name__ = "moment"
|
||||
__display_name__ = "Moment"
|
||||
__reverse_dns__ = "xyz.mx-moment"
|
||||
__version__ = "0.7.3"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# Copyright Mirage authors & contributors <https://github.com/mirukana/mirage>
|
||||
# and Moment contributors <https://gitlab.com/mx-moment/moment>
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
import asyncio
|
||||
|
@ -104,7 +105,7 @@ class Backend:
|
|||
media_cache: A matrix media cache for downloaded files.
|
||||
|
||||
presences: A `{user_id: Presence}` dict for storing presence info about
|
||||
matrix users registered on Mirage.
|
||||
matrix users registered on Moment.
|
||||
|
||||
mxc_events: A dict storing media `Event` model items for any account
|
||||
that have the same mxc URI
|
||||
|
@ -137,7 +138,7 @@ class Backend:
|
|||
DefaultDict(asyncio.Lock) # {room_id: lock}
|
||||
|
||||
cache_dir = Path(
|
||||
os.environ.get("MIRAGE_CACHE_DIR") or self.appdirs.user_cache_dir,
|
||||
os.environ.get("MOMENT_CACHE_DIR") or self.appdirs.user_cache_dir,
|
||||
)
|
||||
|
||||
self.media_cache: MediaCache = MediaCache(self, cache_dir)
|
||||
|
@ -552,7 +553,13 @@ class Backend:
|
|||
)
|
||||
|
||||
api_list = "https://publiclist.anchel.nl/publiclist.json"
|
||||
try:
|
||||
response = await session.get(api_list)
|
||||
except:
|
||||
await session.close()
|
||||
print("Unable to fetch", api_list)
|
||||
return
|
||||
|
||||
coros = []
|
||||
|
||||
for server in (await response.json()):
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# Copyright Mirage authors & contributors <https://github.com/mirukana/mirage>
|
||||
# and Moment contributors <https://gitlab.com/mx-moment/moment>
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
"""Matrix media downloading, caching and retrieval."""
|
||||
|
@ -95,7 +96,7 @@ class Media:
|
|||
<base download folder>/<homeserver domain>/
|
||||
<file title>_<mxc id>.<file extension>`
|
||||
```
|
||||
e.g. `~/.cache/mirage/downloads/matrix.org/foo_Hm24ar11i768b0el.png`.
|
||||
e.g. `~/.cache/moment/downloads/matrix.org/foo_Hm24ar11i768b0el.png`.
|
||||
"""
|
||||
|
||||
parsed = urlparse(self.mxc)
|
||||
|
@ -304,7 +305,7 @@ class Thumbnail(Media):
|
|||
<file title>_<mxc id>.<file extension>`
|
||||
```
|
||||
e.g.
|
||||
`~/.cache/mirage/thumbnails/matrix.org/32x32/foo_Hm24ar11i768b0el.png`.
|
||||
`~/.cache/moment/thumbnails/matrix.org/32x32/foo_Hm24ar11i768b0el.png`.
|
||||
"""
|
||||
|
||||
size = self.normalize_size(self.server_size or self.wanted_size)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# Copyright Mirage authors & contributors <https://github.com/mirukana/mirage>
|
||||
# and Moment contributors <https://gitlab.com/mx-moment/moment>
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
"""User data and configuration files definitions."""
|
||||
|
@ -197,7 +198,7 @@ class ConfigFile(UserFile):
|
|||
@property
|
||||
def path(self) -> Path:
|
||||
return Path(
|
||||
os.environ.get("MIRAGE_CONFIG_DIR") or
|
||||
os.environ.get("MOMENT_CONFIG_DIR") or
|
||||
self.backend.appdirs.user_config_dir,
|
||||
) / self.filename
|
||||
|
||||
|
@ -209,7 +210,7 @@ class UserDataFile(UserFile):
|
|||
@property
|
||||
def path(self) -> Path:
|
||||
return Path(
|
||||
os.environ.get("MIRAGE_DATA_DIR") or
|
||||
os.environ.get("MOMENT_DATA_DIR") or
|
||||
self.backend.appdirs.user_data_dir,
|
||||
) / self.filename
|
||||
|
||||
|
@ -460,7 +461,7 @@ class NewTheme(UserDataFile, PCNFile):
|
|||
@property
|
||||
def path(self) -> Path:
|
||||
data_dir = Path(
|
||||
os.environ.get("MIRAGE_DATA_DIR") or
|
||||
os.environ.get("MOMENT_DATA_DIR") or
|
||||
self.backend.appdirs.user_data_dir,
|
||||
)
|
||||
return data_dir / "themes" / self.filename
|
||||
|
@ -515,17 +516,17 @@ class Theme(UserDataFile):
|
|||
@property
|
||||
def path(self) -> Path:
|
||||
data_dir = Path(
|
||||
os.environ.get("MIRAGE_DATA_DIR") or
|
||||
os.environ.get("MOMENT_DATA_DIR") or
|
||||
self.backend.appdirs.user_data_dir,
|
||||
)
|
||||
return data_dir / "themes" / self.filename
|
||||
|
||||
@property
|
||||
def default_data(self) -> str:
|
||||
if self.filename in ("Midnight.qpl", "Glass.qpl"):
|
||||
if self.filename in ("Foliage.qpl", "Midnight.qpl", "Glass.qpl"):
|
||||
path = f"src/themes/{self.filename}"
|
||||
else:
|
||||
path = "src/themes/Midnight.qpl"
|
||||
path = "src/themes/Foliage.qpl"
|
||||
|
||||
try:
|
||||
byte_content = pyotherside.qrc_get_file_contents(path)
|
||||
|
|
|
@ -26,13 +26,14 @@ class General:
|
|||
tooltips_delay: float = 0.7
|
||||
|
||||
# Application theme to use.
|
||||
# Can be the name of a built-in theme (Mirage.qpl or Glass.qpl), or
|
||||
# the name (including extension) of a file in the user theme folder, which
|
||||
# is "$XDG_DATA_HOME/mirage/themes" if that environment variable is set,
|
||||
# else "~/.local/share/mirage/themes".
|
||||
# Can be the name of a built-in theme (Foliage.qpl, Midnight.qpl or
|
||||
# Glass.qpl), or the name (including extension) of a file in the user theme
|
||||
# folder, which is "$XDG_DATA_HOME/moment/themes" if that environment
|
||||
# variable is set,
|
||||
# else "~/.local/share/moment/themes".
|
||||
# For Flatpak, it is
|
||||
# "~/.var/app/io.github.mirukana.mirage/data/mirage/themes".
|
||||
theme: str = "Midnight.qpl"
|
||||
theme: str = "Foliage.qpl"
|
||||
|
||||
# Interface scale multiplier, e.g. 0.5 makes everything half-size.
|
||||
zoom: float = 1.0
|
||||
|
@ -204,7 +205,7 @@ class Chat:
|
|||
auto_play_gif: bool = True
|
||||
|
||||
# When clicking on a file in the timeline, open it in an external
|
||||
# program instead of displaying it using Mirage's interface.
|
||||
# program instead of displaying it using Moment's interface.
|
||||
# On Linux, the xdg-open command is called.
|
||||
click_opens_externally: bool = False
|
||||
|
||||
|
@ -234,7 +235,7 @@ class Keys:
|
|||
# would need to be pressed.
|
||||
#
|
||||
# A list of default bindings can be found at:
|
||||
# https://github.com/mirukana/mirage/blob/master/docs/KEYBINDINGS.md
|
||||
# https://gitlab.com/mx-moment/moment/-/blob/main/docs/KEYBINDINGS.md
|
||||
|
||||
# Helper functions
|
||||
|
||||
|
@ -280,7 +281,7 @@ class Keys:
|
|||
qml_console = ["F1"]
|
||||
|
||||
# Start the Python backend debugger.
|
||||
# Mirage must be connected to a terminal for this to work.
|
||||
# Moment must be connected to a terminal for this to work.
|
||||
python_debugger = ["Shift+F1"]
|
||||
|
||||
# Start the Python backend debugger in remote access mode.
|
||||
|
@ -288,8 +289,8 @@ class Keys:
|
|||
# From any terminal, run `socat readline tcp:127.0.0.1:4444` to connect.
|
||||
python_remote_debugger = ["Alt+F1"]
|
||||
|
||||
# Quit Mirage
|
||||
quit = []
|
||||
# Quit Moment
|
||||
quit = ["Ctrl+Q"]
|
||||
|
||||
class Scrolling: # Keys.Scrolling
|
||||
# Pages and chat timeline scrolling
|
||||
|
@ -349,7 +350,7 @@ class Keys:
|
|||
# When focusing the field, use Tab/Shift+Tab or the arrows to navigate
|
||||
# the list, Enter to switch to focused account/room, Escape to cancel,
|
||||
# Menu to open the context menu.
|
||||
focus_filter = ["Alt+F"]
|
||||
focus_filter = ["Alt+F","Ctrl+K"]
|
||||
clear_filter = ["Alt+Shift+F"]
|
||||
|
||||
# Switch to the previous/next room in the list.
|
||||
|
@ -431,7 +432,7 @@ class Keys:
|
|||
# Focus the previous/next message in the timeline.
|
||||
# Keybinds defined below in this section affect the focused message.
|
||||
# The Menu key can open the context menu for a focused message.
|
||||
previous = ["Ctrl+Up", "Ctrl+K"]
|
||||
previous = ["Ctrl+Up", "Ctrl+I"]
|
||||
next = ["Ctrl+Down", "Ctrl+J"]
|
||||
|
||||
# Select the currently focused message, same as clicking on it.
|
||||
|
@ -461,12 +462,12 @@ class Keys:
|
|||
|
||||
# Remove the selected messages if any, else the focused message if any,
|
||||
# else the last message you posted.
|
||||
remove = ["Ctrl+R", "Alt+Del"]
|
||||
remove = ["Ctrl+Shift+R", "Alt+Del"]
|
||||
|
||||
# Reply/cancel reply to the focused message if any,
|
||||
# else the last message posted by someone else.
|
||||
# Replying can also be cancelled by pressing Escape.
|
||||
reply = ["Ctrl+Q"]
|
||||
reply = ["Ctrl+R"]
|
||||
|
||||
# Open the QML developer console for the focused message if any,
|
||||
# and display the event source.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Copyright Mirage authors & contributors <https://github.com/mirukana/mirage>
|
||||
// and Moment contributors <https://gitlab.com/mx-moment/moment>
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
pragma Singleton
|
||||
|
@ -18,9 +19,9 @@ QtObject {
|
|||
-h, --help Show this help and exit
|
||||
|
||||
Environment variables:
|
||||
MIRAGE_CONFIG_DIR Override the default configuration folder
|
||||
MIRAGE_DATA_DIR Override the default application data folder
|
||||
MIRAGE_CACHE_DIR Override the default cache and downloads folder
|
||||
MOMENT_CONFIG_DIR Override the default configuration folder
|
||||
MOMENT_DATA_DIR Override the default application data folder
|
||||
MOMENT_CACHE_DIR Override the default cache and downloads folder
|
||||
http_proxy Override the General.proxy setting, see settings.py
|
||||
`
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ Rectangle {
|
|||
icon.name: "documentation"
|
||||
text: qsTr("Online documentation")
|
||||
onTriggered: Qt.openUrlExternally(
|
||||
"https://github.com/mirukana/mirage/tree/master/docs"
|
||||
"https://gitlab.com/mx-moment/moment/-/tree/main/docs"
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ HListView {
|
|||
|
||||
Timer {
|
||||
id: autoSaveTimer
|
||||
interval: 30000
|
||||
interval: 3000
|
||||
onTriggered: root.save()
|
||||
}
|
||||
|
||||
|
|
|
@ -246,7 +246,7 @@ HBox {
|
|||
Timer {
|
||||
interval: 1000
|
||||
running:
|
||||
fetchServersFutureId === "" &&
|
||||
// fetchServersFutureId === "" &&
|
||||
ModelStore.get("homeservers").count === 0
|
||||
|
||||
repeat: true
|
||||
|
|
|
@ -11,7 +11,7 @@ HFlickableColumnPopup {
|
|||
property string path
|
||||
|
||||
readonly property string docs:
|
||||
"https://github.com/mirukana/mirage/tree/master/docs"
|
||||
"https://gitlab.com/mx-moment/moment/-/tree/main/docs"
|
||||
|
||||
page.footer: AutoDirectionLayout {
|
||||
CancelButton {
|
||||
|
|
|
@ -27,7 +27,7 @@ HColumnPopup {
|
|||
text: qsTr("Report")
|
||||
icon.name: "report-error"
|
||||
onClicked: Qt.openUrlExternally(
|
||||
"https://github.com/mirukana/mirage/blob/master/docs/" +
|
||||
"https://gitlab.com/mx-moment/moment/-/blob/main/docs/" +
|
||||
"CONTRIBUTING.md#issues"
|
||||
)
|
||||
}
|
||||
|
|
BIN
src/images/foliage.jpg
Normal file
After Width: | Height: | Size: 246 KiB |
250
src/main.cpp
|
@ -1,4 +1,5 @@
|
|||
// Copyright Mirage authors & contributors <https://github.com/mirukana/mirage>
|
||||
// and Moment contributors <https://gitlab.com/mx-moment/moment>
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
// This file creates the application, registers custom objects for QML
|
||||
|
@ -17,6 +18,7 @@
|
|||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QLockFile>
|
||||
#include <QMessageBox>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
|
@ -97,6 +99,236 @@ void onExitSignal(int signum) {
|
|||
}
|
||||
|
||||
|
||||
void migrateFile(QDir source, QDir destination, QString fname) {
|
||||
if (! QFile::copy(source.filePath(fname), destination.filePath(fname)))
|
||||
qWarning() << "Could not migrate" << fname;
|
||||
}
|
||||
|
||||
|
||||
void migrateShallowDirectory(
|
||||
QDir sourceParent, QDir destinationParent, QString dname
|
||||
) {
|
||||
if (sourceParent.exists(dname)) {
|
||||
if (! destinationParent.mkpath(dname)) {
|
||||
qWarning() << "Could not create directory"
|
||||
<< destinationParent.filePath(dname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
QDir source(sourceParent.filePath(dname));
|
||||
QDir destination(destinationParent.filePath(dname));
|
||||
QFileInfoList files = source.entryInfoList();
|
||||
for (QFileInfo file : files) {
|
||||
if(file.fileName() == "." || file.fileName() == "..")
|
||||
continue;
|
||||
migrateFile(source, destination, file.fileName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void offerMigrateFromMirage(
|
||||
QDir configDirMoment, QDir configDirMirage,
|
||||
QDir dataDirMoment, QDir dataDirMirage
|
||||
) {
|
||||
QMessageBox dialog;
|
||||
dialog.setText("Would you like Moment to re-use your logins, "
|
||||
"encryption keys, configuration and themes from Mirage?");
|
||||
dialog.setInformativeText(
|
||||
"Will copy "+configDirMirage.path()+" → "+configDirMoment.path()
|
||||
+"\nWill copy "+dataDirMirage.path()+" → "+dataDirMoment.path());
|
||||
dialog.addButton(QMessageBox::Yes);
|
||||
dialog.addButton(QMessageBox::No);
|
||||
dialog.addButton(QMessageBox::Cancel);
|
||||
int result = dialog.exec();
|
||||
if (result == QMessageBox::Yes) {
|
||||
qWarning("Migrating config and data from Mirage");
|
||||
if (! configDirMoment.mkpath(".")) {
|
||||
qFatal("Could not create config directory");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (! dataDirMoment.mkpath(".")) {
|
||||
qFatal("Could not create data directory");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
migrateFile(configDirMirage, configDirMoment, "settings.py");
|
||||
migrateFile(configDirMirage, configDirMoment, "settings.gui.json");
|
||||
migrateFile(configDirMirage, configDirMoment, "accounts.json");
|
||||
migrateFile(dataDirMirage, dataDirMoment, "history.json");
|
||||
migrateFile(dataDirMirage, dataDirMoment, "state.json");
|
||||
migrateShallowDirectory(dataDirMirage, dataDirMoment, "themes");
|
||||
migrateShallowDirectory(dataDirMirage, dataDirMoment, "encryption");
|
||||
} else if (result == QMessageBox::No) {
|
||||
// Nothing to do. Proceed with starting the app
|
||||
qWarning("Not migrating");
|
||||
return;
|
||||
} else {
|
||||
// Neither "Yes" nor "No" was chosen.
|
||||
// We can't know what the user wants. Just quit.
|
||||
qWarning("Quitting. You can decide about migration next time.");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool shouldMigrateFromMirage() {
|
||||
QString genericConfig = QStandardPaths::writableLocation(
|
||||
QStandardPaths::GenericConfigLocation);
|
||||
QString genericData = QStandardPaths::writableLocation(
|
||||
QStandardPaths::GenericDataLocation);
|
||||
|
||||
// Check whether Moment config already exists
|
||||
{
|
||||
QString customConfigDirMoment(
|
||||
qEnvironmentVariable("MOMENT_CONFIG_DIR")
|
||||
);
|
||||
if (! customConfigDirMoment.isEmpty()) {
|
||||
// MOMENT_CONFIG_DIR is set.
|
||||
// Moment would definitely use this as the config directory.
|
||||
if (QDir(customConfigDirMoment).exists())
|
||||
// But it already exists.
|
||||
// So this is not the first time Moment was started.
|
||||
return false;
|
||||
} else {
|
||||
// No MOMENT_CONFIG_DIR, so check the default config directory.
|
||||
if (QDir(genericConfig + "/moment").exists())
|
||||
// The default config folder exists.
|
||||
// So this is not the first time Moment was started.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether Moment data already exists
|
||||
{
|
||||
QString customDataDirMoment(qEnvironmentVariable("MOMENT_DATA_DIR"));
|
||||
if (! customDataDirMoment.isEmpty()) {
|
||||
// MOMENT_DATA_DIR is set.
|
||||
// Moment would definitely use this as the data directory.
|
||||
if (QDir(customDataDirMoment).exists())
|
||||
// But it already exists.
|
||||
// So this is not the first time Moment was started.
|
||||
return false;
|
||||
} else {
|
||||
// No MOMENT_DATA_DIR, so check the default data directory.
|
||||
if (QDir(genericData + "/moment").exists())
|
||||
// The default data folder exists.
|
||||
// So this is not the first time Moment was started.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether Mirage config exists
|
||||
{
|
||||
QString customConfigDirMirage(
|
||||
qEnvironmentVariable("MIRAGE_CONFIG_DIR")
|
||||
);
|
||||
if (! customConfigDirMirage.isEmpty()) {
|
||||
// MIRAGE_CONFIG_DIR is set.
|
||||
// Mirage would definitely use this as the config directory.
|
||||
if (! QDir(customConfigDirMirage).exists())
|
||||
// But this directory does not exist.
|
||||
// So there is nowhere to migrate from.
|
||||
return false;
|
||||
} else {
|
||||
// No MIRAGE_CONFIG_DIR, so check the default config directory.
|
||||
// Check /matrix-mirage (Debian) first, since it is more specific
|
||||
if (! QDir(genericConfig + "/matrix-mirage").exists())
|
||||
// Default Debian config folder does not exist,
|
||||
// so check whether the normal /mirage exists
|
||||
if (! QDir(genericConfig + "/mirage").exists())
|
||||
// No, neither /matrix-mirage nor /mirage exist.
|
||||
// So there is nowhere to migrate from.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// We found out that there is no Moment config dir nor Moment data dir,
|
||||
// but there is a Mirage config dir which can be migrated from.
|
||||
// We could also check for Mirage data dir but it doesn't really matter.
|
||||
// User should definitely be prompted for migration.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void tryMigrateFromMirage() {
|
||||
QString genericConfig = QStandardPaths::writableLocation(
|
||||
QStandardPaths::GenericConfigLocation);
|
||||
QString genericData = QStandardPaths::writableLocation(
|
||||
QStandardPaths::GenericDataLocation);
|
||||
|
||||
QDir configDirMoment, configDirMirage, dataDirMoment, dataDirMirage;
|
||||
|
||||
QString customConfigDirMoment(qEnvironmentVariable("MOMENT_CONFIG_DIR"));
|
||||
configDirMoment = QDir(customConfigDirMoment.isEmpty()
|
||||
? genericConfig + "/moment" : customConfigDirMoment);
|
||||
|
||||
QString customDataDirMoment(qEnvironmentVariable("MOMENT_DATA_DIR"));
|
||||
dataDirMoment = QDir(customDataDirMoment.isEmpty()
|
||||
? genericData + "/moment" : customDataDirMoment);
|
||||
|
||||
QString customConfigDirMirage(qEnvironmentVariable("MIRAGE_CONFIG_DIR"));
|
||||
if (! customConfigDirMirage.isEmpty()) {
|
||||
// MIRAGE_CONFIG_DIR is set.
|
||||
// Mirage would definitely use this as the config directory.
|
||||
// So this is where we should migrate from.
|
||||
configDirMirage = QDir(customConfigDirMirage);
|
||||
} else {
|
||||
// No MIRAGE_CONFIG_DIR.
|
||||
// Check if Mirage default config directory exists
|
||||
// Check /matrix-mirage (Debian) first
|
||||
QDir dirDeb(genericConfig + "/matrix-mirage");
|
||||
if (dirDeb.exists()) {
|
||||
// Default Debian config dir exists.
|
||||
// So this is where we should migrate from.
|
||||
configDirMirage = dirDeb;
|
||||
} else {
|
||||
// No /matrix-mirage found, so check /mirage
|
||||
QDir dir(genericConfig + "/mirage");
|
||||
if (dir.exists())
|
||||
// Default config dir exists.
|
||||
// So this is where we should migrate from.
|
||||
configDirMirage = dir;
|
||||
else
|
||||
// No Mirage config dir found.
|
||||
// Do not migrate.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QString customDataDirMirage(qEnvironmentVariable("MIRAGE_DATA_DIR"));
|
||||
if (! customDataDirMirage.isEmpty()) {
|
||||
// MIRAGE_DATA_DIR is set.
|
||||
// Mirage would definitely use this as the data directory.
|
||||
// So this is where we should migrate from.
|
||||
dataDirMirage = QDir(customDataDirMirage);
|
||||
} else {
|
||||
// No MIRAGE_DATA_DIR.
|
||||
// Check if Mirage default data directory exists
|
||||
// Check /matrix-mirage (Debian) first
|
||||
QDir dirDeb(genericData + "/matrix-mirage");
|
||||
if (dirDeb.exists()) {
|
||||
// Default Debian data dir exists.
|
||||
// So this is where we should migrate from.
|
||||
dataDirMirage = dirDeb;
|
||||
} else {
|
||||
// No /matrix-mirage found, so check /mirage
|
||||
QDir dir(genericData + "/mirage");
|
||||
if (dir.exists())
|
||||
// Default data dir exists.
|
||||
// So this is where we should migrate from.
|
||||
dataDirMirage = dir;
|
||||
else
|
||||
// No Mirage data dir found.
|
||||
// Do not migrate.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
offerMigrateFromMirage(
|
||||
configDirMoment, configDirMirage, dataDirMoment, dataDirMirage
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
bool setLockFile(QString configPath) {
|
||||
|
||||
QDir settingsFolder(configPath);
|
||||
|
@ -130,13 +362,19 @@ int main(int argc, char *argv[]) {
|
|||
qInstallMessageHandler(loggingHandler);
|
||||
|
||||
// Define some basic info about the app before creating the QApplication
|
||||
QApplication::setOrganizationName("mirage");
|
||||
QApplication::setApplicationName("mirage");
|
||||
QApplication::setApplicationDisplayName("Mirage");
|
||||
QApplication::setApplicationVersion("0.7.2");
|
||||
QApplication::setOrganizationName("moment");
|
||||
QApplication::setApplicationName("moment");
|
||||
QApplication::setApplicationDisplayName("Moment");
|
||||
QApplication::setApplicationVersion("0.7.3");
|
||||
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
|
||||
QString customConfigDir(qEnvironmentVariable("MIRAGE_CONFIG_DIR"));
|
||||
// app needs to be constructed before attempting to migrate
|
||||
// because migrate displays a popup dialog
|
||||
QApplication app(argc, argv);
|
||||
|
||||
if (shouldMigrateFromMirage()) tryMigrateFromMirage();
|
||||
|
||||
QString customConfigDir(qEnvironmentVariable("MOMENT_CONFIG_DIR"));
|
||||
QString settingsFolder(
|
||||
customConfigDir.isEmpty() ?
|
||||
QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation)
|
||||
|
@ -144,8 +382,8 @@ int main(int argc, char *argv[]) {
|
|||
customConfigDir
|
||||
);
|
||||
|
||||
// Attempt to create a lockfile in the settings folder
|
||||
if (! setLockFile(settingsFolder)) return EXIT_SUCCESS;
|
||||
QApplication app(argc, argv);
|
||||
|
||||
// Register handlers for quit signals, e.g. SIGINT/Ctrl-C in unix terminals
|
||||
signal(SIGINT, onExitSignal);
|
||||
|
|
561
src/themes/Foliage.qpl
Normal file
|
@ -0,0 +1,561 @@
|
|||
// vim: syntax=qml
|
||||
|
||||
// Base variables
|
||||
|
||||
real uiScale: window.settings.General.zoom
|
||||
|
||||
int minimumSupportedWidth: 240 * uiScale
|
||||
int minimumSupportedHeight: 120 * uiScale
|
||||
int contentIsWideAbove: 472 * uiScale
|
||||
|
||||
int baseElementsHeight: 36 * uiScale
|
||||
int spacing: 12 * uiScale
|
||||
int radius: 4 * uiScale
|
||||
int animationDuration: 100
|
||||
real loadingElementsOpacity: 0.8
|
||||
real disabledElementsOpacity: 0.3
|
||||
|
||||
|
||||
fontSize:
|
||||
int smaller: 13 * uiScale
|
||||
int small: 13 * uiScale
|
||||
int normal: 16 * uiScale
|
||||
int big: 20 * uiScale
|
||||
int bigger: 32 * uiScale
|
||||
int biggest: 48 * uiScale
|
||||
|
||||
fontFamily:
|
||||
string sans: "Roboto"
|
||||
string mono: "Hack"
|
||||
// Fonts are comma-separated.
|
||||
// For example, if you want colorful emoji, you could do:
|
||||
// string sans: "Roboto,Joypixels"
|
||||
// string mono: "Hack,Joypixels"
|
||||
|
||||
colors:
|
||||
int hue: 200
|
||||
|
||||
real intensity: 1.0
|
||||
real coloredTextIntensity: intensity * 71
|
||||
real dimColoredTextIntensity: intensity * 60
|
||||
|
||||
int saturation: 40
|
||||
int bgSaturation: saturation
|
||||
int coloredTextSaturation: saturation + 20
|
||||
int dimColoredTextSaturation: saturation
|
||||
|
||||
real opacity: 0.7
|
||||
|
||||
color weakBackground:
|
||||
hsluv(hue, bgSaturation, intensity * 2.5, opacity)
|
||||
color mediumBackground:
|
||||
hsluv(hue, bgSaturation, intensity * 7, opacity)
|
||||
color strongBackground:
|
||||
hsluv(hue, bgSaturation * 2, intensity, opacity)
|
||||
|
||||
color accentBackground: hsluv(hue, saturation, intensity * 40, 1)
|
||||
color accentElement: hsluv(hue, saturation * 1.5, intensity * 52, 1)
|
||||
color strongAccentElement: hsluv(hue, saturation * 1.5, intensity * 72, 1)
|
||||
|
||||
color positiveBackground:
|
||||
hsluv(155, saturation * 1.5, intensity * 65, 1)
|
||||
|
||||
color middleBackground:
|
||||
hsluv(60, saturation * 1.5, intensity * 65, 1)
|
||||
|
||||
color negativeBackground:
|
||||
hsluv(0, saturation * 1.5, intensity * 54, 1)
|
||||
|
||||
color alertBackground: negativeBackground
|
||||
|
||||
color brightText: hsluv(0, 0, intensity * 100)
|
||||
color text: hsluv(0, 0, intensity * 85)
|
||||
color halfDimText: hsluv(0, 0, intensity * 72)
|
||||
color dimText: hsluv(0, 0, intensity * 60)
|
||||
|
||||
color positiveText: hsluv(155, coloredTextSaturation, coloredTextIntensity)
|
||||
color warningText: hsluv(60, coloredTextSaturation, coloredTextIntensity)
|
||||
color errorText: hsluv(0, coloredTextSaturation, coloredTextIntensity)
|
||||
color accentText: hsluv(hue, coloredTextSaturation, coloredTextIntensity)
|
||||
|
||||
color link: hsluv(hue, coloredTextSaturation, coloredTextIntensity)
|
||||
color code: hsluv(hue + 10, coloredTextSaturation, coloredTextIntensity)
|
||||
|
||||
// Example of an animation, set running: true to enable
|
||||
NumberAnimation on hue
|
||||
running: false
|
||||
from: 0
|
||||
to: 360
|
||||
duration: 10000
|
||||
loops: Animation.Infinite
|
||||
|
||||
icons:
|
||||
string preferredPack: "thin"
|
||||
|
||||
// "transparent" to disable colorizing
|
||||
color colorize: hsluv(0, 0, colors.intensity * 90)
|
||||
color disabledColorize: "white"
|
||||
|
||||
int smallDimension: 16 * uiScale
|
||||
int dimension: 22 * uiScale
|
||||
|
||||
|
||||
// Generic UI controls
|
||||
|
||||
controls:
|
||||
scrollBar:
|
||||
int width: theme.spacing
|
||||
|
||||
color track: colors.strongBackground
|
||||
|
||||
color slider: colors.accentElement
|
||||
color hoveredSlider: colors.accentElement
|
||||
color pressedSlider: colors.strongAccentElement
|
||||
|
||||
int sliderPadding: 2
|
||||
int sliderRadius: theme.radius
|
||||
|
||||
box:
|
||||
int defaultWidth: minimumSupportedWidth
|
||||
color background: colors.mediumBackground
|
||||
int radius: theme.radius
|
||||
|
||||
popup:
|
||||
int defaultWidth: minimumSupportedWidth * 1.75
|
||||
color background: colors.mediumBackground
|
||||
color opaqueBackground: hsluv(
|
||||
colors.hue,
|
||||
colors.bgSaturation,
|
||||
colors.intensity * 7,
|
||||
1
|
||||
)
|
||||
color windowOverlay: hsluv(0, 0, 0, 0.7)
|
||||
|
||||
header:
|
||||
color background: colors.strongBackground
|
||||
|
||||
button:
|
||||
color background: colors.strongBackground
|
||||
color text: colors.text
|
||||
color focusedBorder: colors.accentElement
|
||||
int focusedBorderWidth: 2
|
||||
|
||||
color hoveredOverlay: hsluv(0, 0, 50, 0.2)
|
||||
color pressedOverlay: hsluv(0, 0, 50, 0.5)
|
||||
color checkedOverlay: colors.accentBackground
|
||||
|
||||
tab:
|
||||
color text: controls.button.text
|
||||
color background: controls.button.background
|
||||
color alternateBackground: hsluv(
|
||||
colors.hue,
|
||||
colors.bgSaturation * 1.25,
|
||||
colors.intensity * 4,
|
||||
Math.max(0.6, colors.opacity)
|
||||
)
|
||||
|
||||
color bottomLine: background
|
||||
color focusedBorder: colors.accentElement
|
||||
int focusedBorderWidth: 1
|
||||
|
||||
color hoveredOverlay: controls.button.hoveredOverlay
|
||||
color pressedOverlay: controls.button.pressedOverlay
|
||||
color checkedOverlay: controls.button.checkedOverlay
|
||||
|
||||
menu:
|
||||
color background: hsluv(
|
||||
colors.hue,
|
||||
colors.bgSaturation * 2,
|
||||
colors.intensity,
|
||||
Math.max(0.9, colors.opacity),
|
||||
)
|
||||
color border: "black"
|
||||
real borderWidth: 2
|
||||
|
||||
menuItem:
|
||||
color background: "transparent"
|
||||
color text: controls.button.text
|
||||
|
||||
color hoveredOverlay: controls.button.hoveredOverlay
|
||||
color pressedOverlay: controls.button.hoveredOverlay
|
||||
color checkedOverlay: controls.button.hoveredOverlay
|
||||
|
||||
checkBox:
|
||||
color checkIconColorize: colors.accentElement
|
||||
color boxBackground: controls.button.background
|
||||
int boxSize: 24 * uiScale
|
||||
|
||||
color boxBorder: "black"
|
||||
color boxHoveredBorder: colors.accentElement
|
||||
color boxPressedBorder: colors.strongAccentElement
|
||||
|
||||
color text: controls.button.text
|
||||
color subtitle: colors.dimText
|
||||
|
||||
listView:
|
||||
color highlight: hsluv(
|
||||
colors.hue,
|
||||
colors.bgSaturation * 2,
|
||||
colors.intensity * 1,
|
||||
colors.opacity / 1.5,
|
||||
)
|
||||
color highlightBorder: colors.strongAccentElement
|
||||
int highlightBorderThickness: 1
|
||||
|
||||
textField:
|
||||
color background: colors.strongBackground
|
||||
color focusedBackground: background
|
||||
|
||||
int borderWidth: 1
|
||||
color border: "transparent"
|
||||
color focusedBorder: colors.accentElement
|
||||
color errorBorder: colors.negativeBackground
|
||||
|
||||
color text: colors.text
|
||||
color focusedText: colors.text
|
||||
color placeholderText: colors.dimText
|
||||
|
||||
textArea:
|
||||
color background: colors.strongBackground
|
||||
|
||||
int borderWidth: 1
|
||||
color border: "transparent"
|
||||
color focusedBorder: colors.accentElement
|
||||
color errorBorder: colors.negativeBackground
|
||||
|
||||
color text: colors.text
|
||||
color placeholderText: controls.textField.placeholderText
|
||||
|
||||
toolTip:
|
||||
color background: colors.strongBackground
|
||||
color text: colors.text
|
||||
color border: "black"
|
||||
int borderWidth: 2
|
||||
|
||||
progressBar:
|
||||
int height: Math.max(2, spacing / 2)
|
||||
color background: colors.strongBackground
|
||||
color foreground: colors.accentElement
|
||||
color pausedForeground: colors.middleBackground
|
||||
color errorForeground: colors.negativeBackground
|
||||
|
||||
circleProgressBar:
|
||||
int thickness: Math.max(2, spacing / 2)
|
||||
color background: colors.strongBackground
|
||||
color foreground: colors.accentElement
|
||||
color errorForeground: colors.negativeBackground
|
||||
color text: colors.text
|
||||
real indeterminateSpan: 0.5 // 0-1
|
||||
|
||||
slider:
|
||||
int radius: 2
|
||||
int height: controls.progressBar.height
|
||||
color background: controls.progressBar.background
|
||||
color foreground: controls.progressBar.foreground
|
||||
|
||||
handle:
|
||||
int size: 20
|
||||
color inside: hsluv(0, 0, 90)
|
||||
color pressedInside: "white"
|
||||
color border: "black"
|
||||
color pressedBorder: colors.strongAccentElement
|
||||
|
||||
avatar:
|
||||
int size: baseElementsHeight
|
||||
int compactSize: baseElementsHeight / 2
|
||||
int radius: theme.radius
|
||||
|
||||
hoveredImage:
|
||||
int size: 192
|
||||
color background: hsluv(0, 0, 0, 0.4)
|
||||
|
||||
background:
|
||||
int saturation: colors.saturation
|
||||
int lightness: Math.min(50, colors.intensity * 25)
|
||||
real opacity: 1.0
|
||||
|
||||
letter:
|
||||
int saturation: colors.saturation + 20
|
||||
int lightness: colors.intensity * 60
|
||||
real opacity: 1.0
|
||||
|
||||
displayName:
|
||||
int saturation: colors.coloredTextSaturation
|
||||
int lightness: colors.coloredTextIntensity
|
||||
int dimSaturation: colors.dimColoredTextSaturation
|
||||
int dimLightness: colors.dimColoredTextIntensity
|
||||
|
||||
presence:
|
||||
color online: colors.positiveBackground
|
||||
color unavailable: colors.middleBackground
|
||||
color offline: hsluv(0, 0, 60, 1)
|
||||
color border: "black"
|
||||
int borderWidth: 2 * uiScale
|
||||
real opacity: 1.0
|
||||
real radius: 6.0 * uiScale
|
||||
|
||||
|
||||
// Specific interface parts
|
||||
|
||||
ui:
|
||||
// The background image can be an URL or local file path
|
||||
// (in the form file://<path>, e.g. file:///home/user/images/foo.png).
|
||||
// If not specified, the gradient will be shown instead.
|
||||
url image: "../../images/foliage.jpg"
|
||||
|
||||
point gradientStart: Qt.point(0, 0)
|
||||
point gradientEnd: Qt.point(window.width, window.height)
|
||||
|
||||
color gradientStartColor:
|
||||
hsluv(colors.hue, 100, colors.intensity * 8)
|
||||
color gradientEndColor:
|
||||
hsluv(colors.hue + 50, 30, colors.intensity * 22)
|
||||
|
||||
// To have a solid color instead,
|
||||
// set gradientStartColor and gradientEndColor to the same value, e.g.:
|
||||
// color gradientStartColor: hsluv(0, 0, 0, 0.5)
|
||||
// color gradientEndColor: hsluv(0, 0, 0, 0.5)
|
||||
|
||||
|
||||
mainPane:
|
||||
color background: "transparent"
|
||||
|
||||
topBar:
|
||||
color background: colors.strongBackground
|
||||
color nameVersionLabel: colors.text
|
||||
|
||||
accountBar:
|
||||
color background: colors.mediumBackground
|
||||
|
||||
account:
|
||||
color selectedBackground: colors.accentBackground
|
||||
real selectedBackgroundOpacity: 0.3
|
||||
color selectedBorder: colors.strongAccentElement
|
||||
int selectedBorderSize: 1
|
||||
|
||||
unreadIndicator:
|
||||
color background: colors.strongBackground
|
||||
color text: colors.accentText
|
||||
bool bold: false
|
||||
color border: Qt.darker(text, 2)
|
||||
int borderWidth: 1
|
||||
int radius: theme.radius / 2
|
||||
|
||||
color highlightBackground: colors.strongBackground
|
||||
color highlightText: colors.errorText
|
||||
bool highlightBold: false
|
||||
color highlightBorder: Qt.darker(highlightText, 2)
|
||||
int highlightBorderWidth: 1
|
||||
int highlightRadius: theme.radius / 2
|
||||
|
||||
listView:
|
||||
color background: colors.mediumBackground
|
||||
real offlineOpacity: 0.5
|
||||
|
||||
account:
|
||||
real collapsedOpacity: 0.3
|
||||
color background: "transparent"
|
||||
color name: colors.text
|
||||
|
||||
int avatarRadius: controls.avatar.radius
|
||||
int collapsedAvatarRadius: controls.avatar.size / 2
|
||||
|
||||
room:
|
||||
real leftRoomOpacity: 0.65
|
||||
|
||||
color background: "transparent"
|
||||
color name: colors.text
|
||||
color unreadName: colors.brightText
|
||||
color lastEventDate: colors.halfDimText
|
||||
|
||||
color subtitle: colors.dimText
|
||||
color subtitleQuote: chat.message.quote
|
||||
|
||||
int avatarRadius: controls.avatar.radius
|
||||
int collapsedAvatarRadius: controls.avatar.radius
|
||||
|
||||
unreadIndicator:
|
||||
color background: colors.strongBackground
|
||||
color text: colors.accentText
|
||||
bool bold: false
|
||||
color border: Qt.darker(text, 2)
|
||||
int borderWidth: 1
|
||||
int radius: theme.radius / 2
|
||||
|
||||
color highlightBackground: colors.strongBackground
|
||||
color highlightText: colors.errorText
|
||||
bool highlightBold: false
|
||||
color highlightBorder: Qt.darker(highlightText, 2)
|
||||
int highlightBorderWidth: 1
|
||||
int highlightRadius: theme.radius / 2
|
||||
|
||||
bottomBar:
|
||||
color background: "transparent"
|
||||
color settingsButtonBackground: colors.strongBackground
|
||||
color filterFieldBackground: colors.strongBackground
|
||||
|
||||
|
||||
chat:
|
||||
roomHeader:
|
||||
color background: controls.header.background
|
||||
color name: colors.text
|
||||
color topic: colors.dimText
|
||||
|
||||
roomPane:
|
||||
color background: "transparent"
|
||||
|
||||
topBar:
|
||||
color background: colors.strongBackground
|
||||
|
||||
listView:
|
||||
color background: colors.mediumBackground
|
||||
|
||||
member:
|
||||
real invitedOpacity: 0.5
|
||||
|
||||
color background: "transparent"
|
||||
color name: colors.text
|
||||
color subtitle: colors.dimText
|
||||
|
||||
color adminIcon: hsluv(60, colors.saturation * 2.25, 60)
|
||||
color moderatorIcon: adminIcon
|
||||
color invitedIcon: hsluv(0, colors.saturation * 2.25, 60)
|
||||
|
||||
roomSettings:
|
||||
color background: colors.mediumBackground
|
||||
|
||||
bottomBar:
|
||||
color background: colors.strongBackground
|
||||
|
||||
inviteButton:
|
||||
color background: "transparent"
|
||||
|
||||
filterMembers:
|
||||
color background: "transparent"
|
||||
|
||||
eventList:
|
||||
color background: "transparent"
|
||||
|
||||
message:
|
||||
int avatarSize: 56 * uiScale
|
||||
int collapsedAvatarSize: 32 * uiScale
|
||||
int avatarRadius: controls.avatar.radius
|
||||
|
||||
int radius: theme.radius
|
||||
int horizontalSpacing: theme.spacing / 1.25
|
||||
int verticalSpacing: theme.spacing / 1.75
|
||||
|
||||
color focusedHighlight: colors.accentBackground
|
||||
real focusedHighlightOpacity: 0.4
|
||||
|
||||
color background: colors.weakBackground
|
||||
color ownBackground: colors.mediumBackground
|
||||
color checkedBackground: colors.accentBackground
|
||||
|
||||
color body: colors.text
|
||||
color date: colors.dimText
|
||||
color localEcho: colors.dimText
|
||||
color readCounter: colors.accentText
|
||||
|
||||
color redactedBody: colors.dimText
|
||||
|
||||
color noticeBody: colors.halfDimText
|
||||
int noticeLineWidth: 1 * uiScale
|
||||
|
||||
color quote: hsluv(
|
||||
135, colors.coloredTextSaturation, colors.coloredTextIntensity,
|
||||
)
|
||||
color link: colors.link
|
||||
color code: colors.code
|
||||
|
||||
string styleSheet:
|
||||
"* { white-space: pre-wrap }" +
|
||||
"a { color: " + link + " }" +
|
||||
"p { margin-top: 0 }" +
|
||||
|
||||
"code { font-family: " + fontFamily.mono + "; " +
|
||||
"color: " + code + " }" +
|
||||
|
||||
"h1, h2, h3 { font-weight: normal }" +
|
||||
"h1 { font-size: " + fontSize.biggest + "px }" +
|
||||
"h2 { font-size: " + fontSize.bigger + "px }" +
|
||||
"h3 { font-size: " + fontSize.big + "px }" +
|
||||
"h4 { font-size: " + fontSize.normal + "px }" +
|
||||
"h5 { font-size: " + fontSize.small + "px }" +
|
||||
"h6 { font-size: " + fontSize.smaller + "px }" +
|
||||
|
||||
"table { margin-top: " + theme.spacing + "px; " +
|
||||
" margin-bottom: " + theme.spacing + "px }" +
|
||||
|
||||
"td { padding-left: " + theme.spacing / 2 + "px; " +
|
||||
" padding-right: " + theme.spacing / 2 + "px; " +
|
||||
" padding-top: " + theme.spacing / 4 + "px; " +
|
||||
" padding-bottom: " + theme.spacing / 4 + "px } " +
|
||||
|
||||
"li { margin-top: " + theme.spacing / 2 + "px; " +
|
||||
" margin-bottom: " + theme.spacing / 2 + "px; }" +
|
||||
|
||||
".sender { margin-bottom: " + spacing / 2 + " }" +
|
||||
".quote { color: " + quote + " }" +
|
||||
|
||||
".mention { text-decoration: none; }" +
|
||||
".room-id-mention, .room-alias-mention { font-weight: bold; }"
|
||||
|
||||
string styleInclude:
|
||||
'<style type"text/css">\n' + styleSheet + '\n</style>\n'
|
||||
|
||||
real thumbnailCheckedOverlayOpacity: 0.4
|
||||
|
||||
daybreak:
|
||||
color background: colors.mediumBackground
|
||||
color text: colors.text
|
||||
int radius: theme.radius
|
||||
|
||||
inviteBanner:
|
||||
color background: colors.mediumBackground
|
||||
|
||||
leftBanner:
|
||||
color background: colors.mediumBackground
|
||||
|
||||
unknownDevices:
|
||||
color background: colors.mediumBackground
|
||||
|
||||
typingMembers:
|
||||
color background: hsluv(
|
||||
colors.hue, colors.saturation, colors.intensity * 9, 0.52
|
||||
)
|
||||
|
||||
replyBar:
|
||||
color background: chat.typingMembers.background
|
||||
|
||||
fileTransfer:
|
||||
color background: chat.typingMembers.background
|
||||
|
||||
userAutoCompletion:
|
||||
color background: chat.typingMembers.background
|
||||
int avatarsRadius: controls.avatar.radius
|
||||
color displayNames: colors.text
|
||||
color userIds: colors.dimText
|
||||
|
||||
composer:
|
||||
color background: colors.strongBackground
|
||||
|
||||
uploadButton:
|
||||
color background: "transparent"
|
||||
|
||||
|
||||
mediaPlayer:
|
||||
hoverPreview:
|
||||
int maxHeight: 192
|
||||
|
||||
progress:
|
||||
int height: 8
|
||||
color background: hsluv(0, 0, 0, 0.5)
|
||||
|
||||
controls:
|
||||
int iconSize: icons.dimension
|
||||
int volumeSliderWidth: 100
|
||||
int speedSliderWidth: 100
|
||||
color background: hsluv(
|
||||
colors.hue, colors.saturation * 1.25, colors.intensity * 2, 0.85,
|
||||
)
|