Compare commits
10 Commits
813cbee528
...
780df43c83
Author | SHA1 | Date |
---|---|---|
Xavier Del Campo Romero | 780df43c83 | |
Xavier Del Campo Romero | 38b075873f | |
Xavier Del Campo Romero | 2e5f9c5ba2 | |
Xavier Del Campo Romero | 1aaafc1af4 | |
Xavier Del Campo Romero | 45b74d9a4b | |
Xavier Del Campo Romero | f01dd81c73 | |
Xavier Del Campo Romero | 7a31d74581 | |
Xavier Del Campo Romero | a9d1b5fb43 | |
Xavier Del Campo Romero | 6a152d4e4c | |
Xavier Del Campo Romero | 12cf6ada70 |
|
@ -0,0 +1,343 @@
|
|||
This fork of Dino diverged from upstream on this commit:
|
||||
|
||||
f25bfb00969a7e09996da2d5500e6718f4cc0148
|
||||
|
||||
However, this fork of Dino aims to backport all compatible security
|
||||
fixes and improvements from upstream. This is an exhaustive list of
|
||||
every commit that was reviewed and its status, plus additional
|
||||
comments:
|
||||
|
||||
7e7dcedaf31ee35499875491c9f569c575d28435: Not applied.
|
||||
As its commit message suggests, this commit ported Dino from GTK3 to
|
||||
GTK4, but this fork will keep using GTK3 as a requirement.
|
||||
|
||||
2b3ce5fc95c63ed7d54e207db0585c8b8bbcd603: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
|
||||
f44cbe02c17df1f02ad49c63cd784fec0ea02d85: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
|
||||
e51b55432fe98e0fbc036fe785ef50fbf1589034: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
|
||||
0af92393f134c59646deaab7d963a32c0d3d58b2: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
|
||||
517363dfc9dab81c4b59310c739bcf71266fabe0: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
|
||||
6bfa70fc7045669be435d3757456e1da7d341927: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
|
||||
5103a7fb7b32fcee6656dbae0eec54fb26f89d80: Not applied.
|
||||
The resource tree for Dino got changed during the GTK4 port, including
|
||||
some icons. However, this commit is not needed for this fork.
|
||||
|
||||
7b252d040a845b7e9c515f61927fbf5bf7ed4c3a: Partially applied.
|
||||
However, it had to be slightly adapted to the dependencies as listed
|
||||
by our version of plugins/rtp/CMakeLists.txt.
|
||||
|
||||
d6afa6e8ff4cfb533140d9434b83f18f627f11ca: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
|
||||
054d3fec1627a9ee8d84d636d578aa68d3494d19: Not applied.
|
||||
None of these changes seem required or seem to fix anything in our
|
||||
fork.
|
||||
|
||||
e85477bb19166e742e34852b2a99b33e55565ded: Not applied.
|
||||
I am unsure whether this commit would break anything, and so far I had
|
||||
no problems on 0.56.0, which is older than 0.56.1.
|
||||
Also, these changes were introduced by the change from GTK3 to GTK4.
|
||||
Some further reference: https://github.com/dino/dino/pull/1234.
|
||||
|
||||
0aa73c4569a90031d8a88173f8689c18d02ddbe2: Not applied.
|
||||
Because of the same reasons as e85477bb19166e742e34852b2a99b33e55565ded.
|
||||
|
||||
14bc3d6717515e0b34b02ef5b5ad4c3ec52ccdc2: Not applied.
|
||||
This is regression introduced by
|
||||
f44cbe02c17df1f02ad49c63cd784fec0ea02d85, which was part of the effort
|
||||
to port Dino to GTK4.
|
||||
|
||||
117f19381233207e4b5aef03c82e7dd4b2d1debd: Not applied.
|
||||
Again, these look like regressions introduced with the migration to
|
||||
GTK4.
|
||||
|
||||
b8e84c83268a11ae41ad1d673999362427fd755c: Applied.
|
||||
|
||||
7ad52d9335579d03613036a7da9967fcf0c5d6b3: Not applied.
|
||||
This commit looks incompatible with GTK3, but I might be wrong.
|
||||
|
||||
146af3152475f12c9b19a92c4779a53f6fc517ce: Not applied.
|
||||
Some resources were moved when porting Dino to GTK4, but this does not
|
||||
apply to our fork.
|
||||
|
||||
21ab48e09aa6b0ade8f25bdc93f89f8d3aa462e7: Not applied.
|
||||
It looks like this is trying to solve a regression introduced during
|
||||
the migration from GTK3 to GTK4, as the calls to
|
||||
jid_entry.key_release_event.connect() and
|
||||
nick_entry.key_release_event.connect() are not commented out on this
|
||||
fork.
|
||||
|
||||
85342ee2eb2aa3e6d7599c503d17c00d861bafcb: Not applied.
|
||||
Drag and drop uploading always forked for this fork.
|
||||
|
||||
03878eee495cac8dcc8baf0ff4f84e4c9e76114e: Not applied.
|
||||
These were disabled during the migration from GTK3 to GTK4, so this
|
||||
commit does not apply to this fork.
|
||||
|
||||
7d8b08deca0aa4eb24def6b9af4ec180c0bc9a27: Partially applied.
|
||||
Whereas the changes on list_row.ui caused many conflicts, the null
|
||||
check on conversation_view_controller.vala is required.
|
||||
|
||||
9c736af765d8c62838440afbfd2ad7ee78b44951: Not applied.
|
||||
check_if_done() was introduced by
|
||||
21ab48e09aa6b0ade8f25bdc93f89f8d3aa462e7, which was not applied,
|
||||
either.
|
||||
|
||||
6c6e7e3aa7935ec513b7e5ea9b53a92b741ecf92: Partially applied.
|
||||
Almost everything could be cleanly backported, except from
|
||||
main/src/ui/add_conversation/conference_list.vala, where the original
|
||||
implementation was preferred.
|
||||
|
||||
80258a874ddfeb87b4b71f5791eab94a2465de6d: Not applied.
|
||||
I have no personal interest in XMPP reactions for this fork, as other
|
||||
popular XMPP clients such as Conversations are still rely on styling as
|
||||
described on https://xmpp.org/extensions/xep-0393.html#quote.
|
||||
|
||||
bc5a1d35cbf5c1aca406fa0fe81ca60d6b280bd5: Applied.
|
||||
|
||||
7e0d1db1965555720db2bef7380e61c23ef6dbcd: Applied.
|
||||
|
||||
f82f788f43e385391db2827cde151830fc91bc14: Applied.
|
||||
|
||||
1bf57a42fa5c36977132d21f59ca6637fcd0c3d3: Applied.
|
||||
|
||||
11b6e615b73e4183a06f9d456634c44ead612336: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
|
||||
09829b33824ab7d1fbf9886b7ed3e42cd8c34ff2: Not applied.
|
||||
This commit fixes a regression introduced by
|
||||
80258a874ddfeb87b4b71f5791eab94a2465de6d, which is related to
|
||||
reactions, something this fork does not implement.
|
||||
|
||||
a45280f8dfe45f8908b44cd13996316af44117e9: Not applied.
|
||||
This commit is related to reactions, which this fork does not
|
||||
implement.
|
||||
|
||||
2ab7374aa53f70b30765a02865d92e6d71c6e623: Not applied.
|
||||
This commit is related to reactions, which this fork does not
|
||||
implement.
|
||||
|
||||
a2f2224781a82121c86a1f19b309245bc8369a91: Applied.
|
||||
|
||||
809c1579e41000f2f43eeb05735afc8165a1a430: Applied.
|
||||
According to the commit message, the changes introduced by this commit
|
||||
were meant for libsoup3 only. However, the commit did not wrap the
|
||||
libsoup3-specific in #if SOUP_3, so this has been added for this
|
||||
fork.
|
||||
|
||||
6e37f3fe3fa0f4ce9a25a91e9d97191c8e4abec1: Applied.
|
||||
|
||||
e62955d3cf266a7f7ff0f2085a64f1c99021127c: Applied.
|
||||
|
||||
7a19a25156a73e7e6b6d77fabc7621e7d2c443f0: Partially applied.
|
||||
The changes to libdino/src/service/reactions.vala are out of scope for
|
||||
this fork.
|
||||
|
||||
a2e894dda132f1679ee8e9998879be6bda7ab320: Applied.
|
||||
|
||||
cdd22e404eca3db640b6f2f2789314f7cbb65de6: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
|
||||
d1fb22ebedca7dbbbd0f693baa3c38d99ab5c344: Not applied.
|
||||
This commit is related to reactions, which this fork does not
|
||||
implement.
|
||||
|
||||
4d50c51a75de70c0f30a196e1f128154ba1651fa: Applied.
|
||||
|
||||
30f99d1347f8f5e2db364a25910d76b0faf2ea36: Applied.
|
||||
|
||||
799d09a4c98d1a00790f261600d3f4d813140954: Applied.
|
||||
|
||||
4d7809bb12199a598b531ca3ca019a4bb5a867f7: Partially applied.
|
||||
- Too many changes are introduced to
|
||||
main/src/ui/chat_input/encryption_button.vala, which might break this
|
||||
fork.
|
||||
- Changes related to own_occupant_ids are
|
||||
related to reactions (as introduced by
|
||||
80258a874ddfeb87b4b71f5791eab94a2465de6d), and thus are out of scope
|
||||
for this fork.
|
||||
- This commit removes plugins/omemo/src/ui/manage_key_dialog.vala, which
|
||||
this fork still relies on.
|
||||
- headerbar is still used by plugins/omemo/src/ui/manage_key_dialog.vala,
|
||||
and thus should not be removed.
|
||||
- Too many changes are introduced to
|
||||
main/src/ui/conversation_content_view/conversation_item_skeleton.vala,
|
||||
which might break this fork.
|
||||
- The changes in
|
||||
main/src/ui/conversation_content_view/conversation_view.vala break
|
||||
the build.
|
||||
- The changes in
|
||||
main/src/ui/conversation_view_controller.vala break the build.
|
||||
|
||||
dc52e7595cca06d0a2da7d11b3c88cb2f7ce529c: Not applied.
|
||||
I am not interested in XEP-0461 (replies) for this fork, as the
|
||||
fallback implementations is already provided here.
|
||||
|
||||
60371331e0882758b0b9c2efedb3821e716defd7: Not applied.
|
||||
Replies are out of scope for this fork.
|
||||
|
||||
424a4290622246303a7b73410d7e4a5a6d57dd6b: Not applied.
|
||||
Replies are out of scope for this fork.
|
||||
|
||||
0c4aea96ffbc05d6efeb9a83424b872ce7f30d88: Not applied.
|
||||
Replies are out of scope for this fork.
|
||||
|
||||
cb3b19b01deb8460627578b885339e7528411f6f: Not applied.
|
||||
Replies are out of scope for this fork.
|
||||
|
||||
75500dc767f2cf657c0fbb5d2a4d4557183ed2e9: Not applied.
|
||||
This commit breaks the build in some places, and I am not particulary
|
||||
interested in conversation pinning anyway.
|
||||
|
||||
860c72bfc93d252d45eb97e71cf9ff22985c7ef9: Not applied.
|
||||
This commit fixes regressions introduced by other commits that were not
|
||||
introduced by this fork, such as
|
||||
7e7dcedaf31ee35499875491c9f569c575d28435.
|
||||
|
||||
73c0263f35a73b68d20d299ee7fe8c37b9a6ffeb: Not applied.
|
||||
This commit depends on other commits that were not introduced by this
|
||||
fork, such as cb3b19b01deb8460627578b885339e7528411f6f, which was
|
||||
related to replies (not implemented by this fork).
|
||||
|
||||
05289e0b4dc9bc076955e27b30b386cb7f0604c7: Not applied.
|
||||
Replies are out of scope for this fork.
|
||||
|
||||
7da79864b384c9370a5937d480230e771834d91a: Not applied.
|
||||
Conversation pinning is out of scope for this fork.
|
||||
|
||||
7e0d1db1965555720db2bef7380e61c23ef6dbcd: Applied.
|
||||
|
||||
f6e73d85c00a60a719da95a048ba2c15712325c3: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
|
||||
1ef42b47d22d21600ccf1e2d8b4d80605448660d: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
|
||||
2741bf21ae6d53324a512dacef65d540be840fe4: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
|
||||
ba9462503c0561dbe8306e3bf6aa49392bfc8078: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
|
||||
04acab82c98f5d9cdb798ba3baac8d73b097b1df: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
|
||||
e934a76a1139938ae668836b812102cd5d9c9d9f: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
Also, this fork already has a back button for ConversationTitleBar.
|
||||
|
||||
0d7c8bb6e117f8cdd631730302413aad21632c2d: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
|
||||
92aca5672db723121471e513e83b68742761d1b5: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
|
||||
4b391f3f31c2272be11a24c8301641b045260e99: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
|
||||
ef98adb18a016dba65162602eb336fb82c64805e: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
|
||||
6a182ba313026b93d54a9d2246a0ab68894c6833: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
|
||||
99d9cb383abb1a33f6d0572deb4292dbf358f3ce: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
|
||||
cc7db3b85f7b29bfac333937d8bf09a81d8dc4a5: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
|
||||
e35df88d4a00c3a34f2b4d9fb7f10bb5d877bd29: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
|
||||
26be9d4bb40b223cb8a657b03e6457988a8cc269: Not applied.
|
||||
Reactions are out of scope for this fork.
|
||||
|
||||
5d9978b38bb0e729dcccecddd08cc59e5585a6cc: Not applied.
|
||||
Reactions are out of scope for this fork.
|
||||
|
||||
c813a6d2405980c71450cefa10abdf11fab8e995: Not applied.
|
||||
GTK4-related changes are out of scope for this fork.
|
||||
|
||||
e833a924b5a66048506b4e0b0885ce2e35cac6fc: Applied.
|
||||
|
||||
e833a924b5a66048506b4e0b0885ce2e35cac6fc: Applied.
|
||||
|
||||
04eb0e763b0e02ea1bc698f1ccb24f84b0154010: Not applied.
|
||||
This commit is way too big to merge and is tighly coupled to upstream
|
||||
source code. Maybe a similar commit can be provided independently.
|
||||
|
||||
d0a00e1e7549609f7d83e7b432f7f547a1fcebb0: Applied.
|
||||
|
||||
1dbacbbcab139d0f8036446441ad143ef7e7eb30: Applied.
|
||||
|
||||
10a2bce5122dcd1e6fef037633a26568bf27d4d1: Applied.
|
||||
|
||||
b0b81b88c6948dcfd2b1b82a9fe7357316a3af1f: Not applied.
|
||||
Both reactions and replies are out of scope for this fork.
|
||||
|
||||
e3c833bce0713e9a0290841306c7727dfc1e3860: Applied.
|
||||
This fork defines different logic for update_received_mark(), so the
|
||||
commit was adapted to it.
|
||||
|
||||
1e23b7bbd2a66e5ff40ae5fc5aa6523fa604f242: Not applied.
|
||||
Replies are out of scope for this fork.
|
||||
|
||||
9e11bef219880b5bdc5d299c31ec6249596a86ba: Not applied.
|
||||
string_if_tooltips_active() was added by
|
||||
6bfa70fc7045669be435d3757456e1da7d341927, which is GTK4-related.
|
||||
|
||||
921f28c84bbda56ec93df7dcde7c828eaabb0b58: Not applied.
|
||||
Reactions are out of scope for this fork.
|
||||
|
||||
3aa3912dc3ea740a5b93f8b694ead45e1b655238: Not applied.
|
||||
main/src/ui/widgets/date_separator.vala depends on GTK4 libadwaita.
|
||||
|
||||
e0ece2aa62aa6b8350be83c787ea003a75f07437: Partially applied.
|
||||
The changes to main/data/unified_main_content.ui and
|
||||
main/src/ui/conversation_selector/conversation_selector.vala depend on
|
||||
other commits related to GTK4 and libadwaita.
|
||||
|
||||
95fefaff51e5506d3f0e5fe8bced14aeb3fbe037: Applied.
|
||||
|
||||
18321ed15ce782ff5d1f24de9f2fb459d714d125: Partially applied.
|
||||
The changes to libdino/src/service/reactions.vala and
|
||||
xmpp-vala/src/module/xep/0444_reactions.vala are not relevant to this
|
||||
fork.
|
||||
|
||||
d76e12b215eb62e4eda5a0f92fbf5c1bd7c1848e: Applied.
|
||||
|
||||
f74c1f18b12df0d650f74b6fa43b7f2f0a9bce79: Applied.
|
||||
|
||||
1d123c7e66d963fd8cc8cc4250b5813a62676f56: Applied.
|
||||
|
||||
d092473fe401a5a668e57f054efbd1e84ac6ca59: Applied.
|
||||
|
||||
1559a7a60370c2aa0203e5c4222def4ae3258006: Applied.
|
||||
|
||||
32ae87a3c4cebaa05e0e702d744900cd414000db: Not applied.
|
||||
Seems to cause many conflicts while providing little benefit.
|
||||
|
||||
116682e311edca6665a0497c8b225b4fe69859a7: Partially applied.
|
||||
Changes to main/src/ui/conversation_content_view/quote_widget.vala are
|
||||
not relevant to this fork.
|
||||
|
||||
9c5e36020d8997452d4fd07c5a153e1e7fc24088: Applied.
|
||||
|
||||
e73b556a1ae5ea4af41c610f7b05545cf60d59c4: Not applied.
|
||||
This commit is way too big to merge and is tighly coupled to upstream
|
||||
source code. Maybe a similar commit can be provided independently.
|
||||
|
||||
5568bbc6bf505c4f8ea93fc460dbeff6f4d36e15: Partially applied.
|
||||
Changes related to libadwaita are out of scope for this fork.
|
15
README.md
15
README.md
|
@ -1,10 +1,21 @@
|
|||
# An unbranded Dino fork
|
||||
|
||||
## Screenshots
|
||||
|
||||
![Screenshot showing mobile form factor and OMEMO-by-default support](doc/screenshot-2.png)
|
||||
|
||||
![Screenshot showing a MUC room in desktip form factor](doc/screenshot-1.png)
|
||||
|
||||
## Features
|
||||
|
||||
- **OMEMO encryption set by default**.
|
||||
- Portrait screen support with `libhandy`.
|
||||
- Improved [`connection_manager.vala`](libdino/src/service/connection_manager.vala).
|
||||
- Quote messages according to XEP-0393 Message Styling.
|
||||
- Copy messages.
|
||||
- Optional send button and Enter-to-send accelerator.
|
||||
- Keeps using GTK3.
|
||||
- Includes some features that did not make into upstream.
|
||||
- Backports bugfixes and improvements from upstream.
|
||||
- Backports bugfixes and improvements from upstream (see [`BACKPORT`](BACKPORT)).
|
||||
|
||||
## TODO
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 77 KiB |
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
|
@ -3,7 +3,7 @@ using Xmpp;
|
|||
namespace Dino.Entities {
|
||||
|
||||
public class FileTransfer : Object {
|
||||
|
||||
public signal void progress_updated(int progress);
|
||||
public const bool DIRECTION_SENT = true;
|
||||
public const bool DIRECTION_RECEIVED = false;
|
||||
|
||||
|
@ -70,6 +70,14 @@ public class FileTransfer : Object {
|
|||
public State state { get; set; default=State.NOT_STARTED; }
|
||||
public int provider { get; set; }
|
||||
public string info { get; set; }
|
||||
public int progress_ { get; set; }
|
||||
public int progress {
|
||||
get {return progress_;}
|
||||
set {
|
||||
progress_ = value;
|
||||
progress_updated(progress_);
|
||||
}
|
||||
}
|
||||
public Cancellable cancellable { get; default=new Cancellable(); }
|
||||
|
||||
private Database? db;
|
||||
|
@ -103,6 +111,7 @@ public class FileTransfer : Object {
|
|||
state = (State) row[db.file_transfer.state];
|
||||
provider = row[db.file_transfer.provider];
|
||||
info = row[db.file_transfer.info];
|
||||
progress = row[db.file_transfer.progress];
|
||||
|
||||
notify.connect(on_update);
|
||||
}
|
||||
|
@ -124,7 +133,8 @@ public class FileTransfer : Object {
|
|||
.value(db.file_transfer.size, size)
|
||||
.value(db.file_transfer.state, state)
|
||||
.value(db.file_transfer.provider, provider)
|
||||
.value(db.file_transfer.info, info);
|
||||
.value(db.file_transfer.info, info)
|
||||
.value(db.file_transfer.progress, progress);
|
||||
|
||||
if (file_name != null) builder.value(db.file_transfer.file_name, file_name);
|
||||
if (path != null) builder.value(db.file_transfer.path, path);
|
||||
|
@ -169,6 +179,8 @@ public class FileTransfer : Object {
|
|||
update_builder.set(db.file_transfer.provider, provider); break;
|
||||
case "info":
|
||||
update_builder.set(db.file_transfer.info, info); break;
|
||||
case "progress":
|
||||
update_builder.set(db.file_transfer.progress, progress); break;
|
||||
}
|
||||
update_builder.perform();
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ public class Settings : Object {
|
|||
default_encryption = col_to_encryption_or_default("default_encryption", Encryption.OMEMO);
|
||||
send_button = col_to_bool_or_default("send_button", false);
|
||||
enter_newline = col_to_bool_or_default("enter_newline", false);
|
||||
quit_ctrl_q = col_to_bool_or_default("quit_ctrl_q", true);
|
||||
}
|
||||
|
||||
private bool col_to_bool_or_default(string key, bool def) {
|
||||
|
@ -126,6 +127,20 @@ public class Settings : Object {
|
|||
enter_newline_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
public signal void quit_ctrl_q_update(bool active);
|
||||
private bool quit_ctrl_q_;
|
||||
public bool quit_ctrl_q {
|
||||
get { return quit_ctrl_q_; }
|
||||
set {
|
||||
db.settings.upsert()
|
||||
.value(db.settings.key, "quit_ctrl_q", true)
|
||||
.value(db.settings.value, value.to_string())
|
||||
.perform();
|
||||
quit_ctrl_q_ = value;
|
||||
quit_ctrl_q_update(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -252,11 +252,32 @@ public class ConnectionManager : Object {
|
|||
}
|
||||
}
|
||||
|
||||
private void check_ping_reconnect(Xmpp.Xep.Ping.Module identity,
|
||||
XmppStream stream, Account account) {
|
||||
identity.send_ping.begin(stream, account.bare_jid.domain_jid, () => {
|
||||
connections[account].acked = true;
|
||||
if (connections[account].stream != stream) return;
|
||||
connect_stream.begin(account);
|
||||
});
|
||||
|
||||
Timeout.add_seconds(10, () => {
|
||||
if (!connections.has_key(account)) return false;
|
||||
if (connections[account].stream != stream) return false;
|
||||
if (connections[account].acked) return false;
|
||||
|
||||
// Reconnect. Nothing gets through the stream.
|
||||
debug("[%s %p] Ping timeouted. Reconnecting", account.bare_jid.to_string(), stream);
|
||||
change_connection_state(account, ConnectionState.DISCONNECTED);
|
||||
|
||||
connections[account].reset();
|
||||
connect_stream.begin(account);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
private void check_reconnect(Account account, bool directly_reconnect = false) {
|
||||
if (!connections.has_key(account)) return;
|
||||
|
||||
XmppStream? stream = connections[account].stream;
|
||||
|
||||
var cancellable = new Cancellable();
|
||||
debug(@"account.domainpart=$(account.domainpart)");
|
||||
|
||||
|
@ -267,29 +288,23 @@ public class ConnectionManager : Object {
|
|||
debug(@"can-reach: $(reachable)");
|
||||
|
||||
if (reachable) {
|
||||
Xmpp.Xep.Ping.Module? identity = null;
|
||||
if (connections[account].connection_state == ConnectionState.CONNECTING) return;
|
||||
|
||||
XmppStream? stream = connections[account].stream;
|
||||
connections[account].acked = false;
|
||||
change_connection_state(account, ConnectionState.CONNECTING);
|
||||
|
||||
stream.get_module(Xep.Ping.Module.IDENTITY).send_ping.begin(stream, account.bare_jid.domain_jid, () => {
|
||||
connections[account].acked = true;
|
||||
if (connections[account].stream != stream) return;
|
||||
change_connection_state(account, ConnectionState.CONNECTED);
|
||||
});
|
||||
|
||||
Timeout.add_seconds(10, () => {
|
||||
if (!connections.has_key(account)) return false;
|
||||
if (connections[account].stream != stream) return false;
|
||||
if (connections[account].acked) return false;
|
||||
|
||||
// Reconnect. Nothing gets through the stream.
|
||||
debug("[%s %p] Ping timeouted. Reconnecting", account.bare_jid.to_string(), stream);
|
||||
if (stream != null
|
||||
&& (identity = stream.get_module(Xep.Ping.Module.IDENTITY)) != null) {
|
||||
change_connection_state(account, ConnectionState.CONNECTING);
|
||||
check_ping_reconnect(identity, stream, account);
|
||||
}
|
||||
else {
|
||||
change_connection_state(account, ConnectionState.DISCONNECTED);
|
||||
|
||||
connections[account].reset();
|
||||
connect_stream.begin(account);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Error e) {
|
||||
|
|
|
@ -147,11 +147,12 @@ public class Database : Qlite.Database {
|
|||
public Column<int> state = new Column.Integer("state");
|
||||
public Column<int> provider = new Column.Integer("provider");
|
||||
public Column<string> info = new Column.Text("info");
|
||||
public Column<int> progress = new Column.Integer("progress");
|
||||
|
||||
internal FileTransferTable(Database db) {
|
||||
base(db, "file_transfer");
|
||||
init({id, account_id, counterpart_id, counterpart_resource, our_resource, direction, time, local_time,
|
||||
encryption, file_name, path, mime_type, size, state, provider, info});
|
||||
encryption, file_name, path, mime_type, size, state, provider, info, progress});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -119,7 +119,19 @@ public class FileManager : StreamInteractionModule, Object {
|
|||
file_send_data = file_encryptor.preprocess_send_file(conversation, file_transfer, file_send_data, file_meta);
|
||||
}
|
||||
|
||||
size_t sent_bytes = 0;
|
||||
|
||||
file_sender.progress.connect((length) => {
|
||||
if (file_transfer.size != 0) {
|
||||
sent_bytes += length;
|
||||
file_transfer.progress =
|
||||
(int)(((uint64)sent_bytes * (uint64)100)
|
||||
/ (uint64)file_transfer.size);
|
||||
debug(@"length=$(length), sent_bytes=$(sent_bytes), progress=$(file_transfer.progress)");
|
||||
}
|
||||
});
|
||||
yield file_sender.send_file(conversation, file_transfer, file_send_data, file_meta);
|
||||
file_transfer.state = FileTransfer.State.COMPLETE;
|
||||
|
||||
} catch (Error e) {
|
||||
warning("Send file error: %s", e.message);
|
||||
|
@ -292,6 +304,7 @@ public class FileManager : StreamInteractionModule, Object {
|
|||
file_transfer.file_name = file_meta.file_name;
|
||||
file_transfer.size = (int)file_meta.size;
|
||||
file_transfer.info = info;
|
||||
file_transfer.progress = 0;
|
||||
|
||||
var encryption = file_provider.get_encryption(file_transfer, receive_data, file_meta);
|
||||
if (encryption != Encryption.NONE) file_transfer.encryption = encryption;
|
||||
|
@ -328,7 +341,7 @@ public class FileManager : StreamInteractionModule, Object {
|
|||
File file = File.new_for_path(Path.build_filename(get_storage_dir(), filename));
|
||||
OutputStream os = file.create(FileCreateFlags.REPLACE_DESTINATION);
|
||||
yield os.splice_async(file_transfer.input_stream, OutputStreamSpliceFlags.CLOSE_SOURCE|OutputStreamSpliceFlags.CLOSE_TARGET);
|
||||
file_transfer.state = FileTransfer.State.COMPLETE;
|
||||
file_transfer.state = FileTransfer.State.IN_PROGRESS;
|
||||
file_transfer.path = filename;
|
||||
file_transfer.input_stream = yield file.read_async();
|
||||
} catch (Error e) {
|
||||
|
@ -391,6 +404,7 @@ public interface FileProvider : Object {
|
|||
|
||||
public interface FileSender : Object {
|
||||
public signal void upload_available(Account account);
|
||||
public signal void progress(size_t length);
|
||||
|
||||
public abstract async bool is_upload_available(Conversation conversation);
|
||||
public abstract async long get_file_size_limit(Conversation conversation);
|
||||
|
|
|
@ -537,7 +537,6 @@ public class Dino.HistorySync {
|
|||
if (to_delete.contains(range1)) continue;
|
||||
|
||||
foreach (MamRange range2 in ranges[server_jid]) {
|
||||
debug("[%s | %s] | %s - %s vs %s - %s", account.bare_jid.to_string(), server_jid.to_string(), range1.from_time.to_string(), range1.to_time.to_string(), range2.from_time.to_string(), range2.to_time.to_string());
|
||||
if (range1 == range2 || to_delete.contains(range2)) continue;
|
||||
|
||||
// Check if range2 is a subset of range1
|
||||
|
|
|
@ -172,6 +172,18 @@
|
|||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="quit_ctrl_q_checkbutton">
|
||||
<property name="label" translatable="yes">Quit Dino with Ctrl+Q</property>
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">8</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
|
@ -117,6 +117,8 @@ public class Dino.Ui.Application : Gtk.Application, Dino.Application {
|
|||
}
|
||||
|
||||
private void create_actions() {
|
||||
Dino.Entities.Settings settings = Dino.Application.get_default().settings;
|
||||
|
||||
SimpleAction accounts_action = new SimpleAction("accounts", null);
|
||||
accounts_action.activate.connect(show_accounts_window);
|
||||
add_action(accounts_action);
|
||||
|
@ -132,7 +134,20 @@ public class Dino.Ui.Application : Gtk.Application, Dino.Application {
|
|||
SimpleAction quit_action = new SimpleAction("quit", null);
|
||||
quit_action.activate.connect(quit);
|
||||
add_action(quit_action);
|
||||
set_accels_for_action("app.quit", KEY_COMBINATION_QUIT);
|
||||
|
||||
if (settings.quit_ctrl_q) {
|
||||
set_accels_for_action("app.quit", KEY_COMBINATION_QUIT);
|
||||
}
|
||||
|
||||
settings.quit_ctrl_q_update.connect((active) =>
|
||||
{
|
||||
if (active) {
|
||||
set_accels_for_action("app.quit", KEY_COMBINATION_QUIT);
|
||||
}
|
||||
else {
|
||||
set_accels_for_action("app.quit", {null});
|
||||
}
|
||||
});
|
||||
|
||||
SimpleAction open_conversation_action = new SimpleAction("open-conversation", VariantType.INT32);
|
||||
open_conversation_action.activate.connect((variant) => {
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace Dino.Ui.ConversationSummary {
|
|||
public class ConversationView : Box, Plugins.ConversationItemCollection, Plugins.NotificationCollection {
|
||||
|
||||
public signal void on_quote_text(string text);
|
||||
public signal void on_copy_text(string text);
|
||||
public Conversation? conversation { get; private set; }
|
||||
|
||||
[GtkChild] public unowned ScrolledWindow scrolled;
|
||||
|
@ -330,6 +331,7 @@ public class ConversationView : Box, Plugins.ConversationItemCollection, Plugins
|
|||
|
||||
MessageMetaItem current_item = item as MessageMetaItem;
|
||||
current_item.on_quote_text.connect((t, text) => on_quote_text(text));
|
||||
current_item.on_copy_text.connect((t, text) => on_copy_text(text));
|
||||
}
|
||||
meta_items.add(item);
|
||||
}
|
||||
|
|
|
@ -31,7 +31,8 @@ public class FileDefaultWidget : EventBox {
|
|||
cancel_button = new ModelButton() { text=_("Cancel"), visible=true };
|
||||
}
|
||||
|
||||
public void update_file_info(string? mime_type, FileTransfer.State state, long size) {
|
||||
public void update_file_info(string? mime_type, int progress,
|
||||
bool direction, FileTransfer.State state, long size) {
|
||||
this.state = state;
|
||||
|
||||
spinner.active = false; // A hidden spinning spinner still uses CPU. Deactivate asap
|
||||
|
@ -58,7 +59,12 @@ public class FileDefaultWidget : EventBox {
|
|||
popover_menu.closed.connect(on_pointer_left);
|
||||
break;
|
||||
case FileTransfer.State.IN_PROGRESS:
|
||||
mime_label.label = _("Downloading %s…").printf(get_size_string(size));
|
||||
if (direction == FileTransfer.DIRECTION_SENT) {
|
||||
mime_label.label = _("Uploading %s (%d%%)…").printf(get_size_string(size), progress);
|
||||
}
|
||||
else {
|
||||
mime_label.label = _("Downloading %s (%d)…").printf(get_size_string(size), progress);
|
||||
}
|
||||
spinner.active = true;
|
||||
image_stack.set_visible_child_name("spinner");
|
||||
|
||||
|
|
|
@ -148,6 +148,7 @@ public class FileDefaultWidgetController : Object {
|
|||
this.notify["file-transfer-state"].connect(update_file_info);
|
||||
this.notify["file-transfer-mime-type"].connect(update_file_info);
|
||||
|
||||
file_transfer.progress_updated.connect(update_file_info);
|
||||
update_file_info();
|
||||
}
|
||||
|
||||
|
@ -155,13 +156,15 @@ public class FileDefaultWidgetController : Object {
|
|||
file_uri = file.get_uri();
|
||||
state = FileTransfer.State.COMPLETE;
|
||||
widget.name_label.label = this.file_name = file_name;
|
||||
widget.update_file_info(mime_type, state, -1);
|
||||
widget.update_file_info(mime_type, 0, false, state, -1);
|
||||
}
|
||||
|
||||
private void update_file_info() {
|
||||
file_uri = file_transfer.get_file().get_uri();
|
||||
state = file_transfer.state;
|
||||
widget.update_file_info(file_transfer.mime_type, file_transfer.state, file_transfer.size);
|
||||
widget.update_file_info(file_transfer.mime_type,
|
||||
file_transfer.progress,
|
||||
file_transfer.direction, file_transfer.state, file_transfer.size);
|
||||
}
|
||||
|
||||
private void open_file() {
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace Dino.Ui.ConversationSummary {
|
|||
public class MessageMetaItem : ContentMetaItem {
|
||||
|
||||
public signal void on_quote_text(string text);
|
||||
public signal void on_copy_text(string text);
|
||||
private StreamInteractor stream_interactor;
|
||||
private MessageItemWidget message_item_widget;
|
||||
private MessageItem message_item;
|
||||
|
@ -56,6 +57,14 @@ public class MessageMetaItem : ContentMetaItem {
|
|||
};
|
||||
actions.add(action2);
|
||||
|
||||
Plugins.MessageAction copy_action = new Plugins.MessageAction();
|
||||
copy_action.icon_name = "edit-copy";
|
||||
copy_action.callback = (button, content_meta_item_activated, widget) => {
|
||||
string text = ((MessageItem) message_item_widget.content_item).message.body;
|
||||
on_copy_text(text);
|
||||
};
|
||||
actions.add(copy_action);
|
||||
|
||||
if (allowed && !in_edit_mode) {
|
||||
Plugins.MessageAction action1 = new Plugins.MessageAction();
|
||||
action1.icon_name = "document-edit-symbolic";
|
||||
|
|
|
@ -14,10 +14,12 @@ public class ConversationView : Gtk.Overlay {
|
|||
[GtkChild] public unowned ChatInput.View chat_input;
|
||||
[GtkChild] public unowned ConversationSummary.ConversationView conversation_frame;
|
||||
[GtkChild] public unowned Revealer white_revealer;
|
||||
public signal void copy_text(string text);
|
||||
|
||||
construct {
|
||||
white_revealer.notify["child-revealed"].connect_after(on_child_revealed_changed);
|
||||
conversation_frame.on_quote_text.connect((t, text) => on_quote_text(text));
|
||||
conversation_frame.on_copy_text.connect((t, text) => copy_text(text));
|
||||
}
|
||||
|
||||
public void on_quote_text(string text) {
|
||||
|
|
|
@ -74,7 +74,8 @@ public class FileSendOverlay : Gtk.EventBox {
|
|||
if (widget == null) {
|
||||
FileDefaultWidget default_widget = new FileDefaultWidget() { visible=true };
|
||||
default_widget.name_label.label = file_name;
|
||||
default_widget.update_file_info(mime_type, FileTransfer.State.COMPLETE, (long)file_info.get_size());
|
||||
default_widget.update_file_info(mime_type, 100, FileTransfer.DIRECTION_SENT,
|
||||
FileTransfer.State.COMPLETE, (long)file_info.get_size());
|
||||
widget = default_widget;
|
||||
}
|
||||
|
||||
|
|
|
@ -78,6 +78,12 @@ public class MainWindow : Gtk.Window {
|
|||
search_entry = (SearchEntry) builder.get_object("search_entry");
|
||||
Image conversation_list_placeholder_image = (Image) builder.get_object("conversation_list_placeholder_image");
|
||||
conversation_list_placeholder_image.set_from_pixbuf(new Pixbuf.from_resource("/im/dino/Dino/icons/dino-conversation-list-placeholder-arrow.svg"));
|
||||
|
||||
conversation_view.copy_text.connect((text) => {
|
||||
var display = get_display();
|
||||
var clipboard = Gtk.Clipboard.get_default(display);
|
||||
clipboard.set_text(text, text.length);
|
||||
});
|
||||
}
|
||||
|
||||
private void update_headerbar() {
|
||||
|
|
|
@ -16,6 +16,7 @@ class SettingsDialog : Dialog {
|
|||
[GtkChild] private unowned RadioButton encryption_radio_openpgp;
|
||||
[GtkChild] private unowned CheckButton send_button_checkbutton;
|
||||
[GtkChild] private unowned CheckButton enter_newline_checkbutton;
|
||||
[GtkChild] private unowned CheckButton quit_ctrl_q_checkbutton;
|
||||
|
||||
Dino.Entities.Settings settings = Dino.Application.get_default().settings;
|
||||
|
||||
|
@ -33,6 +34,7 @@ class SettingsDialog : Dialog {
|
|||
send_button_checkbutton.active = settings.send_button;
|
||||
enter_newline_checkbutton.active = settings.enter_newline;
|
||||
enter_newline_checkbutton.sensitive = settings.send_button;
|
||||
quit_ctrl_q_checkbutton.active = settings.quit_ctrl_q;
|
||||
|
||||
typing_checkbutton.toggled.connect(() => { settings.send_typing = typing_checkbutton.active; } );
|
||||
marker_checkbutton.toggled.connect(() => { settings.send_marker = marker_checkbutton.active; } );
|
||||
|
@ -67,6 +69,7 @@ class SettingsDialog : Dialog {
|
|||
enter_newline_checkbutton.active = visible;
|
||||
}
|
||||
});
|
||||
quit_ctrl_q_checkbutton.toggled.connect(() => { settings.quit_ctrl_q = quit_ctrl_q_checkbutton.active; });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -117,7 +117,9 @@ public class FileProvider : Dino.FileProvider, Object {
|
|||
});
|
||||
file_meta.mime_type = content_type;
|
||||
if (content_length != null) {
|
||||
file_meta.size = int64.parse(content_length);
|
||||
if (int64.try_parse(content_length, out file_meta.size) == false) {
|
||||
throw new FileReceiveError.GET_METADATA_FAILED("failed to parse size");
|
||||
}
|
||||
}
|
||||
|
||||
return file_meta;
|
||||
|
@ -134,6 +136,17 @@ public class FileProvider : Dino.FileProvider, Object {
|
|||
var session = new Soup.Session();
|
||||
session.user_agent = @"Dino/$(Dino.get_short_version()) ";
|
||||
var get_message = new Soup.Message("GET", http_receive_data.url);
|
||||
size_t received_bytes = 0;
|
||||
get_message.wrote_body_data.connect((chunk) => {
|
||||
debug(@"length=$(chunk.length), received_bytes=$(received_bytes), progress=$(file_transfer.progress)");
|
||||
if (file_transfer.size != 0) {
|
||||
received_bytes += chunk.length;
|
||||
file_transfer.progress =
|
||||
(int)(((uint64)received_bytes * (uint64)100)
|
||||
/ (uint64)file_transfer.size);
|
||||
debug(@"length=$(chunk.length), received_bytes=$(received_bytes), progress=$(file_transfer.progress)");
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
#if SOUP_3_0
|
||||
|
@ -152,10 +165,23 @@ public class FileProvider : Dino.FileProvider, Object {
|
|||
}
|
||||
|
||||
public FileMeta get_file_meta(FileTransfer file_transfer) throws FileReceiveError {
|
||||
Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation(file_transfer.counterpart.bare_jid, file_transfer.account);
|
||||
if (conversation == null) throw new FileReceiveError.GET_METADATA_FAILED("No conversation");
|
||||
var? cm_identity = stream_interactor.get_module(ConversationManager.IDENTITY);
|
||||
if (cm_identity == null) {
|
||||
throw new FileReceiveError.GET_METADATA_FAILED("null ConversationManager");
|
||||
}
|
||||
|
||||
Message? message = stream_interactor.get_module(MessageStorage.IDENTITY).get_message_by_id(int.parse(file_transfer.info), conversation);
|
||||
Conversation? conversation = cm_identity.get_conversation(file_transfer.counterpart.bare_jid, file_transfer.account);
|
||||
if (conversation == null) throw new FileReceiveError.GET_METADATA_FAILED("No conversation");
|
||||
else if (file_transfer.info == null) {
|
||||
throw new FileReceiveError.GET_METADATA_FAILED("null file_transfer.info");
|
||||
}
|
||||
|
||||
int info;
|
||||
bool result = int.try_parse(file_transfer.info, out info);
|
||||
if (result == false) {
|
||||
throw new FileReceiveError.GET_METADATA_FAILED("failed to parse file_transfer.info");
|
||||
}
|
||||
Message? message = stream_interactor.get_module(MessageStorage.IDENTITY).get_message_by_id(info, conversation);
|
||||
if (message == null) throw new FileReceiveError.GET_METADATA_FAILED("No message");
|
||||
|
||||
var file_meta = new HttpFileMeta();
|
||||
|
@ -170,10 +196,20 @@ public class FileProvider : Dino.FileProvider, Object {
|
|||
}
|
||||
|
||||
public FileReceiveData? get_file_receive_data(FileTransfer file_transfer) {
|
||||
Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation(file_transfer.counterpart.bare_jid, file_transfer.account);
|
||||
var? cm_identity = stream_interactor.get_module(ConversationManager.IDENTITY);
|
||||
if (cm_identity == null) return null;
|
||||
|
||||
Conversation? conversation = cm_identity.get_conversation(file_transfer.counterpart.bare_jid, file_transfer.account);
|
||||
if (conversation == null) return null;
|
||||
|
||||
Message? message = stream_interactor.get_module(MessageStorage.IDENTITY).get_message_by_id(int.parse(file_transfer.info), conversation);
|
||||
var? ms_identity = stream_interactor.get_module(MessageStorage.IDENTITY);
|
||||
if (ms_identity == null || file_transfer.info == null) return null;
|
||||
|
||||
int info;
|
||||
bool result = int.try_parse(file_transfer.info, out info);
|
||||
if (result == false) return null;
|
||||
|
||||
Message? message = ms_identity.get_message_by_id(info, conversation);
|
||||
if (message == null) return null;
|
||||
|
||||
var receive_data = new HttpFileReceiveData();
|
||||
|
|
|
@ -81,6 +81,10 @@ public class HttpFileSender : FileSender, Object {
|
|||
body.complete();
|
||||
return;
|
||||
}
|
||||
else if (read < 0) {
|
||||
warning("transfer_more_bytes: stream.read failed");
|
||||
return;
|
||||
}
|
||||
bytes.length = (int)read;
|
||||
body.append_buffer(new Soup.Buffer.take(bytes));
|
||||
}
|
||||
|
@ -101,6 +105,10 @@ public class HttpFileSender : FileSender, Object {
|
|||
put_message.request_body.set_accumulate(false);
|
||||
put_message.wrote_headers.connect(() => transfer_more_bytes(file_transfer.input_stream, put_message.request_body));
|
||||
put_message.wrote_chunk.connect(() => transfer_more_bytes(file_transfer.input_stream, put_message.request_body));
|
||||
put_message.wrote_body_data.connect((chunk) => {
|
||||
debug(@"wrote_body_data: chunk.length=$(chunk.length)");
|
||||
progress(chunk.length);
|
||||
});
|
||||
#endif
|
||||
foreach (var entry in file_send_data.headers.entries) {
|
||||
put_message.request_headers.append(entry.key, entry.value);
|
||||
|
|
|
@ -41,6 +41,14 @@ public class Dino.Plugins.Rtp.VideoWidget : Gtk.Bin, Dino.Plugins.VideoCallWidge
|
|||
add(widget);
|
||||
widget.visible = true;
|
||||
} else {
|
||||
var dialog = new Gtk.MessageDialog(null, MODAL, WARNING, OK, null);
|
||||
|
||||
dialog.text = "Could not create GTK video sink";
|
||||
dialog.secondary_text = "Please install package gstreamer1.0-gtk3 or equivalent.";
|
||||
dialog.response.connect((response_id) => {
|
||||
dialog.close();
|
||||
});
|
||||
dialog.run();
|
||||
warning("Could not create GTK video sink. Won't display videos.");
|
||||
}
|
||||
size_allocate.connect_after(after_size_allocate);
|
||||
|
|
Loading…
Reference in New Issue