Philipp Hörist pushed to branch gajim_1.1 at gajim / gajim

Commits:

13 changed files:

Changes:

  • flatpak/README.md
    ... ... @@ -23,9 +23,9 @@ Replace install path `~/Gajim/gajim_flatpak` with an install path of your choice
    23 23
     *Note: Remove `--user` if you want a system-wide installation.*
    
    24 24
     
    
    25 25
     1. `flatpak --user remote-add --from gnome https://sdk.gnome.org/gnome.flatpakrepo`
    
    26
    -2. `flatpak --user install gnome org.gnome.Platform//3.28`
    
    27
    -3. `flatpak --user install gnome org.gnome.Sdk//3.28`
    
    28
    -4. `flatpak-builder --repo=gajim_flatpak_repo ~/Gajim/gajim_flatpak ~/Gajim/org.gajim.Gajim.json`
    
    26
    +2. `flatpak --user install gnome org.gnome.Platform//3.30`
    
    27
    +3. `flatpak --user install gnome org.gnome.Sdk//3.30`
    
    28
    +4. `flatpak-builder --repo=gajim_flatpak_repo ~/Gajim/gajim_flatpak ~/Gajim/flatpak/org.gajim.Gajim.yaml`
    
    29 29
     5. `flatpak --user remote-add --no-gpg-verify gajim_flatpak_repo gajim_flatpak_repo`
    
    30 30
     6. `flatpak --user install gajim_flatpak_repo org.gajim.Gajim`
    
    31 31
     7. `flatpak run org.gajim.Gajim`
    
    ... ... @@ -51,7 +51,7 @@ In this example, we use `git` to update the repository. You can also download th
    51 51
     
    
    52 52
     ### Install and update Gajim
    
    53 53
     
    
    54
    -1. `flatpak-builder --repo=gajim_flatpak_repo ~/Gajim/gajim_flatpak ~/Gajim/org.gajim.Gajim.json`
    
    54
    +1. `flatpak-builder --repo=gajim_flatpak_repo ~/Gajim/gajim_flatpak ~/Gajim/flatpak/org.gajim.Gajim.yaml`
    
    55 55
     2. `flatpak --user update`
    
    56 56
     3. `flatpak run org.gajim.Gajim`
    
    57 57
     
    

  • flatpak/org.gajim.Gajim.yaml
    1
    +app-id: org.gajim.Gajim
    
    2
    +runtime: org.gnome.Platform
    
    3
    +runtime-version: 3.30
    
    4
    +sdk: org.gnome.Sdk
    
    5
    +command: gajim
    
    6
    +tags: nightly
    
    7
    +desktop-file-name-prefix: '(Nightly) '
    
    8
    +finish-args:
    
    9
    +  - --share=ipc
    
    10
    +  - --share=network
    
    11
    +  - --socket=x11
    
    12
    +  - --socket=wayland
    
    13
    +  - --socket=pulseaudio
    
    14
    +  - --system-talk-name=org.freedesktop.GeoClue2
    
    15
    +  - --system-talk-name=org.freedesktop.login1
    
    16
    +  - --talk-name=org.gnome.ScreenSaver
    
    17
    +  - --talk-name=org.mpris.MediaPlayer2.*
    
    18
    +  # Keyring
    
    19
    +  - --talk-name=org.freedesktop.secrets
    
    20
    +  # dconf
    
    21
    +  - --filesystem=xdg-run/dconf
    
    22
    +  - --filesystem=~/.config/dconf:ro
    
    23
    +  - --talk-name=ca.desrt.dconf
    
    24
    +  - --env=DCONF_USER_CONFIG_DIR=.config/dconf
    
    25
    +  # extensions
    
    26
    +  - --env=PYTHONPATH=/app/plugins/lib/python3.7/site-packages
    
    27
    +
    
    28
    +add-extensions:
    
    29
    +  org.gajim.Gajim.Plugin:
    
    30
    +    directory: plugins
    
    31
    +    merge-dirs: lib/python3.7/site-packages
    
    32
    +    subdirectories: true
    
    33
    +    no-autodownload: true
    
    34
    +    autodelete: true
    
    35
    +
    
    36
    +build-options:
    
    37
    +  cflags: -O2 -g
    
    38
    +  cxxflags: -O2 -g
    
    39
    +
    
    40
    +cleanup:
    
    41
    +  - '/bin/easy*'
    
    42
    +  - /include
    
    43
    +  - /lib/debug
    
    44
    +  - /lib/pkgconfig
    
    45
    +  - /lib/python2.7
    
    46
    +  - /share/aclocal
    
    47
    +  - /share/doc
    
    48
    +  - /share/gtk-doc
    
    49
    +  - /share/man
    
    50
    +  - '*.a'
    
    51
    +  - '*.la'
    
    52
    +
    
    53
    +modules:
    
    54
    +  - name: python3-pycparser
    
    55
    +    buildsystem: simple
    
    56
    +    build-commands:
    
    57
    +      - python3 setup.py install --prefix=/app
    
    58
    +    sources:
    
    59
    +      - type: archive
    
    60
    +        url: https://files.pythonhosted.org/packages/68/9e/49196946aee219aead1290e00d1e7fdeab8567783e83e1b9ab5585e6206a/pycparser-2.19.tar.gz
    
    61
    +        sha256: a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3
    
    62
    +
    
    63
    +  - name: python3-cffi
    
    64
    +    buildsystem: simple
    
    65
    +    build-commands:
    
    66
    +      - python3 setup.py install --prefix=/app
    
    67
    +    sources:
    
    68
    +      - type: archive
    
    69
    +        url: https://files.pythonhosted.org/packages/e7/a7/4cd50e57cc6f436f1cc3a7e8fa700ff9b8b4d471620629074913e3735fb2/cffi-1.11.5.tar.gz
    
    70
    +        sha256: e90f17980e6ab0f3c2f3730e56d1fe9bcba1891eeea58966e89d352492cc74f4
    
    71
    +
    
    72
    +  - name: python3-six
    
    73
    +    buildsystem: simple
    
    74
    +    build-commands:
    
    75
    +      - pip3 install --prefix=/app six-1.11.0-py2.py3-none-any.whl
    
    76
    +    sources:
    
    77
    +      - type: file
    
    78
    +        url: https://pypi.python.org/packages/67/4b/141a581104b1f6397bfa78ac9d43d8ad29a7ca43ea90a2d863fe3056e86a/six-1.11.0-py2.py3-none-any.whl
    
    79
    +        sha256: 832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb
    
    80
    +
    
    81
    +  - name: python3-pyparsing
    
    82
    +    buildsystem: simple
    
    83
    +    build-commands:
    
    84
    +      - pip3 install --prefix=/app pyparsing-2.2.2-py2.py3-none-any.whl
    
    85
    +    sources:
    
    86
    +      - type: file
    
    87
    +        url: https://files.pythonhosted.org/packages/2b/4a/f06b45ab9690d4c37641ec776f7ad691974f4cf6943a73267475b05cbfca/pyparsing-2.2.2-py2.py3-none-any.whl
    
    88
    +        sha256: d29593d8ebe7b57d6967b62494f8c72b03ac0262b1eed63826c6f788b3606401
    
    89
    +
    
    90
    +  - name: python3-packaging
    
    91
    +    buildsystem: simple
    
    92
    +    build-commands:
    
    93
    +      - pip3 install --prefix=/app packaging-18.0-py2.py3-none-any.whl
    
    94
    +    sources:
    
    95
    +      - type: file
    
    96
    +        url: https://files.pythonhosted.org/packages/89/d1/92e6df2e503a69df9faab187c684585f0136662c12bb1f36901d426f3fab/packaging-18.0-py2.py3-none-any.whl
    
    97
    +        sha256: f95a1e147590f204328170981833854229bb2912ac3d5f89e2a8ccd2834800c9
    
    98
    +
    
    99
    +  - name: python3-appdirs
    
    100
    +    buildsystem: simple
    
    101
    +    build-commands:
    
    102
    +      - pip3 install --prefix=/app appdirs-1.4.3-py2.py3-none-any.whl
    
    103
    +    sources:
    
    104
    +      - type: file
    
    105
    +        url: https://pypi.python.org/packages/56/eb/810e700ed1349edde4cbdc1b2a21e28cdf115f9faf263f6bbf8447c1abf3/appdirs-1.4.3-py2.py3-none-any.whl
    
    106
    +        sha256: d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e
    
    107
    +
    
    108
    +  - name: python3-setuptools
    
    109
    +    ensure-writable:
    
    110
    +      - easy-install.pth
    
    111
    +      - setuptools.pth
    
    112
    +    buildsystem: simple
    
    113
    +    build-commands:
    
    114
    +      - python3 setup.py install --prefix=/app
    
    115
    +    sources:
    
    116
    +      - type: archive
    
    117
    +        url: https://files.pythonhosted.org/packages/6e/9c/6a003320b00ef237f94aa74e4ad66c57a7618f6c79d67527136e2544b728/setuptools-40.4.3.zip
    
    118
    +        sha256: acbc5740dd63f243f46c2b4b8e2c7fd92259c2ddb55a4115b16418a2ed371b15
    
    119
    +
    
    120
    +  - name: python3-asn1crypto
    
    121
    +    buildsystem: simple
    
    122
    +    build-commands:
    
    123
    +      - pip3 install --prefix=/app asn1crypto-0.24.0-py2.py3-none-any.whl
    
    124
    +    sources:
    
    125
    +      - type: file
    
    126
    +        url: https://pypi.python.org/packages/ea/cd/35485615f45f30a510576f1a56d1e0a7ad7bd8ab5ed7cdc600ef7cd06222/asn1crypto-0.24.0-py2.py3-none-any.whl
    
    127
    +        sha256: 2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87
    
    128
    +
    
    129
    +  - name: python3-idna
    
    130
    +    buildsystem: simple
    
    131
    +    build-commands:
    
    132
    +      - pip3 install --prefix=/app idna-2.7-py2.py3-none-any.whl
    
    133
    +    sources:
    
    134
    +      - type: file
    
    135
    +        url: https://files.pythonhosted.org/packages/4b/2a/0276479a4b3caeb8a8c1af2f8e4355746a97fab05a372e4a2c6a6b876165/idna-2.7-py2.py3-none-any.whl
    
    136
    +        sha256: 156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e
    
    137
    +
    
    138
    +  - name: python3-cryptography
    
    139
    +    ensure-writable:
    
    140
    +      - easy-install.pth
    
    141
    +    buildsystem: simple
    
    142
    +    build-commands:
    
    143
    +      - python3 setup.py install --prefix=/app
    
    144
    +    sources:
    
    145
    +      - type: archive
    
    146
    +        url: https://files.pythonhosted.org/packages/22/21/233e38f74188db94e8451ef6385754a98f3cad9b59bedf3a8e8b14988be4/cryptography-2.3.1.tar.gz
    
    147
    +        sha256: 8d10113ca826a4c29d5b85b2c4e045ffa8bad74fb525ee0eceb1d38d4c70dfd6
    
    148
    +
    
    149
    +  - name: python3-pyopenssl
    
    150
    +    buildsystem: simple
    
    151
    +    build-commands:
    
    152
    +      - pip3 install --prefix=/app pyOpenSSL-18.0.0-py2.py3-none-any.whl
    
    153
    +    sources:
    
    154
    +      - type: file
    
    155
    +        url: https://files.pythonhosted.org/packages/96/af/9d29e6bd40823061aea2e0574ccb2fcf72bfd6130ce53d32773ec375458c/pyOpenSSL-18.0.0-py2.py3-none-any.whl
    
    156
    +        sha256: 26ff56a6b5ecaf3a2a59f132681e2a80afcc76b4f902f612f518f92c2a1bf854
    
    157
    +
    
    158
    +  - name: python3-dbus-python
    
    159
    +    build-options:
    
    160
    +      env:
    
    161
    +        PYTHON_VERSION: '3'
    
    162
    +    sources:
    
    163
    +      - type: archive
    
    164
    +        url: https://files.pythonhosted.org/packages/3f/e7/4edb582d1ffd5ac3c84188deea32e960b5c8c0fe1da56ce70224f85ce542/dbus-python-1.2.8.tar.gz
    
    165
    +        sha256: abf12bbb765e300bf8e2a1b2f32f85949eab06998dbda127952c31cb63957b6f
    
    166
    +
    
    167
    +  - name: python3-jeepney
    
    168
    +    buildsystem: simple
    
    169
    +    build-commands:
    
    170
    +      - pip3 install --prefix=/app jeepney-0.4-py3-none-any.whl
    
    171
    +    sources:
    
    172
    +      - type: file
    
    173
    +        url: https://files.pythonhosted.org/packages/2b/f7/ff23b9b59534f501d47c327576aadda59da5b83d76ff837e6075bc325b9f/jeepney-0.4-py3-none-any.whl
    
    174
    +        sha256: f6f8b1428403b4afad04b6b82f9ab9fc426c253d7504c9031c41712a2c01dc74
    
    175
    +
    
    176
    +  - name: python3-secretstorage
    
    177
    +    buildsystem: simple
    
    178
    +    build-commands:
    
    179
    +      - pip3 install --prefix=/app SecretStorage-3.1.0-py3-none-any.whl
    
    180
    +    sources:
    
    181
    +      - type: file
    
    182
    +        url: https://files.pythonhosted.org/packages/d8/e8/80975fd281764c80b2eb581a7f25d2109786e273b8925e8161bd2d06d10a/SecretStorage-3.1.0-py3-none-any.whl
    
    183
    +        sha256: 20196abd1a9d1310df7573d58ca6e7ed9292218c98ca3638eea07beb16080343
    
    184
    +
    
    185
    +  - name: python3-entrypoints
    
    186
    +    buildsystem: simple
    
    187
    +    build-commands:
    
    188
    +      - pip3 install --prefix=/app entrypoints-0.2.3-py2.py3-none-any.whl
    
    189
    +    sources:
    
    190
    +      - type: file
    
    191
    +        url: https://files.pythonhosted.org/packages/cc/8b/4eefa9b47f1910b3d2081da67726b066e379b04ca897acfe9f92bac56147/entrypoints-0.2.3-py2.py3-none-any.whl
    
    192
    +        sha256: 10ad569bb245e7e2ba425285b9fa3e8178a0dc92fc53b1e1c553805e15a8825b
    
    193
    +
    
    194
    +  - name: python3-keyring
    
    195
    +    buildsystem: simple
    
    196
    +    build-commands:
    
    197
    +      - pip3 install --prefix=/app keyring-15.1.0-py2.py3-none-any.whl
    
    198
    +    cleanup:
    
    199
    +      - /bin
    
    200
    +    sources:
    
    201
    +      - type: file
    
    202
    +        url: https://files.pythonhosted.org/packages/6c/3f/7a3f780dfa9ee5708507090ce15d6707aded2865f9e6999f48fa88b65bf3/keyring-15.1.0-py2.py3-none-any.whl
    
    203
    +        sha256: 16dddc3edaeb2703aaf5588a0b488b62f162e26f1877b6faf3a3db4b7712df61
    
    204
    +
    
    205
    +  - name: python3-cssutils
    
    206
    +    buildsystem: simple
    
    207
    +    build-commands:
    
    208
    +      - pip3 install --prefix=/app cssutils-1.0.2-py3-none-any.whl
    
    209
    +    cleanup:
    
    210
    +      - /bin
    
    211
    +    sources:
    
    212
    +      - type: file
    
    213
    +        url: https://files.pythonhosted.org/packages/6b/15/a9fb9010f58d1c55dd0b7779db2334feb9a572d407024f39a60f44293861/cssutils-1.0.2-py3-none-any.whl
    
    214
    +        sha256: c74dbe19c92f5052774eadb15136263548dd013250f1ed1027988e7fef125c8d
    
    215
    +
    
    216
    +  - name: gspell
    
    217
    +    cleanup:
    
    218
    +      - /bin
    
    219
    +    sources:
    
    220
    +      - type: archive
    
    221
    +        url: https://download.gnome.org/sources/gspell/1.8/gspell-1.8.1.tar.xz
    
    222
    +        sha256: 819a1d23c7603000e73f5e738bdd284342e0cd345fb0c7650999c31ec741bbe5
    
    223
    +    modules:
    
    224
    +      - name: enchant2
    
    225
    +        cleanup:
    
    226
    +          - /bin
    
    227
    +        sources:
    
    228
    +          - type: archive
    
    229
    +            url: https://github.com/AbiWord/enchant/releases/download/v2.2.3/enchant-2.2.3.tar.gz
    
    230
    +            sha256: abd8e915675cff54c0d4da5029d95c528362266557c61c7149d53fa069b8076d
    
    231
    +
    
    232
    +  - name: python3-nbxmpp
    
    233
    +    buildsystem: simple
    
    234
    +    build-commands:
    
    235
    +      - python3 setup.py install --prefix=/app
    
    236
    +    sources:
    
    237
    +      - type: archive
    
    238
    +        url: https://files.pythonhosted.org/packages/24/54/23a475a0d7d3664ea21b14ce907245dc390496f31d229a9aac2ae20c7c28/nbxmpp-0.6.8.tar.gz
    
    239
    +        sha256: 8c2b4b8aac1a8c6d07c1e30af542fde20a70a9b8c7c04017e9cea0db654437c6
    
    240
    +
    
    241
    +  - name: gajim
    
    242
    +    buildsystem: simple
    
    243
    +    build-commands:
    
    244
    +      - pip3 install --prefix=/app .
    
    245
    +      - touch /app/share/run-as-flatpak
    
    246
    +    sources:
    
    247
    +      - type: git
    
    248
    +        url: https://dev.gajim.org/gajim/gajim.git
    
    249
    +    post-install:
    
    250
    +      - install -d /app/plugins

  • gajim/chat_control.py
    ... ... @@ -134,11 +134,6 @@ class ChatControl(ChatControlBase):
    134 134
             self.show_avatar()
    
    135 135
     
    
    136 136
             # Hook up signals
    
    137
    -        message_tv_buffer = self.msg_textview.get_buffer()
    
    138
    -        id_ = message_tv_buffer.connect('changed',
    
    139
    -            self._on_message_tv_buffer_changed)
    
    140
    -        self.handlers[id_] = message_tv_buffer
    
    141
    -
    
    142 137
             widget = self.xml.get_object('avatar_eventbox')
    
    143 138
             widget.set_property('height-request', AvatarSize.CHAT)
    
    144 139
     
    
    ... ... @@ -680,7 +675,11 @@ class ChatControl(ChatControlBase):
    680 675
             status_escaped = GLib.markup_escape_text(status_reduced)
    
    681 676
     
    
    682 677
             st = app.config.get('displayed_chat_state_notifications')
    
    683
    -        cs = app.contacts.get_combined_chatstate(self.account, self.contact.jid)
    
    678
    +        if self.TYPE_ID == 'pm':
    
    679
    +            cs = self.gc_contact.chatstate
    
    680
    +        else:
    
    681
    +            cs = app.contacts.get_combined_chatstate(
    
    682
    +                self.account, self.contact.jid)
    
    684 683
             if cs and st in ('composing_only', 'all'):
    
    685 684
                 if contact.show == 'offline':
    
    686 685
                     chatstate = ''
    
    ... ... @@ -1152,13 +1151,21 @@ class ChatControl(ChatControlBase):
    1152 1151
             if event.account != self.account:
    
    1153 1152
                 return
    
    1154 1153
     
    
    1155
    -        if event.jid != self.contact.jid:
    
    1156
    -            return
    
    1154
    +        if self.TYPE_ID == 'pm':
    
    1155
    +            if event.contact != self.gc_contact:
    
    1156
    +                return
    
    1157
    +        else:
    
    1158
    +            if event.contact.jid != self.contact.jid:
    
    1159
    +                return
    
    1157 1160
     
    
    1158 1161
             self.draw_banner_text()
    
    1162
    +
    
    1159 1163
             # update chatstate in tab for this chat
    
    1160
    -        chatstate = app.contacts.get_combined_chatstate(
    
    1161
    -            self.account, self.contact.jid)
    
    1164
    +        if event.contact.is_gc_contact:
    
    1165
    +            chatstate = event.contact.chatstate
    
    1166
    +        else:
    
    1167
    +            chatstate = app.contacts.get_combined_chatstate(
    
    1168
    +                self.account, self.contact.jid)
    
    1162 1169
             self.parent_win.redraw_tab(self, chatstate)
    
    1163 1170
     
    
    1164 1171
         def _nec_caps_received(self, obj):
    
    ... ... @@ -1239,12 +1246,6 @@ class ChatControl(ChatControlBase):
    1239 1246
     
    
    1240 1247
                 dialogs.TransformChatToMUC(self.account, [c.jid], [dropped_jid])
    
    1241 1248
     
    
    1242
    -    def _on_message_tv_buffer_changed(self, textbuffer):
    
    1243
    -        super()._on_message_tv_buffer_changed(textbuffer)
    
    1244
    -        if textbuffer.get_char_count() and self.encryption:
    
    1245
    -            app.plugin_manager.extension_point(
    
    1246
    -                'typing' + self.encryption, self)
    
    1247
    -
    
    1248 1249
         def restore_conversation(self):
    
    1249 1250
             jid = self.contact.jid
    
    1250 1251
             # don't restore lines if it's a transport
    

  • gajim/chat_control_base.py
    ... ... @@ -341,10 +341,9 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
    341 341
             con = app.connections[self.account]
    
    342 342
             con.get_module('Chatstate').set_active(self.contact.jid)
    
    343 343
     
    
    344
    -        message_tv_buffer = self.msg_textview.get_buffer()
    
    345
    -        id_ = message_tv_buffer.connect('changed',
    
    344
    +        id_ = self.msg_textview.connect('text-changed',
    
    346 345
                 self._on_message_tv_buffer_changed)
    
    347
    -        self.handlers[id_] = message_tv_buffer
    
    346
    +        self.handlers[id_] = self.msg_textview
    
    348 347
             if parent_win is not None:
    
    349 348
                 id_ = parent_win.window.connect('motion-notify-event',
    
    350 349
                     self._on_window_motion_notify)
    
    ... ... @@ -837,10 +836,14 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
    837 836
                 con = app.connections[self.account]
    
    838 837
                 con.get_module('Chatstate').set_mouse_activity(self.contact)
    
    839 838
     
    
    840
    -    def _on_message_tv_buffer_changed(self, *args):
    
    839
    +    def _on_message_tv_buffer_changed(self, textview, textbuffer):
    
    840
    +        if textbuffer.get_char_count() and self.encryption:
    
    841
    +            app.plugin_manager.extension_point(
    
    842
    +                'typing' + self.encryption, self)
    
    843
    +
    
    841 844
             con = app.connections[self.account]
    
    842 845
             con.get_module('Chatstate').set_keyboard_activity(self.contact)
    
    843
    -        if not self.msg_textview.has_text():
    
    846
    +        if not textview.has_text():
    
    844 847
                 con.get_module('Chatstate').set_chatstate(self.contact,
    
    845 848
                                                           Chatstate.ACTIVE)
    
    846 849
                 return
    

  • gajim/common/contacts.py
    ... ... @@ -60,6 +60,8 @@ class CommonContact(XMPPEntity):
    60 60
             # this is contact's chatstate
    
    61 61
             self._chatstate = chatstate
    
    62 62
     
    
    63
    +        self._is_pm_contact = False
    
    64
    +
    
    63 65
         @property
    
    64 66
         def show(self):
    
    65 67
             return self._show
    
    ... ... @@ -91,6 +93,10 @@ class CommonContact(XMPPEntity):
    91 93
         def is_gc_contact(self):
    
    92 94
             return isinstance(self, GC_Contact)
    
    93 95
     
    
    96
    +    @property
    
    97
    +    def is_pm_contact(self):
    
    98
    +        return self._is_pm_contact
    
    99
    +
    
    94 100
         def get_full_jid(self):
    
    95 101
             raise NotImplementedError
    
    96 102
     
    
    ... ... @@ -117,7 +123,8 @@ class Contact(CommonContact):
    117 123
         """
    
    118 124
         def __init__(self, jid, account, name='', groups=None, show='', status='',
    
    119 125
         sub='', ask='', resource='', priority=0, keyID='', client_caps=None,
    
    120
    -    chatstate=None, idle_time=None, avatar_sha=None, groupchat=False):
    
    126
    +    chatstate=None, idle_time=None, avatar_sha=None, groupchat=False,
    
    127
    +    is_pm_contact=False):
    
    121 128
             if not isinstance(jid, str):
    
    122 129
                 print('no str')
    
    123 130
             if groups is None:
    
    ... ... @@ -130,6 +137,7 @@ class Contact(CommonContact):
    130 137
             self.groups = [i if i else _('General') for i in set(groups)] # filter duplicate values
    
    131 138
             self.avatar_sha = avatar_sha
    
    132 139
             self._is_groupchat = groupchat
    
    140
    +        self._is_pm_contact = is_pm_contact
    
    133 141
     
    
    134 142
             self.sub = sub
    
    135 143
             self.ask = ask
    
    ... ... @@ -227,7 +235,8 @@ class GC_Contact(CommonContact):
    227 235
             """
    
    228 236
             return Contact(jid=self.get_full_jid(), account=self.account,
    
    229 237
                 name=self.name, groups=[], show=self.show, status=self.status,
    
    230
    -            sub='none', client_caps=self.client_caps, avatar_sha=self.avatar_sha)
    
    238
    +            sub='none', client_caps=self.client_caps, avatar_sha=self.avatar_sha,
    
    239
    +            is_pm_contact=True)
    
    231 240
     
    
    232 241
     
    
    233 242
     class LegacyContactsAPI:
    

  • gajim/common/i18n.py
    ... ... @@ -67,7 +67,7 @@ def iter_locale_dirs():
    67 67
                 continue
    
    68 68
             found_paths.append(locale_dir)
    
    69 69
             if locale_dir.is_dir():
    
    70
    -            yield locale_dir
    
    70
    +            yield str(locale_dir)
    
    71 71
     
    
    72 72
     def initialize_direction_mark():
    
    73 73
         from gi.repository import Gtk
    

  • gajim/common/modules/chatstates.py
    ... ... @@ -74,42 +74,58 @@ class Chatstate:
    74 74
                 return
    
    75 75
     
    
    76 76
             full_jid = stanza.getFrom()
    
    77
    -        jid = full_jid.getStripped()
    
    78 77
     
    
    79 78
             if self._con.get_own_jid().bareMatch(full_jid):
    
    80 79
                 return
    
    81 80
     
    
    82
    -        contact = app.contacts.get_contact_from_full_jid(
    
    83
    -            self._account, str(full_jid))
    
    84
    -        if contact is None or contact.is_gc_contact:
    
    81
    +        contact = app.contacts.get_gc_contact(
    
    82
    +            self._account, full_jid.getStripped(), full_jid.getResource())
    
    83
    +        if contact is None:
    
    84
    +            contact = app.contacts.get_contact_from_full_jid(
    
    85
    +                self._account, str(full_jid))
    
    86
    +        if contact is None:
    
    85 87
                 return
    
    86 88
     
    
    87 89
             if contact.chatstate is None:
    
    88 90
                 return
    
    89 91
     
    
    92
    +        if contact.is_gc_contact:
    
    93
    +            jid = contact.get_full_jid()
    
    94
    +        else:
    
    95
    +            jid = contact.jid
    
    96
    +
    
    90 97
             contact.chatstate = None
    
    91
    -        self._chatstates.pop(contact.jid, None)
    
    92
    -        self._last_mouse_activity.pop(contact.jid, None)
    
    98
    +        self._chatstates.pop(jid, None)
    
    99
    +        self._last_mouse_activity.pop(jid, None)
    
    100
    +        self._last_keyboard_activity.pop(jid, None)
    
    93 101
     
    
    94 102
             log.info('Reset chatstate for %s', jid)
    
    95 103
     
    
    96 104
             app.nec.push_outgoing_event(
    
    97 105
                 NetworkEvent('chatstate-received',
    
    98 106
                              account=self._account,
    
    99
    -                         jid=jid))
    
    107
    +                         contact=contact))
    
    100 108
     
    
    101 109
         def delegate(self, event: Any) -> None:
    
    102 110
             if self._con.get_own_jid().bareMatch(event.jid) or event.sent:
    
    103 111
                 # Dont show chatstates from our own resources
    
    104 112
                 return
    
    105 113
     
    
    114
    +        if event.mtype == 'groupchat':
    
    115
    +            # Not implemented yet
    
    116
    +            return
    
    117
    +
    
    106 118
             chatstate = parse_chatstate(event.stanza)
    
    107 119
             if chatstate is None:
    
    108 120
                 return
    
    109 121
     
    
    110
    -        contact = app.contacts.get_contact_from_full_jid(
    
    111
    -            self._account, event.fjid)
    
    112
    -        if contact is None or contact.is_gc_contact:
    
    122
    +        if event.muc_pm:
    
    123
    +            contact = app.contacts.get_gc_contact(
    
    124
    +                self._account, event.jid, event.resource)
    
    125
    +        else:
    
    126
    +            contact = app.contacts.get_contact_from_full_jid(
    
    127
    +                self._account, event.fjid)
    
    128
    +        if contact is None:
    
    113 129
                 return
    
    114 130
     
    
    115 131
             contact.chatstate = chatstate
    
    ... ... @@ -117,7 +133,7 @@ class Chatstate:
    117 133
             app.nec.push_outgoing_event(
    
    118 134
                 NetworkEvent('chatstate-received',
    
    119 135
                              account=self._account,
    
    120
    -                         jid=event.jid))
    
    136
    +                         contact=contact))
    
    121 137
     
    
    122 138
         def _check_last_interaction(self) -> GLib.SOURCE_CONTINUE:
    
    123 139
             setting = app.config.get('outgoing_chat_state_notifications')
    
    ... ... @@ -125,14 +141,16 @@ class Chatstate:
    125 141
                 return GLib.SOURCE_CONTINUE
    
    126 142
     
    
    127 143
             now = time.time()
    
    128
    -        for jid, time_ in self._last_mouse_activity.items():
    
    144
    +        for jid in list(self._last_mouse_activity.keys()):
    
    145
    +            time_ = self._last_mouse_activity[jid]
    
    129 146
                 current_state = self._chatstates.get(jid)
    
    130 147
                 if current_state is None:
    
    131 148
                     self._last_mouse_activity.pop(jid, None)
    
    132
    -                return GLib.SOURCE_CONTINUE
    
    149
    +                self._last_keyboard_activity.pop(jid, None)
    
    150
    +                continue
    
    133 151
     
    
    134 152
                 if current_state in (State.GONE, State.INACTIVE):
    
    135
    -                return GLib.SOURCE_CONTINUE
    
    153
    +                continue
    
    136 154
     
    
    137 155
                 new_chatstate = None
    
    138 156
                 if now - time_ > INACTIVE_AFTER:
    
    ... ... @@ -147,9 +165,16 @@ class Chatstate:
    147 165
                     if self._chatstates.get(jid) != new_chatstate:
    
    148 166
                         contact = app.contacts.get_contact(self._account, jid)
    
    149 167
                         if contact is None:
    
    150
    -                        self._last_mouse_activity.pop(jid, None)
    
    151
    -                        return GLib.SOURCE_CONTINUE
    
    152
    -                    self.set_chatstate(contact, new_chatstate)
    
    168
    +                        room, nick = app.get_room_and_nick_from_fjid(jid)
    
    169
    +                        contact = app.contacts.get_gc_contact(
    
    170
    +                            self._account, room, nick)
    
    171
    +                        if contact is not None:
    
    172
    +                            contact = contact.as_contact()
    
    173
    +                        else:
    
    174
    +                            self._last_mouse_activity.pop(jid, None)
    
    175
    +                            self._last_keyboard_activity.pop(jid, None)
    
    176
    +                            continue
    
    177
    +                self.set_chatstate(contact, new_chatstate)
    
    153 178
     
    
    154 179
             return GLib.SOURCE_CONTINUE
    
    155 180
     
    
    ... ... @@ -191,13 +216,15 @@ class Chatstate:
    191 216
                                              chatstate=str(State.GONE)))
    
    192 217
                 self._chatstates.pop(contact.jid, None)
    
    193 218
                 self._last_mouse_activity.pop(contact.jid, None)
    
    219
    +            self._last_keyboard_activity.pop(contact.jid, None)
    
    194 220
                 return
    
    195 221
     
    
    196 222
             if not contact.is_groupchat():
    
    197 223
                 # Dont leak presence to contacts
    
    198 224
                 # which are not allowed to see our status
    
    199
    -            if contact and contact.sub in ('to', 'none'):
    
    200
    -                return
    
    225
    +            if not contact.is_pm_contact:
    
    226
    +                if contact and contact.sub in ('to', 'none'):
    
    227
    +                    return
    
    201 228
     
    
    202 229
                 if contact.show == 'offline':
    
    203 230
                     return
    

  • gajim/data/gui/change_status_message_dialog.ui
    1 1
     <?xml version="1.0" encoding="UTF-8"?>
    
    2
    -<!-- Generated with glade 3.18.3 -->
    
    2
    +<!-- Generated with glade 3.22.1 -->
    
    3 3
     <interface>
    
    4
    -  <requires lib="gtk+" version="3.12"/>
    
    4
    +  <requires lib="gtk+" version="3.18"/>
    
    5 5
       <object class="GtkDialog" id="change_status_message_dialog">
    
    6 6
         <property name="can_focus">False</property>
    
    7
    -    <property name="border_width">6</property>
    
    7
    +    <property name="border_width">18</property>
    
    8 8
         <property name="default_width">270</property>
    
    9 9
         <property name="default_height">330</property>
    
    10 10
         <property name="type_hint">dialog</property>
    
    11 11
         <signal name="key-press-event" handler="on_change_status_message_dialog_key_press_event" swapped="no"/>
    
    12
    +    <child>
    
    13
    +      <placeholder/>
    
    14
    +    </child>
    
    12 15
         <child internal-child="vbox">
    
    13
    -      <object class="GtkBox" id="dialog-vbox5">
    
    16
    +      <object class="GtkBox">
    
    14 17
             <property name="visible">True</property>
    
    15 18
             <property name="can_focus">False</property>
    
    16 19
             <property name="orientation">vertical</property>
    
    17
    -        <property name="spacing">6</property>
    
    20
    +        <property name="spacing">12</property>
    
    18 21
             <child internal-child="action_area">
    
    19 22
               <object class="GtkButtonBox" id="dialog-action_area">
    
    20 23
                 <property name="visible">True</property>
    
    21 24
                 <property name="can_focus">False</property>
    
    25
    +            <property name="margin_top">6</property>
    
    22 26
                 <property name="layout_style">end</property>
    
    23 27
                 <child>
    
    24 28
                   <object class="GtkButton" id="cancel_button">
    
    25 29
                     <property name="label">gtk-cancel</property>
    
    26
    -                <property name="use_action_appearance">False</property>
    
    27 30
                     <property name="visible">True</property>
    
    28 31
                     <property name="can_focus">True</property>
    
    29 32
                     <property name="can_default">True</property>
    
    ... ... @@ -39,13 +42,15 @@
    39 42
                 <child>
    
    40 43
                   <object class="GtkButton" id="ok_button">
    
    41 44
                     <property name="label">gtk-ok</property>
    
    42
    -                <property name="use_action_appearance">False</property>
    
    43 45
                     <property name="visible">True</property>
    
    44 46
                     <property name="can_focus">True</property>
    
    45 47
                     <property name="can_default">True</property>
    
    46 48
                     <property name="has_default">True</property>
    
    47 49
                     <property name="receives_default">False</property>
    
    48 50
                     <property name="use_stock">True</property>
    
    51
    +                <style>
    
    52
    +                  <class name="suggested-action"/>
    
    53
    +                </style>
    
    49 54
                   </object>
    
    50 55
                   <packing>
    
    51 56
                     <property name="expand">False</property>
    
    ... ... @@ -62,109 +67,94 @@
    62 67
               </packing>
    
    63 68
             </child>
    
    64 69
             <child>
    
    65
    -          <object class="GtkFrame" id="frame38">
    
    70
    +          <object class="GtkFrame">
    
    66 71
                 <property name="visible">True</property>
    
    67 72
                 <property name="can_focus">False</property>
    
    68 73
                 <property name="label_xalign">0</property>
    
    69 74
                 <property name="shadow_type">none</property>
    
    70 75
                 <child>
    
    71
    -              <object class="GtkBox" id="vbox112">
    
    76
    +              <object class="GtkBox">
    
    72 77
                     <property name="visible">True</property>
    
    73 78
                     <property name="can_focus">False</property>
    
    74
    -                <property name="border_width">6</property>
    
    79
    +                <property name="margin_top">6</property>
    
    75 80
                     <property name="orientation">vertical</property>
    
    76 81
                     <property name="spacing">6</property>
    
    77 82
                     <child>
    
    78
    -                  <object class="GtkScrolledWindow" id="scrolledwindow24">
    
    83
    +                  <object class="GtkBox">
    
    79 84
                         <property name="visible">True</property>
    
    80
    -                    <property name="can_focus">True</property>
    
    81
    -                    <property name="shadow_type">in</property>
    
    85
    +                    <property name="can_focus">False</property>
    
    82 86
                         <child>
    
    83
    -                      <object class="GtkTextView" id="message_textview">
    
    87
    +                      <object class="GtkScrolledWindow">
    
    84 88
                             <property name="visible">True</property>
    
    85 89
                             <property name="can_focus">True</property>
    
    86
    -                        <property name="wrap_mode">word</property>
    
    90
    +                        <property name="shadow_type">in</property>
    
    91
    +                        <child>
    
    92
    +                          <object class="GtkTextView" id="message_textview">
    
    93
    +                            <property name="visible">True</property>
    
    94
    +                            <property name="can_focus">True</property>
    
    95
    +                            <property name="wrap_mode">word</property>
    
    96
    +                            <property name="left_margin">6</property>
    
    97
    +                            <property name="right_margin">6</property>
    
    98
    +                            <property name="top_margin">6</property>
    
    99
    +                            <property name="bottom_margin">6</property>
    
    100
    +                          </object>
    
    101
    +                        </child>
    
    87 102
                           </object>
    
    103
    +                      <packing>
    
    104
    +                        <property name="expand">True</property>
    
    105
    +                        <property name="fill">True</property>
    
    106
    +                        <property name="position">0</property>
    
    107
    +                      </packing>
    
    88 108
                         </child>
    
    89
    -                  </object>
    
    90
    -                  <packing>
    
    91
    -                    <property name="expand">True</property>
    
    92
    -                    <property name="fill">True</property>
    
    93
    -                    <property name="position">0</property>
    
    94
    -                  </packing>
    
    95
    -                </child>
    
    96
    -                <child>
    
    97
    -                  <object class="GtkButtonBox" id="hbuttonbox33">
    
    98
    -                    <property name="visible">True</property>
    
    99
    -                    <property name="can_focus">False</property>
    
    100
    -                    <property name="layout_style">end</property>
    
    101 109
                         <child>
    
    102 110
                           <object class="GtkButton" id="save_as_preset_button">
    
    103
    -                        <property name="use_action_appearance">False</property>
    
    104 111
                             <property name="visible">True</property>
    
    105 112
                             <property name="sensitive">False</property>
    
    106 113
                             <property name="can_focus">True</property>
    
    107 114
                             <property name="can_default">True</property>
    
    108 115
                             <property name="receives_default">False</property>
    
    116
    +                        <property name="tooltip_text" translatable="yes">Save this message as a preset</property>
    
    109 117
                             <signal name="clicked" handler="on_save_as_preset_button_clicked" swapped="no"/>
    
    110 118
                             <child>
    
    111
    -                          <object class="GtkBox" id="hbox3021">
    
    119
    +                          <object class="GtkImage">
    
    112 120
                                 <property name="visible">True</property>
    
    113 121
                                 <property name="can_focus">False</property>
    
    114
    -                            <property name="spacing">2</property>
    
    115
    -                            <child>
    
    116
    -                              <object class="GtkImage" id="image1369">
    
    117
    -                                <property name="visible">True</property>
    
    118
    -                                <property name="can_focus">False</property>
    
    119
    -                                <property name="stock">gtk-save-as</property>
    
    120
    -                              </object>
    
    121
    -                              <packing>
    
    122
    -                                <property name="expand">False</property>
    
    123
    -                                <property name="fill">False</property>
    
    124
    -                                <property name="position">0</property>
    
    125
    -                              </packing>
    
    126
    -                            </child>
    
    127
    -                            <child>
    
    128
    -                              <object class="GtkLabel" id="label380">
    
    129
    -                                <property name="visible">True</property>
    
    130
    -                                <property name="can_focus">False</property>
    
    131
    -                                <property name="label" translatable="yes">Save as Preset...</property>
    
    132
    -                                <property name="use_underline">True</property>
    
    133
    -                              </object>
    
    134
    -                              <packing>
    
    135
    -                                <property name="expand">False</property>
    
    136
    -                                <property name="fill">False</property>
    
    137
    -                                <property name="position">1</property>
    
    138
    -                              </packing>
    
    139
    -                            </child>
    
    122
    +                            <property name="stock">gtk-save-as</property>
    
    140 123
                               </object>
    
    141 124
                             </child>
    
    142 125
                           </object>
    
    143 126
                           <packing>
    
    144 127
                             <property name="expand">False</property>
    
    145 128
                             <property name="fill">False</property>
    
    146
    -                        <property name="position">0</property>
    
    129
    +                        <property name="position">1</property>
    
    147 130
                           </packing>
    
    148 131
                         </child>
    
    149 132
                       </object>
    
    150 133
                       <packing>
    
    151
    -                    <property name="expand">False</property>
    
    134
    +                    <property name="expand">True</property>
    
    152 135
                         <property name="fill">True</property>
    
    153
    -                    <property name="position">1</property>
    
    136
    +                    <property name="position">0</property>
    
    154 137
                       </packing>
    
    155 138
                     </child>
    
    156 139
                     <child>
    
    157 140
                       <object class="GtkGrid" id="under_table">
    
    158 141
                         <property name="visible">True</property>
    
    159 142
                         <property name="can_focus">False</property>
    
    143
    +                    <property name="halign">center</property>
    
    144
    +                    <property name="margin_top">6</property>
    
    160 145
                         <property name="row_spacing">6</property>
    
    161
    -                    <property name="column_spacing">6</property>
    
    146
    +                    <property name="column_spacing">12</property>
    
    162 147
                         <child>
    
    163
    -                      <object class="GtkLabel" id="label165">
    
    148
    +                      <object class="GtkLabel">
    
    164 149
                             <property name="visible">True</property>
    
    165 150
                             <property name="can_focus">False</property>
    
    166
    -                        <property name="xalign">0</property>
    
    167
    -                        <property name="label" translatable="yes">Preset messages:</property>
    
    151
    +                        <property name="halign">end</property>
    
    152
    +                        <property name="label" translatable="yes">Preset _messages</property>
    
    153
    +                        <property name="use_underline">True</property>
    
    154
    +                        <property name="mnemonic_widget">message_combobox</property>
    
    155
    +                        <style>
    
    156
    +                          <class name="dim-label"/>
    
    157
    +                        </style>
    
    168 158
                           </object>
    
    169 159
                           <packing>
    
    170 160
                             <property name="left_attach">0</property>
    
    ... ... @@ -175,8 +165,14 @@
    175 165
                           <object class="GtkLabel" id="activity_label">
    
    176 166
                             <property name="visible">True</property>
    
    177 167
                             <property name="can_focus">False</property>
    
    178
    -                        <property name="xalign">0</property>
    
    179
    -                        <property name="label" translatable="yes">Activity:</property>
    
    168
    +                        <property name="halign">end</property>
    
    169
    +                        <property name="margin_top">6</property>
    
    170
    +                        <property name="label" translatable="yes">Ac_tivity</property>
    
    171
    +                        <property name="use_underline">True</property>
    
    172
    +                        <property name="mnemonic_widget">activity_button</property>
    
    173
    +                        <style>
    
    174
    +                          <class name="dim-label"/>
    
    175
    +                        </style>
    
    180 176
                           </object>
    
    181 177
                           <packing>
    
    182 178
                             <property name="left_attach">0</property>
    
    ... ... @@ -187,8 +183,13 @@
    187 183
                           <object class="GtkLabel" id="mood_label">
    
    188 184
                             <property name="visible">True</property>
    
    189 185
                             <property name="can_focus">False</property>
    
    190
    -                        <property name="xalign">0</property>
    
    191
    -                        <property name="label" translatable="yes">Mood:</property>
    
    186
    +                        <property name="halign">end</property>
    
    187
    +                        <property name="label" translatable="yes">M_ood</property>
    
    188
    +                        <property name="use_underline">True</property>
    
    189
    +                        <property name="mnemonic_widget">mood_button</property>
    
    190
    +                        <style>
    
    191
    +                          <class name="dim-label"/>
    
    192
    +                        </style>
    
    192 193
                           </object>
    
    193 194
                           <packing>
    
    194 195
                             <property name="left_attach">0</property>
    
    ... ... @@ -197,6 +198,7 @@
    197 198
                         </child>
    
    198 199
                         <child>
    
    199 200
                           <object class="GtkComboBox" id="message_combobox">
    
    201
    +                        <property name="width_request">200</property>
    
    200 202
                             <property name="visible">True</property>
    
    201 203
                             <property name="can_focus">False</property>
    
    202 204
                             <property name="hexpand">True</property>
    
    ... ... @@ -209,13 +211,13 @@
    209 211
                         </child>
    
    210 212
                         <child>
    
    211 213
                           <object class="GtkButton" id="activity_button">
    
    212
    -                        <property name="use_action_appearance">False</property>
    
    213 214
                             <property name="visible">True</property>
    
    214 215
                             <property name="can_focus">True</property>
    
    215 216
                             <property name="receives_default">True</property>
    
    217
    +                        <property name="margin_top">6</property>
    
    216 218
                             <signal name="clicked" handler="on_activity_button_clicked" swapped="no"/>
    
    217 219
                             <child>
    
    218
    -                          <object class="GtkBox" id="hbox1">
    
    220
    +                          <object class="GtkBox">
    
    219 221
                                 <property name="visible">True</property>
    
    220 222
                                 <property name="can_focus">False</property>
    
    221 223
                                 <property name="spacing">6</property>
    
    ... ... @@ -235,8 +237,8 @@
    235 237
                                   <object class="GtkLabel" id="activity_button_label">
    
    236 238
                                     <property name="visible">True</property>
    
    237 239
                                     <property name="can_focus">False</property>
    
    238
    -                                <property name="xalign">0</property>
    
    239 240
                                     <property name="wrap">True</property>
    
    241
    +                                <property name="xalign">0</property>
    
    240 242
                                   </object>
    
    241 243
                                   <packing>
    
    242 244
                                     <property name="expand">True</property>
    
    ... ... @@ -254,13 +256,12 @@
    254 256
                         </child>
    
    255 257
                         <child>
    
    256 258
                           <object class="GtkButton" id="mood_button">
    
    257
    -                        <property name="use_action_appearance">False</property>
    
    258 259
                             <property name="visible">True</property>
    
    259 260
                             <property name="can_focus">True</property>
    
    260 261
                             <property name="receives_default">True</property>
    
    261 262
                             <signal name="clicked" handler="on_mood_button_clicked" swapped="no"/>
    
    262 263
                             <child>
    
    263
    -                          <object class="GtkBox" id="hbox2">
    
    264
    +                          <object class="GtkBox">
    
    264 265
                                 <property name="visible">True</property>
    
    265 266
                                 <property name="can_focus">False</property>
    
    266 267
                                 <property name="spacing">6</property>
    
    ... ... @@ -280,8 +281,8 @@
    280 281
                                   <object class="GtkLabel" id="mood_button_label">
    
    281 282
                                     <property name="visible">True</property>
    
    282 283
                                     <property name="can_focus">False</property>
    
    283
    -                                <property name="xalign">0</property>
    
    284 284
                                     <property name="wrap">True</property>
    
    285
    +                                <property name="xalign">0</property>
    
    285 286
                                   </object>
    
    286 287
                                   <packing>
    
    287 288
                                     <property name="expand">True</property>
    
    ... ... @@ -301,17 +302,23 @@
    301 302
                       <packing>
    
    302 303
                         <property name="expand">False</property>
    
    303 304
                         <property name="fill">True</property>
    
    304
    -                    <property name="position">2</property>
    
    305
    +                    <property name="position">1</property>
    
    305 306
                       </packing>
    
    306 307
                     </child>
    
    307 308
                   </object>
    
    308 309
                 </child>
    
    309 310
                 <child type="label">
    
    310
    -              <object class="GtkLabel" id="label383">
    
    311
    +              <object class="GtkLabel">
    
    311 312
                     <property name="visible">True</property>
    
    312 313
                     <property name="can_focus">False</property>
    
    313
    -                <property name="label" translatable="yes">&lt;b&gt;Type your new status message&lt;/b&gt;</property>
    
    314
    -                <property name="use_markup">True</property>
    
    314
    +                <property name="label" translatable="yes">_Type your new status message</property>
    
    315
    +                <property name="use_underline">True</property>
    
    316
    +                <property name="justify">center</property>
    
    317
    +                <property name="mnemonic_widget">message_textview</property>
    
    318
    +                <style>
    
    319
    +                  <class name="dim-label"/>
    
    320
    +                  <class name="bold"/>
    
    321
    +                </style>
    
    315 322
                   </object>
    
    316 323
                 </child>
    
    317 324
               </object>
    

  • gajim/gajim.py
    ... ... @@ -27,7 +27,7 @@ from distutils.version import LooseVersion as V
    27 27
     # Install _() in namespace
    
    28 28
     from gajim.common import i18n
    
    29 29
     
    
    30
    -_MIN_NBXMPP_VER = "0.6.7"
    
    30
    +_MIN_NBXMPP_VER = "0.6.8"
    
    31 31
     _MIN_GTK_VER = "3.22.0"
    
    32 32
     
    
    33 33
     
    

  • gajim/message_textview.py
    ... ... @@ -21,6 +21,7 @@ import gc
    21 21
     
    
    22 22
     from gi.repository import Gtk
    
    23 23
     from gi.repository import GLib
    
    24
    +from gi.repository import GObject
    
    24 25
     from gi.repository import Pango
    
    25 26
     
    
    26 27
     from gajim.common import app
    
    ... ... @@ -36,6 +37,10 @@ class MessageTextView(Gtk.TextView):
    36 37
         Class for the message textview (where user writes new messages) for
    
    37 38
         chat/groupchat windows
    
    38 39
         """
    
    40
    +    __gsignals__ = {
    
    41
    +        'text-changed': (GObject.SIGNAL_RUN_LAST, None, (Gtk.TextBuffer,))
    
    42
    +    }
    
    43
    +
    
    39 44
         UNDO_LIMIT = 20
    
    40 45
         PLACEHOLDER = _('Write a message…')
    
    41 46
     
    
    ... ... @@ -60,6 +65,9 @@ class MessageTextView(Gtk.TextView):
    60 65
             self.undo_pressed = False
    
    61 66
     
    
    62 67
             buffer_ = self.get_buffer()
    
    68
    +        buffer_.connect('changed', self._on_buffer_changed)
    
    69
    +        self._last_text = ''
    
    70
    +
    
    63 71
             self.begin_tags = {}
    
    64 72
             self.end_tags = {}
    
    65 73
             self.color_tags = []
    
    ... ... @@ -94,6 +102,16 @@ class MessageTextView(Gtk.TextView):
    94 102
             buffer_.insert_with_tags(
    
    95 103
                 start, self.PLACEHOLDER, self.placeholder_tag)
    
    96 104
     
    
    105
    +    def _on_buffer_changed(self, *args):
    
    106
    +        text = self.get_text()
    
    107
    +        # Because of inserting and removing PLACEHOLDER text
    
    108
    +        # the signal becomes unreliable when determining if the user
    
    109
    +        # typed in new text. So we send our own signal depending on if
    
    110
    +        # there is real new text that is not the PLACEHOLDER
    
    111
    +        if text != self._last_text:
    
    112
    +            self.emit('text-changed', self.get_buffer())
    
    113
    +            self._last_text = text
    
    114
    +
    
    97 115
         def has_text(self):
    
    98 116
             buf = self.get_buffer()
    
    99 117
             start, end = buf.get_bounds()
    

  • gajim/plugins/pluginmanager.py
    ... ... @@ -110,7 +110,7 @@ class PluginManager(metaclass=Singleton):
    110 110
             '''
    
    111 111
     
    
    112 112
             for path in reversed(configpaths.get_plugin_dirs()):
    
    113
    -            pc = PluginManager.scan_dir_for_plugins(path)
    
    113
    +            pc = self.scan_dir_for_plugins(path)
    
    114 114
                 self.add_plugins(pc)
    
    115 115
     
    
    116 116
         @log_calls('PluginManager')
    
    ... ... @@ -137,7 +137,6 @@ class PluginManager(metaclass=Singleton):
    137 137
             and adding class from reloaded module or ignoring adding plug-in?
    
    138 138
             '''
    
    139 139
             plugin = plugin_class()
    
    140
    -
    
    141 140
             if plugin not in self.plugins:
    
    142 141
                 if not self._plugin_has_entry_in_global_config(plugin):
    
    143 142
                     self._create_plugin_entry_in_global_config(plugin)
    
    ... ... @@ -520,9 +519,8 @@ class PluginManager(metaclass=Singleton):
    520 519
         def _set_plugin_active_in_global_config(self, plugin, active=True):
    
    521 520
             app.config.set_per('plugins', plugin.short_name, 'active', active)
    
    522 521
     
    
    523
    -    @staticmethod
    
    524 522
         @log_calls('PluginManager')
    
    525
    -    def scan_dir_for_plugins(path, scan_dirs=True, package=False):
    
    523
    +    def scan_dir_for_plugins(self, path, scan_dirs=True, package=False):
    
    526 524
             r'''
    
    527 525
             Scans given directory for plugin classes.
    
    528 526
     
    
    ... ... @@ -584,6 +582,21 @@ class PluginManager(metaclass=Singleton):
    584 582
                                     elem_name, exc_info=True)
    
    585 583
                         continue
    
    586 584
     
    
    585
    +            short_name = conf.get('info', 'short_name', fallback=None)
    
    586
    +            if short_name is None:
    
    587
    +                log.error('No short_name defined for %s', elem_name)
    
    588
    +
    
    589
    +            # Check if the plugin is already loaded
    
    590
    +            try:
    
    591
    +                for plugin in self.plugins:
    
    592
    +                    if plugin.short_name == short_name:
    
    593
    +                        raise PluginAlreadyLoaded(
    
    594
    +                            'Skip Plugin %s because its '
    
    595
    +                            'already loaded' % elem_name)
    
    596
    +            except PluginAlreadyLoaded as error:
    
    597
    +                log.warning(error)
    
    598
    +                continue
    
    599
    +
    
    587 600
                 min_v = conf.get('info', 'min_gajim_version', fallback=None)
    
    588 601
                 max_v = conf.get('info', 'max_gajim_version', fallback=None)
    
    589 602
     
    
    ... ... @@ -734,3 +747,7 @@ class PluginManager(metaclass=Singleton):
    734 747
             for plugin in self.plugins:
    
    735 748
                 if plugin.__path__ in plugin_dir:
    
    736 749
                     return plugin
    
    750
    +
    
    751
    +
    
    752
    +class PluginAlreadyLoaded(Exception):
    
    753
    +    pass

  • gajim/remote_control.py
    ... ... @@ -324,8 +324,14 @@ class GajimRemote(Server):
    324 324
                 self.on_message_sent)
    
    325 325
     
    
    326 326
         def on_chatstate_received(self, obj):
    
    327
    -        self.raise_signal('ChatState', (obj.conn.name, [
    
    328
    -            obj.jid, obj.fjid, obj.stanza, obj.resource, obj.chatstate]))
    
    327
    +        if obj.contact.is_gc_contact:
    
    328
    +            jid = obj.contact.get_full_jid()
    
    329
    +            chatstate = obj.contact.chatstate
    
    330
    +        else:
    
    331
    +            jid = obj.contact.jid
    
    332
    +            chatstate = app.contacts.get_combined_chatstate(
    
    333
    +                obj.account, obj.contact.jid)
    
    334
    +        self.raise_signal('ChatState', (obj.account, [jid, chatstate]))
    
    329 335
     
    
    330 336
         def on_message_sent(self, obj):
    
    331 337
             try:
    

  • org.gajim.Gajim.json deleted
    1
    -{
    
    2
    -    "app-id": "org.gajim.Gajim",
    
    3
    -    "runtime": "org.gnome.Platform",
    
    4
    -    "runtime-version": "3.28",
    
    5
    -    "sdk": "org.gnome.Sdk",
    
    6
    -    "command": "gajim",
    
    7
    -    "tags": ["nightly"],
    
    8
    -    "desktop-file-name-prefix": "(Nightly) ",
    
    9
    -    "finish-args": [
    
    10
    -        "--share=ipc",
    
    11
    -        "--share=network",
    
    12
    -        "--socket=x11",
    
    13
    -        "--socket=wayland",
    
    14
    -        "--socket=pulseaudio",
    
    15
    -        "--system-talk-name=org.freedesktop.GeoClue2",
    
    16
    -        "--system-talk-name=org.freedesktop.login1",
    
    17
    -        "--talk-name=org.gnome.ScreenSaver",
    
    18
    -        "--talk-name=org.mpris.MediaPlayer2.*",
    
    19
    -        /* Keyring */
    
    20
    -        "--talk-name=org.freedesktop.secrets",
    
    21
    -        /* dconf */
    
    22
    -        "--filesystem=xdg-run/dconf",
    
    23
    -        "--filesystem=~/.config/dconf:ro",
    
    24
    -        "--talk-name=ca.desrt.dconf",
    
    25
    -        "--env=DCONF_USER_CONFIG_DIR=.config/dconf",
    
    26
    -        /* extensions */
    
    27
    -        "--env=PYTHONPATH=/app/plugins/lib/python3.5/site-packages"
    
    28
    -    ],
    
    29
    -    "add-extensions": {
    
    30
    -        "org.gajim.Gajim.Plugin": {
    
    31
    -            "directory": "plugins",
    
    32
    -            "merge-dirs": "lib/python3.5/site-packages",
    
    33
    -            "subdirectories": true,
    
    34
    -            "no-autodownload": true,
    
    35
    -            "autodelete": true
    
    36
    -        }
    
    37
    -    },
    
    38
    -    "build-options": {
    
    39
    -        "cflags": "-O2 -g",
    
    40
    -        "cxxflags": "-O2 -g"
    
    41
    -    },
    
    42
    -    "cleanup": [
    
    43
    -        "/bin/easy*",
    
    44
    -        "/include",
    
    45
    -        "/lib/debug",
    
    46
    -        "/lib/pkgconfig",
    
    47
    -        "/lib/python2.7",
    
    48
    -        "/share/aclocal",
    
    49
    -        "/share/doc",
    
    50
    -        "/share/man",
    
    51
    -        "*.a",
    
    52
    -        "*.la"
    
    53
    -    ],
    
    54
    -    "modules": [
    
    55
    -        {
    
    56
    -            "name": "python3-pycparser",
    
    57
    -            "buildsystem": "simple",
    
    58
    -            "build-commands": [
    
    59
    -                "python3 setup.py install --prefix=/app"
    
    60
    -            ],
    
    61
    -            "sources": [
    
    62
    -                {
    
    63
    -                    "type": "archive",
    
    64
    -                    "url": "https://pypi.python.org/packages/8c/2d/aad7f16146f4197a11f8e91fb81df177adcc2073d36a17b1491fd09df6ed/pycparser-2.18.tar.gz",
    
    65
    -                    "sha256": "99a8ca03e29851d96616ad0404b4aad7d9ee16f25c9f9708a11faf2810f7b226"
    
    66
    -                }
    
    67
    -            ]
    
    68
    -        },
    
    69
    -        {
    
    70
    -            "name": "python3-cffi",
    
    71
    -            "buildsystem": "simple",
    
    72
    -            "build-commands": [
    
    73
    -                "python3 setup.py install --prefix=/app"
    
    74
    -            ],
    
    75
    -            "sources": [
    
    76
    -                {
    
    77
    -                    "type": "archive",
    
    78
    -                    "url": "https://files.pythonhosted.org/packages/e7/a7/4cd50e57cc6f436f1cc3a7e8fa700ff9b8b4d471620629074913e3735fb2/cffi-1.11.5.tar.gz",
    
    79
    -                    "sha256": "e90f17980e6ab0f3c2f3730e56d1fe9bcba1891eeea58966e89d352492cc74f4"
    
    80
    -                }
    
    81
    -            ]
    
    82
    -        },
    
    83
    -        {
    
    84
    -            "name": "python3-six",
    
    85
    -            "buildsystem": "simple",
    
    86
    -            "build-commands": [
    
    87
    -                "pip3 install --prefix=/app six-1.11.0-py2.py3-none-any.whl"
    
    88
    -            ],
    
    89
    -            "sources": [
    
    90
    -                {
    
    91
    -                    "type": "file",
    
    92
    -                    "url": "https://pypi.python.org/packages/67/4b/141a581104b1f6397bfa78ac9d43d8ad29a7ca43ea90a2d863fe3056e86a/six-1.11.0-py2.py3-none-any.whl",
    
    93
    -                    "sha256": "832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"
    
    94
    -                }
    
    95
    -            ]
    
    96
    -        },
    
    97
    -        {
    
    98
    -            "name": "python3-pyparsing",
    
    99
    -            "buildsystem": "simple",
    
    100
    -            "build-commands": [
    
    101
    -                "pip3 install --prefix=/app pyparsing-2.2.0-py2.py3-none-any.whl"
    
    102
    -            ],
    
    103
    -            "sources": [
    
    104
    -                {
    
    105
    -                    "type": "file",
    
    106
    -                    "url": "https://pypi.python.org/packages/6a/8a/718fd7d3458f9fab8e67186b00abdd345b639976bc7fb3ae722e1b026a50/pyparsing-2.2.0-py2.py3-none-any.whl",
    
    107
    -                    "sha256": "fee43f17a9c4087e7ed1605bd6df994c6173c1e977d7ade7b651292fab2bd010"
    
    108
    -                }
    
    109
    -            ]
    
    110
    -        },
    
    111
    -        {
    
    112
    -            "name": "python3-packaging",
    
    113
    -            "buildsystem": "simple",
    
    114
    -            "build-commands": [
    
    115
    -                "pip3 install --prefix=/app packaging-17.1-py2.py3-none-any.whl"
    
    116
    -            ],
    
    117
    -            "sources": [
    
    118
    -                {
    
    119
    -                    "type": "file",
    
    120
    -                    "url": "https://files.pythonhosted.org/packages/ad/c2/b500ea05d5f9f361a562f089fc91f77ed3b4783e13a08a3daf82069b1224/packaging-17.1-py2.py3-none-any.whl",
    
    121
    -                    "sha256": "e9215d2d2535d3ae866c3d6efc77d5b24a0192cce0ff20e42896cc0664f889c0"
    
    122
    -                }
    
    123
    -            ]
    
    124
    -        },
    
    125
    -        {
    
    126
    -            "name": "python3-appdirs",
    
    127
    -            "buildsystem": "simple",
    
    128
    -            "build-commands": [
    
    129
    -                "pip3 install --prefix=/app appdirs-1.4.3-py2.py3-none-any.whl"
    
    130
    -            ],
    
    131
    -            "sources": [
    
    132
    -                {
    
    133
    -                    "type": "file",
    
    134
    -                    "url": "https://pypi.python.org/packages/56/eb/810e700ed1349edde4cbdc1b2a21e28cdf115f9faf263f6bbf8447c1abf3/appdirs-1.4.3-py2.py3-none-any.whl",
    
    135
    -                    "sha256": "d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"
    
    136
    -                }
    
    137
    -            ]
    
    138
    -        },
    
    139
    -        {
    
    140
    -            "name": "python3-setuptools",
    
    141
    -            "ensure-writable": [
    
    142
    -                "easy-install.pth",
    
    143
    -                "setuptools.pth"
    
    144
    -            ],
    
    145
    -            "buildsystem": "simple",
    
    146
    -            "build-commands": [
    
    147
    -                "python3 setup.py install --prefix=/app"
    
    148
    -            ],
    
    149
    -            "sources": [
    
    150
    -                {
    
    151
    -                    "type": "archive",
    
    152
    -                    "url": "https://files.pythonhosted.org/packages/d3/3e/1d74cdcb393b68ab9ee18d78c11ae6df8447099f55fe86ee842f9c5b166c/setuptools-40.0.0.zip",
    
    153
    -                    "sha256": "012adb8e25fbfd64c652e99e7bab58799a3aaf05d39ab38561f69190a909015f"
    
    154
    -                }
    
    155
    -            ]
    
    156
    -        },
    
    157
    -        {
    
    158
    -            "name": "python3-asn1crypto",
    
    159
    -            "buildsystem": "simple",
    
    160
    -            "build-commands": [
    
    161
    -                "pip3 install --prefix=/app asn1crypto-0.24.0-py2.py3-none-any.whl"
    
    162
    -            ],
    
    163
    -            "sources": [
    
    164
    -                {
    
    165
    -                    "type": "file",
    
    166
    -                    "url": "https://pypi.python.org/packages/ea/cd/35485615f45f30a510576f1a56d1e0a7ad7bd8ab5ed7cdc600ef7cd06222/asn1crypto-0.24.0-py2.py3-none-any.whl",
    
    167
    -                    "sha256": "2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87"
    
    168
    -                }
    
    169
    -            ]
    
    170
    -        },
    
    171
    -        {
    
    172
    -            "name": "python3-idna",
    
    173
    -            "buildsystem": "simple",
    
    174
    -            "build-commands": [
    
    175
    -                "pip3 install --prefix=/app idna-2.7-py2.py3-none-any.whl"
    
    176
    -            ],
    
    177
    -            "sources": [
    
    178
    -                {
    
    179
    -                    "type": "file",
    
    180
    -                    "url": "https://files.pythonhosted.org/packages/4b/2a/0276479a4b3caeb8a8c1af2f8e4355746a97fab05a372e4a2c6a6b876165/idna-2.7-py2.py3-none-any.whl",
    
    181
    -                    "sha256": "156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e"
    
    182
    -                }
    
    183
    -            ]
    
    184
    -        },
    
    185
    -        {
    
    186
    -            "name": "python3-cryptography",
    
    187
    -            "ensure-writable": [
    
    188
    -                "easy-install.pth"
    
    189
    -            ],
    
    190
    -            "buildsystem": "simple",
    
    191
    -            "build-commands": [
    
    192
    -                "python3 setup.py install --prefix=/app"
    
    193
    -            ],
    
    194
    -            "sources": [
    
    195
    -                {
    
    196
    -                    "type": "archive",
    
    197
    -                    "url": "https://files.pythonhosted.org/packages/22/21/233e38f74188db94e8451ef6385754a98f3cad9b59bedf3a8e8b14988be4/cryptography-2.3.1.tar.gz",
    
    198
    -                    "sha256": "8d10113ca826a4c29d5b85b2c4e045ffa8bad74fb525ee0eceb1d38d4c70dfd6"
    
    199
    -                }
    
    200
    -            ]
    
    201
    -        },
    
    202
    -        {
    
    203
    -            "name": "python3-pyopenssl",
    
    204
    -            "buildsystem": "simple",
    
    205
    -            "build-commands": [
    
    206
    -                "pip3 install --prefix=/app pyOpenSSL-18.0.0-py2.py3-none-any.whl"
    
    207
    -            ],
    
    208
    -            "sources": [
    
    209
    -                {
    
    210
    -                    "type": "file",
    
    211
    -                    "url": "https://files.pythonhosted.org/packages/96/af/9d29e6bd40823061aea2e0574ccb2fcf72bfd6130ce53d32773ec375458c/pyOpenSSL-18.0.0-py2.py3-none-any.whl",
    
    212
    -                    "sha256": "26ff56a6b5ecaf3a2a59f132681e2a80afcc76b4f902f612f518f92c2a1bf854"
    
    213
    -                }
    
    214
    -            ]
    
    215
    -        },
    
    216
    -        {
    
    217
    -            "name": "python3-dbus-python",
    
    218
    -            "build-options": {
    
    219
    -                "env": {
    
    220
    -                    "PYTHON_VERSION": "3"
    
    221
    -                }
    
    222
    -            },
    
    223
    -            "sources": [
    
    224
    -                {
    
    225
    -                    "type": "archive",
    
    226
    -                    "url": "https://files.pythonhosted.org/packages/3f/e7/4edb582d1ffd5ac3c84188deea32e960b5c8c0fe1da56ce70224f85ce542/dbus-python-1.2.8.tar.gz",
    
    227
    -                    "sha256": "abf12bbb765e300bf8e2a1b2f32f85949eab06998dbda127952c31cb63957b6f"
    
    228
    -                }
    
    229
    -            ]
    
    230
    -        },
    
    231
    -        {
    
    232
    -            "name": "python3-jeepney",
    
    233
    -            "buildsystem": "simple",
    
    234
    -            "build-commands": [
    
    235
    -                "pip3 install --prefix=/app jeepney-0.3.1-py3-none-any.whl"
    
    236
    -            ],
    
    237
    -            "sources": [
    
    238
    -                {
    
    239
    -                    "type": "file",
    
    240
    -                    "url": "https://files.pythonhosted.org/packages/a9/21/c07060fac57d8d4932ccb19f96b244ff056f13192993d2d1253fb87d6784/jeepney-0.3.1-py3-none-any.whl",
    
    241
    -                    "sha256": "e7b961fe9dfa1ed4c576d3bb2d70a9276dace0e16ebed9da09e4d288fe1d3b2a"
    
    242
    -                }
    
    243
    -            ]
    
    244
    -        },
    
    245
    -        {
    
    246
    -            "name": "python3-secretstorage",
    
    247
    -            "buildsystem": "simple",
    
    248
    -            "build-commands": [
    
    249
    -                "pip3 install --prefix=/app SecretStorage-3.0.1-py3-none-any.whl"
    
    250
    -            ],
    
    251
    -            "sources": [
    
    252
    -                {
    
    253
    -                    "type": "file",
    
    254
    -                    "url": "https://files.pythonhosted.org/packages/f3/40/3cbd8b15c8f98b5c6d2480fb0087b06eb39b87992e61c966775156e1a693/SecretStorage-3.0.1-py3-none-any.whl",
    
    255
    -                    "sha256": "1bbf5b85a718854916d1c151fa33e6f667e3c005e033ea46d4123384d233b137"
    
    256
    -                }
    
    257
    -            ]
    
    258
    -        },
    
    259
    -        {
    
    260
    -            "name": "python3-entrypoints",
    
    261
    -            "buildsystem": "simple",
    
    262
    -            "build-commands": [
    
    263
    -                "pip3 install --prefix=/app entrypoints-0.2.3-py2.py3-none-any.whl"
    
    264
    -            ],
    
    265
    -            "sources": [
    
    266
    -                {
    
    267
    -                    "type": "file",
    
    268
    -                    "url": "https://files.pythonhosted.org/packages/cc/8b/4eefa9b47f1910b3d2081da67726b066e379b04ca897acfe9f92bac56147/entrypoints-0.2.3-py2.py3-none-any.whl",
    
    269
    -                    "sha256": "10ad569bb245e7e2ba425285b9fa3e8178a0dc92fc53b1e1c553805e15a8825b"
    
    270
    -                }
    
    271
    -            ]
    
    272
    -        },
    
    273
    -        {
    
    274
    -            "name": "python3-keyring",
    
    275
    -            "buildsystem": "simple",
    
    276
    -            "build-commands": [
    
    277
    -                "pip3 install --prefix=/app keyring-13.2.1-py2.py3-none-any.whl"
    
    278
    -            ],
    
    279
    -            "sources": [
    
    280
    -                {
    
    281
    -                    "type": "file",
    
    282
    -                    "url": "https://files.pythonhosted.org/packages/88/a8/341fa4686e98bf10289eb4eaea89e8176b93c1e38de52e3c42d9112baae1/keyring-13.2.1-py2.py3-none-any.whl",
    
    283
    -                    "sha256": "6e01954fd3e404820e1fade262ee661974051551ed08c899ffc5e88bb9df288e"
    
    284
    -                }
    
    285
    -            ]
    
    286
    -        },
    
    287
    -        {
    
    288
    -            "name": "python3-cssutils",
    
    289
    -            "buildsystem": "simple",
    
    290
    -            "build-commands": [
    
    291
    -                "pip3 install --prefix=/app cssutils-1.0.2-py3-none-any.whl"
    
    292
    -            ],
    
    293
    -            "sources": [
    
    294
    -                {
    
    295
    -                    "type": "file",
    
    296
    -                    "url": "https://files.pythonhosted.org/packages/6b/15/a9fb9010f58d1c55dd0b7779db2334feb9a572d407024f39a60f44293861/cssutils-1.0.2-py3-none-any.whl",
    
    297
    -                    "sha256": "c74dbe19c92f5052774eadb15136263548dd013250f1ed1027988e7fef125c8d"
    
    298
    -                }
    
    299
    -            ]
    
    300
    -        },
    
    301
    -        {
    
    302
    -            "name": "gspell",
    
    303
    -            "cleanup": [
    
    304
    -              "/bin"
    
    305
    -            ],
    
    306
    -            "sources": [
    
    307
    -                {
    
    308
    -                    "type": "archive",
    
    309
    -                    "url": "https://download.gnome.org/sources/gspell/1.8/gspell-1.8.1.tar.xz",
    
    310
    -                    "sha256": "819a1d23c7603000e73f5e738bdd284342e0cd345fb0c7650999c31ec741bbe5"
    
    311
    -                }
    
    312
    -            ],
    
    313
    -            "modules": [
    
    314
    -                {
    
    315
    -                    "name": "enchant2",
    
    316
    -                    "cleanup": [
    
    317
    -                      "/bin"
    
    318
    -                    ],
    
    319
    -                    "sources": [
    
    320
    -                        {
    
    321
    -                            "type": "archive",
    
    322
    -                            "url": "https://github.com/AbiWord/enchant/releases/download/v2.2.3/enchant-2.2.3.tar.gz",
    
    323
    -                            "sha256": "abd8e915675cff54c0d4da5029d95c528362266557c61c7149d53fa069b8076d"
    
    324
    -                        }
    
    325
    -                    ]
    
    326
    -                }
    
    327
    -            ]
    
    328
    -        },
    
    329
    -        {
    
    330
    -            "name": "python3-nbxmpp",
    
    331
    -            "buildsystem": "simple",
    
    332
    -            "build-commands": [
    
    333
    -                "python3 setup.py install --prefix=/app"
    
    334
    -            ],
    
    335
    -            "sources": [
    
    336
    -                {
    
    337
    -                    "type": "archive",
    
    338
    -                    "url": "https://files.pythonhosted.org/packages/b2/2d/680b61de01eaaadfe1b57fe8a21cdfbce63fe51d36d3bf48b0dca5e14c57/nbxmpp-0.6.7.tar.gz",
    
    339
    -                    "sha256": "5b291d9604854b611479657867e2d5118b65f0e58280bcd19fb539c955245a39"
    
    340
    -                }
    
    341
    -            ]
    
    342
    -        },
    
    343
    -        {
    
    344
    -            "name": "gajim",
    
    345
    -            "buildsystem": "simple",
    
    346
    -            "build-commands": [
    
    347
    -                "pip3 install --prefix=/app .",
    
    348
    -                "touch /app/share/run-as-flatpak"
    
    349
    -            ],
    
    350
    -            "sources": [
    
    351
    -                {
    
    352
    -                    "type": "git",
    
    353
    -                    "url": "https://dev.gajim.org/gajim/gajim.git"
    
    354
    -                }
    
    355
    -            ],
    
    356
    -            "post-install": [
    
    357
    -                "install -d /app/plugins"
    
    358
    -            ]
    
    359
    -        }
    
    360
    -    ]
    
    361
    -}