mirror of https://github.com/koreader/koreader
Compare commits
480 Commits
Author | SHA1 | Date |
---|---|---|
SomeGuy | c5600ffe19 | 9 hours ago |
Benoit Pierre | 99447414dc | 10 hours ago |
ziz57 | 93407c8947 | 10 hours ago |
Benoit Pierre | 4c6919ac2a | 13 hours ago |
Benoit Pierre | 10e6f489d0 | 13 hours ago |
hius07 | 14519bc076 | 14 hours ago |
hius07 | b06272592d | 14 hours ago |
zwim | d2ff789543 | 15 hours ago |
SomeGuy | 1b37aa1bd6 | 15 hours ago |
hius07 | 84d28dc5d9 | 23 hours ago |
Benoit Pierre | ea51435237 | 23 hours ago |
SomeGuy | 512065fa14 | 1 day ago |
SomeGuy | c429ac8c3f | 1 day ago |
Benoit Pierre | 2f0e456a42 | 3 days ago |
Benoit Pierre | b7c1957e4b | 3 days ago |
Benoit Pierre | 4750b4a4cd | 3 days ago |
Benoit Pierre | 404c7c0dfe | 3 days ago |
Benoit Pierre | 5a465f413b | 3 days ago |
Benoit Pierre | 1c9c35dcb3 | 3 days ago |
nairyo | c7a59145a3 | 5 days ago |
Piotrek Marciniak | 9b1a21ef82 | 5 days ago |
SomeGuy | 1aefd80ea6 | 5 days ago |
Frans de Jonge | 94372c2adf | 6 days ago |
SomeGuy | eb63cf655f | 6 days ago |
Frans de Jonge | ffc43030ec | 6 days ago |
hius07 | 9223cde2bd | 6 days ago |
Frans de Jonge | 8f2bd5420d | 6 days ago |
Martín Fernández | 3fb2f18041 | 6 days ago |
Frans de Jonge | a21db40745 | 6 days ago |
SomeGuy | 00d0affd70 | 6 days ago |
SomeGuy | d217f5c161 | 6 days ago |
hius07 | 076f77282b | 7 days ago |
hius07 | c6e6d72cf3 | 7 days ago |
ziz57 | 7925455b68 | 7 days ago |
Frans de Jonge | b222900cb9 | 1 week ago |
hius07 | 556e5bd6b4 | 1 week ago |
SomeGuy | 81575ae24f | 1 week ago |
NiLuJe | f0f37e3153 | 1 week ago |
Frans de Jonge | 07b507370f | 1 week ago |
poire-z | fd7e224c16 | 1 week ago |
poire-z | f00a88aef7 | 1 week ago |
poire-z | 54a0cdd737 | 1 week ago |
Frans de Jonge | 20d8a5c313 | 1 week ago |
SomeGuy | 3f64ecfd28 | 2 weeks ago |
Frans de Jonge | 5b18c30336 | 2 weeks ago |
SomeGuy | e859109885 | 2 weeks ago |
poire-z | 40814bf12b | 2 weeks ago |
SomeGuy | 6c7e2a9c62 | 2 weeks ago |
SomeGuy | 577c5d454f | 2 weeks ago |
Martín Fernández | 36d2e3cf74 | 2 weeks ago |
yparitcher | 59fb906921 | 2 weeks ago |
NiLuJe | 4d9c6523ad | 2 weeks ago |
Martín Fernández | 1eb2095ead | 2 weeks ago |
Martín Fernández | 89a6ae28a6 | 2 weeks ago |
Martín Fernández | 635d243152 | 2 weeks ago |
Nico Hirsch | 3b97e2988a | 2 weeks ago |
Martín Fernández | ba8891082c | 2 weeks ago |
Tomáš Janoušek | e94550a261 | 2 weeks ago |
Martín Fernández | 7bded465eb | 2 weeks ago |
Martín Fernández | d801af6d41 | 2 weeks ago |
hius07 | daf0fa4b4b | 2 weeks ago |
hius07 | 6b192c346a | 2 weeks ago |
hius07 | 46449eb06e | 2 weeks ago |
nairyo | 126c01e1b5 | 2 weeks ago |
hius07 | db63db11b2 | 2 weeks ago |
NiLuJe | 05168b22f5 | 2 weeks ago |
Philip Chan | 5d63907cae | 2 weeks ago |
NiLuJe | fd5260f2ce | 3 weeks ago |
Martín Fernández | 79be8a10b1 | 3 weeks ago |
Benoit Pierre | a9a023c062 | 3 weeks ago |
Benoit Pierre | ea538900ba | 3 weeks ago |
Benoit Pierre | b2d495fcdd | 3 weeks ago |
Benoit Pierre | 0aaa8e7c5b | 3 weeks ago |
Benoit Pierre | f82cc31717 | 3 weeks ago |
Benoit Pierre | a12b075e07 | 3 weeks ago |
Benoit Pierre | b28c58b902 | 3 weeks ago |
Benoit Pierre | 76bdb7e65c | 3 weeks ago |
mergen3107 | 8a316f928a | 3 weeks ago |
Benoit Pierre | 25d29aca4a | 3 weeks ago |
Benoit Pierre | c9c8089188 | 3 weeks ago |
Martín Fernández | 2c6808ba78 | 3 weeks ago |
sdasda7777 | eb7af994e1 | 3 weeks ago |
Nico Hirsch | 3e04184638 | 3 weeks ago |
Philip Chan | f0a3bcf05b | 3 weeks ago |
Benoit Pierre | 7ba42579eb | 3 weeks ago |
Benoit Pierre | 8c0362f9ed | 3 weeks ago |
Benoit Pierre | 5a146414db | 3 weeks ago |
Benoit Pierre | 49e3251e7b | 3 weeks ago |
Benoit Pierre | f749fc2fd9 | 3 weeks ago |
Benoit Pierre | 417d56b440 | 3 weeks ago |
Benoit Pierre | a4526633dd | 3 weeks ago |
Benoit Pierre | 5efba26d80 | 3 weeks ago |
Benoit Pierre | 3f8f87d294 | 3 weeks ago |
Benoit Pierre | a4400b3ccb | 3 weeks ago |
Benoit Pierre | 2d4b12c99c | 3 weeks ago |
Benoit Pierre | e921ed1bc7 | 3 weeks ago |
SomeGuy | baab326332 | 3 weeks ago |
Joshua Bullock | 1398154546 | 3 weeks ago |
Predrag Đokić | eb6e5e3c20 | 3 weeks ago |
hius07 | 12c3c190b0 | 3 weeks ago |
Benoit Pierre | 075edf9980 | 3 weeks ago |
Benoit Pierre | 554e8daf99 | 3 weeks ago |
Benoit Pierre | 089c19cb39 | 3 weeks ago |
Benoit Pierre | 3e809b6c7b | 3 weeks ago |
Benoit Pierre | fdf19e98c3 | 3 weeks ago |
Benoit Pierre | d0ca04c48d | 3 weeks ago |
Benoit Pierre | b67c6147d5 | 3 weeks ago |
peicuiping | a7e34673e6 | 3 weeks ago |
Valentin Dubois | 526a1fb727 | 3 weeks ago |
Benoit Pierre | 821120828b | 3 weeks ago |
sdasda7777 | 8530282d38 | 4 weeks ago |
hius07 | 725df17c45 | 4 weeks ago |
hius07 | c47d3b3177 | 4 weeks ago |
zwim | bf58723af1 | 4 weeks ago |
SomeGuy | e51b71f463 | 4 weeks ago |
poire-z | 001e90db1e | 4 weeks ago |
poire-z | 03d16270d9 | 4 weeks ago |
poire-z | 7d94562602 | 4 weeks ago |
poire-z | ca90b982b4 | 4 weeks ago |
poire-z | 1c9a6509a2 | 4 weeks ago |
Benoit Pierre | 89b1280166 | 4 weeks ago |
hius07 | d82815952e | 4 weeks ago |
hius07 | 6b0d97bf22 | 1 month ago |
Benoit Pierre | 087ddd1510 | 1 month ago |
Benoit Pierre | 7392dd2ad4 | 1 month ago |
Benoit Pierre | 54ded2c578 | 1 month ago |
Benoit Pierre | ad6e3b34c4 | 1 month ago |
Benoit Pierre | 64213bf3d9 | 1 month ago |
Benoit Pierre | 6d5ad05e9f | 1 month ago |
hius07 | 8ff846ba6e | 1 month ago |
Benoit Pierre | e8544316a8 | 1 month ago |
vyaus | f793c6a36c | 1 month ago |
Frans de Jonge | 34abb4e22b | 1 month ago |
Galunid | ca14420372 | 1 month ago |
hius07 | f5be04a738 | 1 month ago |
mergen3107 | caea0e8fb2 | 1 month ago |
ElimGarak1 | bfc84795c8 | 1 month ago |
Max Ignatenko | 87c85bf94d | 1 month ago |
SomeGuy | c70c9f0905 | 1 month ago |
mergen3107 | d3011571a3 | 1 month ago |
Max Ignatenko | b872191dc9 | 2 months ago |
Benoit Pierre | 715f5aa747 | 2 months ago |
Benoit Pierre | 8b8258b44a | 2 months ago |
Benoit Pierre | f3dcc70d8d | 2 months ago |
Benoit Pierre | 4a343d3669 | 2 months ago |
Benoit Pierre | 21c6e37f5e | 2 months ago |
Benoit Pierre | c345de5d71 | 2 months ago |
Benoit Pierre | ad6607cb4c | 2 months ago |
Frans de Jonge | f93cc6e916 | 2 months ago |
Benoit Pierre | 8b4b3025eb | 2 months ago |
Benoit Pierre | 0dbfac22b0 | 2 months ago |
Benoit Pierre | 12552f1c71 | 2 months ago |
Benoit Pierre | c503e9e848 | 2 months ago |
poire-z | d178273671 | 2 months ago |
Frans de Jonge | 31c28378e7 | 2 months ago |
SomeGuy | fb86acaf1a | 2 months ago |
Frans de Jonge | ad266f46c2 | 2 months ago |
SomeGuy | 279f16aa23 | 2 months ago |
Bastian Wagner | aaa56a814f | 2 months ago |
poire-z | ac4d4756f8 | 2 months ago |
Tomas Janousek | 1fbdc1f19d | 2 months ago |
Tomas Janousek | 4fa6783dbb | 2 months ago |
Tomas Janousek | b3e125a7ce | 2 months ago |
hugleo | cd7d3b5ef6 | 2 months ago |
Denis Malinovsky | 6cc970dbb4 | 2 months ago |
hius07 | c415aea67e | 2 months ago |
Frans de Jonge | 601925ab87 | 2 months ago |
Frans de Jonge | ec54afcc0d | 2 months ago |
Frans de Jonge | a7edf213a5 | 2 months ago |
SomeGuy | f6588e95e8 | 2 months ago |
Frans de Jonge | b1a80921ad | 2 months ago |
Frans de Jonge | b9261e0245 | 2 months ago |
Benoit Pierre | dce92020c1 | 2 months ago |
hasezoey | 42c93a7623 | 2 months ago |
SomeGuy | fbd3e822fe | 2 months ago |
Denis Malinovsky | 501cba6ebe | 2 months ago |
dkabot | ee7c3ab551 | 2 months ago |
Frans de Jonge | ca8e9352ba | 2 months ago |
Denis Malinovsky | f4a8514545 | 2 months ago |
poire-z | 86cb5cbd4c | 2 months ago |
poire-z | 67cd647d1a | 2 months ago |
hius07 | c8c4e0301a | 2 months ago |
Frans de Jonge | 9387fcd2d0 | 3 months ago |
hius07 | bb98cbf612 | 3 months ago |
hugleo | 424fa9b6fd | 3 months ago |
Martín Fernández | 5d2782ddfe | 3 months ago |
Martín Fernández | 3638adc841 | 3 months ago |
Jo Van Bulck | 4d19ce24ed | 3 months ago |
hugleo | 95ce974ef9 | 3 months ago |
poire-z | 9a84755e56 | 3 months ago |
poire-z | 191ef2b4c0 | 3 months ago |
hugleo | b026f84949 | 3 months ago |
SomeGuy | ac0483bfce | 3 months ago |
Frans de Jonge | 20813cab53 | 3 months ago |
hius07 | 5414858b74 | 3 months ago |
poire-z | 0eaa2d8248 | 3 months ago |
poire-z | 70e6f4ce09 | 3 months ago |
poire-z | e3d7669588 | 3 months ago |
poire-z | 9467034f3f | 3 months ago |
poire-z | 93b3e3504d | 3 months ago |
hius07 | 6f896e9383 | 3 months ago |
hius07 | bdb1c3135c | 3 months ago |
hius07 | 8df885438c | 3 months ago |
hius07 | 66afeebe85 | 3 months ago |
poire-z | c65d128032 | 3 months ago |
zwim | c8f39c3841 | 3 months ago |
zwim | 58b3367d18 | 3 months ago |
zwim | 764f8ba647 | 3 months ago |
NiLuJe | dd8560cef8 | 3 months ago |
hius07 | 7edb64ecee | 3 months ago |
Frans de Jonge | c4a09b3076 | 3 months ago |
Frans de Jonge | d239623c46 | 3 months ago |
hius07 | ec98c6334b | 3 months ago |
hasezoey | ade1daca3a | 3 months ago |
Frans de Jonge | 3e7ab199e7 | 3 months ago |
hius07 | 2fca0ee989 | 3 months ago |
hius07 | 72a6fa1e64 | 3 months ago |
weijiuqiao | 5939c82bcf | 3 months ago |
hius07 | db2336440f | 3 months ago |
Hzj_jie | d4c78aaa4f | 3 months ago |
hugleo | 52fae11da7 | 4 months ago |
hugleo | ef0077df23 | 4 months ago |
hugleo | 041117cbb6 | 4 months ago |
hasezoey | 76980098ec | 4 months ago |
hius07 | 5d4747c593 | 4 months ago |
poire-z | 76bf85738a | 4 months ago |
poire-z | d77b511849 | 4 months ago |
poire-z | fb39fe93ed | 4 months ago |
poire-z | 0506ffe289 | 4 months ago |
poire-z | 8010808a1f | 4 months ago |
Frans de Jonge | bdd475f55f | 4 months ago |
hius07 | 50fcc04725 | 4 months ago |
hius07 | b8090c641c | 4 months ago |
hius07 | c3bb2263b7 | 4 months ago |
hius07 | 962477e7c6 | 4 months ago |
zwim | f836f6a237 | 4 months ago |
hius07 | 38a14ff3a0 | 4 months ago |
hius07 | d94b819eb1 | 4 months ago |
hius07 | b832d43d98 | 4 months ago |
hius07 | f246b3d19c | 4 months ago |
NiLuJe | 75ffc3bb76 | 4 months ago |
NiLuJe | a906838123 | 4 months ago |
NiLuJe | c9da681874 | 4 months ago |
NiLuJe | a8a944cbaf | 4 months ago |
NiLuJe | 39744d7642 | 4 months ago |
NiLuJe | 4785df48a9 | 4 months ago |
hius07 | 925aa728c9 | 4 months ago |
NiLuJe | 82bf8bf379 | 4 months ago |
NiLuJe | e5cb24a891 | 4 months ago |
NiLuJe | 19ed35e59c | 4 months ago |
NiLuJe | 7f33d94c4c | 4 months ago |
NiLuJe | 90ae4acca6 | 4 months ago |
NiLuJe | 65e22ceafc | 4 months ago |
NiLuJe | 5e4d182608 | 4 months ago |
NiLuJe | 72250daba8 | 4 months ago |
NiLuJe | 55171212c3 | 4 months ago |
poire-z | 43d36b2ea9 | 5 months ago |
poire-z | 487e5f667a | 5 months ago |
hius07 | e0ed04a1a1 | 5 months ago |
hius07 | 43831236ce | 5 months ago |
cookiebit | e3b4cbe71a | 5 months ago |
Andrei Ignatev | 4c503b0f11 | 5 months ago |
NiLuJe | 3b129e2ada | 5 months ago |
NiLuJe | d33bb0452c | 5 months ago |
NiLuJe | 259b4ac950 | 5 months ago |
gbyl | a84ab265b8 | 5 months ago |
NiLuJe | 40d27ac3e5 | 5 months ago |
NiLuJe | 5bd78ab3b4 | 5 months ago |
NiLuJe | c529c1cce3 | 5 months ago |
NiLuJe | d205c72119 | 5 months ago |
NiLuJe | 0f5547a128 | 5 months ago |
NiLuJe | 588bf38c84 | 5 months ago |
hugleo | 98b598ddcb | 5 months ago |
hius07 | 234a68d80b | 5 months ago |
poire-z | e9b2a07352 | 5 months ago |
NiLuJe | b2b87bd651 | 5 months ago |
NiLuJe | 5cbd65acc1 | 5 months ago |
hius07 | c4e9e6bc51 | 5 months ago |
hius07 | 0ceb88a9a3 | 5 months ago |
poire-z | 5f5162d95c | 5 months ago |
poire-z | a025faae4e | 5 months ago |
poire-z | 455e904120 | 5 months ago |
NiLuJe | dcfcc81dcf | 5 months ago |
NiLuJe | 0f194d88b9 | 5 months ago |
NiLuJe | de3e420c1e | 5 months ago |
NiLuJe | 8968c41070 | 5 months ago |
NiLuJe | 871ebb0573 | 5 months ago |
sonix-github | 87915de32b | 5 months ago |
NiLuJe | c97d20cd24 | 5 months ago |
NiLuJe | 18c17829b7 | 5 months ago |
zwim | 2c33fc6576 | 5 months ago |
hius07 | ea9ef6781c | 5 months ago |
Frans de Jonge | cd903d66e5 | 5 months ago |
mergen3107 | 4a9473ed45 | 5 months ago |
hius07 | 4ddc0f2ef8 | 5 months ago |
lbesnard | 5a3f73766c | 5 months ago |
NiLuJe | 9826615f06 | 5 months ago |
NiLuJe | cc52c022dc | 5 months ago |
NiLuJe | 4a15dce3e4 | 5 months ago |
NiLuJe | 3131475e39 | 5 months ago |
Tomáš Janoušek | ccbfbabb25 | 5 months ago |
Mihai Vasiliu | 5d2a441064 | 5 months ago |
mergen3107 | 63329569eb | 5 months ago |
mergen3107 | 6c85547ce6 | 5 months ago |
hius07 | 3533356ffd | 5 months ago |
mergen3107 | 4c2fc1eb81 | 5 months ago |
mergen3107 | 57cbde5901 | 5 months ago |
NiLuJe | ac5d662eb4 | 5 months ago |
greatyingzi | c12b4f2e14 | 5 months ago |
hius07 | 7a421ea3ab | 5 months ago |
hius07 | b949d07f4f | 5 months ago |
mergen3107 | 9ba66ac382 | 5 months ago |
NiLuJe | 33b54f5574 | 5 months ago |
NiLuJe | e7ee900cbd | 5 months ago |
NiLuJe | d151dd5f12 | 5 months ago |
hius07 | 042a529fab | 5 months ago |
Frans de Jonge | 75d3c10496 | 5 months ago |
hius07 | 5a4e70a19d | 6 months ago |
dependabot[bot] | 9d94ab38f3 | 6 months ago |
poire-z | 48197805aa | 6 months ago |
hius07 | bf59f53e18 | 6 months ago |
NiLuJe | 675f5a062f | 6 months ago |
zwim | c30c1ff11f | 6 months ago |
NiLuJe | a2e0642998 | 6 months ago |
NiLuJe | 9ab866598a | 6 months ago |
NiLuJe | bc01394f8f | 6 months ago |
NiLuJe | ff58ac7a65 | 6 months ago |
hius07 | f765fe3070 | 6 months ago |
mergen3107 | 0d2f8fbb3f | 6 months ago |
hius07 | f4a5a2b60a | 6 months ago |
poire-z | fe02b83b6a | 6 months ago |
hius07 | aabd6d7a26 | 6 months ago |
Frans de Jonge | 13a521c398 | 6 months ago |
NiLuJe | 9ebe7714ec | 6 months ago |
NiLuJe | 18fff200ac | 6 months ago |
Wim de With | e7780c09f3 | 6 months ago |
Wim de With | 128accafe3 | 6 months ago |
Wim de With | 01642659d2 | 6 months ago |
Wim de With | 98d92d37ab | 6 months ago |
NiLuJe | 3c63a5d8a8 | 6 months ago |
hugleo | f990937f9f | 6 months ago |
hius07 | 498193c26d | 6 months ago |
poire-z | b361cec4ff | 6 months ago |
poire-z | c32ace4611 | 6 months ago |
hius07 | b4424b4685 | 6 months ago |
hius07 | dce12de09d | 6 months ago |
NiLuJe | 4a64e02c68 | 6 months ago |
mergen3107 | 33c7f05158 | 6 months ago |
hius07 | d3787eee64 | 6 months ago |
Monirzadeh | 6527d7f1ab | 6 months ago |
NiLuJe | 5ef4db6176 | 6 months ago |
NiLuJe | f42893d3d1 | 6 months ago |
hius07 | f6fb35fd98 | 6 months ago |
NiLuJe | 82e7ebd6df | 6 months ago |
NiLuJe | 9af3e95d9d | 6 months ago |
NiLuJe | 2554aee7a3 | 6 months ago |
Monirzadeh | fbd012b928 | 6 months ago |
NiLuJe | bf03f40ef2 | 6 months ago |
NiLuJe | bba48fc1bf | 6 months ago |
NiLuJe | bc7ea8602e | 6 months ago |
Ben Bell | f92c0eae3b | 6 months ago |
WangKe | dea94026f1 | 7 months ago |
Frans de Jonge | 7870e83410 | 7 months ago |
Frans de Jonge | 51b4d5e646 | 7 months ago |
hius07 | d99c70b5e1 | 7 months ago |
hius07 | 88d6613fed | 7 months ago |
hius07 | ed46dca886 | 7 months ago |
hius07 | da8e23c011 | 7 months ago |
hius07 | 082ef9b545 | 7 months ago |
poire-z | 894cb3190d | 7 months ago |
hius07 | 4044c81a5a | 7 months ago |
Wim de With | 17a4aa962f | 7 months ago |
hius07 | d0d3cf78f9 | 7 months ago |
hius07 | 51f3115b90 | 7 months ago |
ElimGarak1 | 2e2ca76a03 | 7 months ago |
hius07 | 68aa209a6c | 7 months ago |
NiLuJe | 94a82087de | 7 months ago |
NiLuJe | fee2b79829 | 7 months ago |
hius07 | 4391267dfa | 7 months ago |
hius07 | 414e74f626 | 7 months ago |
Frans de Jonge | 48dfe6ce05 | 7 months ago |
zwim | 58cb1ff42b | 7 months ago |
hius07 | b70f866656 | 7 months ago |
Frans de Jonge | 873503369c | 7 months ago |
NiLuJe | d805a69446 | 7 months ago |
NiLuJe | 84e942a326 | 7 months ago |
NiLuJe | 6e08809419 | 7 months ago |
hius07 | 6b892a65a3 | 7 months ago |
NiLuJe | 12bea3b14b | 7 months ago |
NiLuJe | 2c5d618f6b | 7 months ago |
hius07 | 39d54956ec | 7 months ago |
Frans de Jonge | 9e82761c45 | 8 months ago |
Frans de Jonge | edf9798bb7 | 8 months ago |
Frans de Jonge | 9274a3febd | 8 months ago |
hius07 | 3b2fc7a551 | 8 months ago |
Frans de Jonge | f3520effd6 | 8 months ago |
hius07 | c92d94af4d | 8 months ago |
NiLuJe | d8a48d9e1c | 8 months ago |
NiLuJe | fed24ba28c | 8 months ago |
NiLuJe | c47ce45fb8 | 8 months ago |
hius07 | 2ed2c2c23d | 8 months ago |
hius07 | e9051353a2 | 8 months ago |
hius07 | 6ccf19b99f | 8 months ago |
hasezoey | ee7a6455ce | 8 months ago |
夏鲁豫 | ff6ee69753 | 8 months ago |
ElimGarak1 | 5b916cccff | 8 months ago |
François Gannaz | 11083022b0 | 8 months ago |
Frans de Jonge | 6e57ccaf4f | 8 months ago |
yparitcher | 0e26d4499b | 8 months ago |
Benoit Pierre | d4421130f8 | 8 months ago |
hius07 | e577c79d95 | 8 months ago |
NiLuJe | 16e96969c5 | 8 months ago |
Ryan W West | 27104ea011 | 8 months ago |
NiLuJe | 4eac18f9b9 | 8 months ago |
NiLuJe | bb492f5d78 | 8 months ago |
NiLuJe | d039aa5f3a | 8 months ago |
hius07 | 517731dbbb | 8 months ago |
poire-z | ea3f8951a3 | 8 months ago |
poire-z | c51b0c7bb9 | 8 months ago |
poire-z | 5406fdf2e0 | 8 months ago |
poire-z | 2b75ef108e | 8 months ago |
poire-z | 1c128f1089 | 8 months ago |
poire-z | fb6bc0391f | 8 months ago |
poire-z | bbf923c7a8 | 8 months ago |
poire-z | 35f16f87a4 | 8 months ago |
poire-z | 5ec736ae96 | 8 months ago |
poire-z | e6ac74c1df | 8 months ago |
poire-z | 52c45ef6db | 8 months ago |
poire-z | da424486ef | 8 months ago |
NiLuJe | 2ff60ce04f | 8 months ago |
François Gannaz | 128302873d | 8 months ago |
Benoit Pierre | 5b5b4d9ebc | 8 months ago |
hius07 | 0ac258fcb7 | 8 months ago |
Benoit Pierre | 08555ad68b | 8 months ago |
Benoit Pierre | e8bc28db33 | 8 months ago |
Benoit Pierre | 7d3456edc1 | 8 months ago |
hius07 | 0c5240074c | 8 months ago |
hius07 | 40e2a838ae | 8 months ago |
hrdl | 4875f63f09 | 8 months ago |
ElimGarak1 | ed885a79b2 | 8 months ago |
Benoit Pierre | 8f6fae81fa | 8 months ago |
NiLuJe | 741302445b | 8 months ago |
NiLuJe | e5535a3a3a | 8 months ago |
hius07 | cafe565ade | 8 months ago |
hius07 | 9f39614e8a | 8 months ago |
NiLuJe | 55ea10655f | 8 months ago |
hius07 | ed5c1cef20 | 8 months ago |
NiLuJe | 34ba2fab30 | 8 months ago |
hugleo | 7ecd94b26a | 9 months ago |
Serge Baranov | 55daf9fbf4 | 9 months ago |
hius07 | 684fc22ffc | 9 months ago |
NiLuJe | 2b13cd7dcb | 9 months ago |
Frans de Jonge | f3d959a324 | 9 months ago |
Wim de With | 1773b62ce8 | 9 months ago |
hius07 | be125af949 | 9 months ago |
Frans de Jonge | 1f03e76aea | 9 months ago |
poire-z | f78a8c5315 | 9 months ago |
hius07 | 3f677a7fdd | 9 months ago |
hius07 | 108d87742a | 9 months ago |
dependabot[bot] | df19c2a0da | 9 months ago |
hius07 | cc82ead981 | 9 months ago |
hius07 | 6efcf96b75 | 9 months ago |
hius07 | 7d626456a3 | 9 months ago |
hius07 | 73378cd9d7 | 9 months ago |
hius07 | 5e74f29fba | 9 months ago |
hius07 | e4ba8c7909 | 9 months ago |
NiLuJe | 2a79ad918c | 9 months ago |
NiLuJe | 6d9d3ee8c2 | 9 months ago |
NiLuJe | ba5c7df0db | 9 months ago |
hius07 | f46f341b9b | 9 months ago |
hius07 | cbcf03b1af | 9 months ago |
hius07 | 912ae156f7 | 9 months ago |
hius07 | a767ad44db | 9 months ago |
NiLuJe | 4cc620b702 | 9 months ago |
NiLuJe | 4d620d9fd2 | 9 months ago |
zwim | bedd422669 | 9 months ago |
hius07 | ed2ea6803f | 9 months ago |
poire-z | 0ef7729678 | 9 months ago |
Wim de With | 599a3034ca | 9 months ago |
hius07 | 1ef7821b66 | 9 months ago |
@ -1,22 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
CI_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
# shellcheck source=/dev/null
|
||||
source "${CI_DIR}/common.sh"
|
||||
|
||||
rm -rf "${HOME}/.luarocks"
|
||||
mkdir "${HOME}/.luarocks"
|
||||
cp "${CI_BUILD_DIR}/install/etc/luarocks/config.lua" "${HOME}/.luarocks/config.lua"
|
||||
echo "wrap_bin_scripts = false" >>"${HOME}/.luarocks/config.lua"
|
||||
travis_retry luarocks --local install luafilesystem
|
||||
# for verbose_print module
|
||||
travis_retry luarocks --local install ansicolors
|
||||
travis_retry luarocks --local install busted 2.0.0-1
|
||||
#- mv -f $HOME/.luarocks/bin/busted_bootstrap $HOME/.luarocks/bin/busted
|
||||
|
||||
travis_retry luarocks --local install luacheck 0.25.0-1
|
||||
travis_retry luarocks --local install lanes # for parallel luacheck
|
||||
|
||||
# used only on master branch but added to cache for better speed
|
||||
travis_retry luarocks --local install ldoc
|
||||
travis_retry luarocks --local install luacov
|
@ -1,69 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
CI_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
# shellcheck source=/dev/null
|
||||
source "${CI_DIR}/common.sh"
|
||||
|
||||
# print some useful info
|
||||
echo "BUILD_DIR: ${CI_BUILD_DIR}"
|
||||
echo "pwd: $(pwd)"
|
||||
ls
|
||||
|
||||
# toss submodules if there are any changes
|
||||
# if [ "$(git status --ignore-submodules=dirty --porcelain)" ]; then
|
||||
# "--ignore-submodules=dirty", removed temporarily, as it did not notice as
|
||||
# expected that base was updated and kept using old cached base
|
||||
if [ "$(git status --ignore-submodules=dirty --porcelain)" ]; then
|
||||
# what changed?
|
||||
git status
|
||||
# purge and reinit submodules
|
||||
git submodule deinit -f .
|
||||
git submodule update --init
|
||||
else
|
||||
echo -e "${ANSI_GREEN}Using cached submodules."
|
||||
fi
|
||||
|
||||
# install our own updated luarocks
|
||||
echo "luarocks installation path: ${CI_BUILD_DIR}"
|
||||
if [ ! -f "${CI_BUILD_DIR}/install/bin/luarocks" ]; then
|
||||
git clone https://github.com/torch/luajit-rocks.git
|
||||
pushd luajit-rocks && {
|
||||
git checkout 6529891
|
||||
cmake . -DWITH_LUAJIT21=ON -DCMAKE_INSTALL_PREFIX="${CI_BUILD_DIR}/install"
|
||||
make install
|
||||
} && popd || exit
|
||||
else
|
||||
echo -e "${ANSI_GREEN}Using cached luarocks."
|
||||
fi
|
||||
|
||||
if [ ! -d "${HOME}/.luarocks" ] || [ ! -f "${HOME}/.luarocks/$(md5sum <"${CI_DIR}/helper_luarocks.sh")" ]; then
|
||||
echo -e "${ANSI_GREEN}Grabbing new .luarocks."
|
||||
sudo apt-get update
|
||||
# install openssl devel for luasec
|
||||
sudo apt-get -y install libssl-dev
|
||||
|
||||
"${CI_DIR}/helper_luarocks.sh"
|
||||
touch "${HOME}/.luarocks/$(md5sum <"${CI_DIR}/helper_luarocks.sh")"
|
||||
else
|
||||
echo -e "${ANSI_GREEN}Using cached .luarocks."
|
||||
fi
|
||||
|
||||
#install our own updated shellcheck
|
||||
SHELLCHECK_VERSION="v0.8.0"
|
||||
SHELLCHECK_URL="https://github.com/koalaman/shellcheck/releases/download/${SHELLCHECK_VERSION?}/shellcheck-${SHELLCHECK_VERSION?}.linux.x86_64.tar.xz"
|
||||
if ! command -v shellcheck; then
|
||||
curl -sSL "${SHELLCHECK_URL}" | tar --exclude 'SHA256SUMS' --strip-components=1 -C "${HOME}/bin" -xJf -
|
||||
chmod +x "${HOME}/bin/shellcheck"
|
||||
shellcheck --version
|
||||
else
|
||||
echo -e "${ANSI_GREEN}Using cached shellcheck."
|
||||
fi
|
||||
|
||||
# install shfmt
|
||||
SHFMT_URL="https://github.com/mvdan/sh/releases/download/v3.2.0/shfmt_v3.2.0_linux_amd64"
|
||||
if [ "$(shfmt --version)" != "v3.2.0" ]; then
|
||||
curl -sSL "${SHFMT_URL}" -o "${HOME}/bin/shfmt"
|
||||
chmod +x "${HOME}/bin/shfmt"
|
||||
else
|
||||
echo -e "${ANSI_GREEN}Using cached shfmt."
|
||||
fi
|
@ -1,112 +1,165 @@
|
||||
version: 2
|
||||
version: "2.1"
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
build:
|
||||
jobs:
|
||||
- build
|
||||
- docs:
|
||||
context: koreader-vars
|
||||
filters:
|
||||
branches:
|
||||
only: master
|
||||
requires:
|
||||
- build
|
||||
# Parameters. {{{
|
||||
|
||||
jobs:
|
||||
build:
|
||||
parameters:
|
||||
|
||||
# Bump this to reset all caches.
|
||||
cache_epoch:
|
||||
type: integer
|
||||
default: 0
|
||||
|
||||
# }}}
|
||||
|
||||
# Executors. {{{
|
||||
|
||||
executors:
|
||||
|
||||
base:
|
||||
docker:
|
||||
- image: koreader/kobase:0.3.0
|
||||
- image: koreader/kobase:0.3.2-20.04
|
||||
auth:
|
||||
username: $DOCKER_USERNAME
|
||||
password: $DOCKER_PASSWORD
|
||||
environment:
|
||||
EMULATE_READER: 1
|
||||
|
||||
# }}}
|
||||
|
||||
# Jobs. {{{
|
||||
|
||||
jobs:
|
||||
|
||||
# Build. {{{
|
||||
|
||||
build:
|
||||
executor: base
|
||||
resource_class: medium
|
||||
environment:
|
||||
BASH_ENV: "~/.bashrc"
|
||||
CCACHE_MAXSIZE: "256M"
|
||||
CLICOLOR_FORCE: "1"
|
||||
EMULATE_READER: "1"
|
||||
MAKEFLAGS: "OUTPUT_DIR=build INSTALL_DIR=install"
|
||||
parallelism: 2
|
||||
steps:
|
||||
# Checkout / fetch. {{{
|
||||
- checkout
|
||||
- run:
|
||||
name: Fetch
|
||||
command: .ci/fetch.sh
|
||||
# }}}
|
||||
# Check.
|
||||
- run:
|
||||
name: Check
|
||||
command: .ci/check.sh
|
||||
# Restore / setup caches. {{{
|
||||
- run:
|
||||
name: Generate cache key
|
||||
command: make -C base TARGET= cache-key
|
||||
- restore_cache:
|
||||
name: Restore build directory
|
||||
keys:
|
||||
# binary dependencies require {{ arch }} because there are different CPUs in use on the servers
|
||||
- deps-{{ arch }}-{{ checksum ".ci/install.sh" }}-{{ checksum ".ci/helper_luarocks.sh" }}
|
||||
# need to init some stuff first or git will complain when sticking in base cache
|
||||
- run: git submodule init base && git submodule update base && pushd base && git submodule init && git submodule update && popd
|
||||
# we can't use command output directly for cache check so we write it to git-rev-base
|
||||
- run: pushd base && git_rev_base=$(git describe HEAD) && popd && echo $git_rev_base && echo $git_rev_base >git-rev-base
|
||||
- &CACHE_KEY_BUILD_DIR '<< pipeline.parameters.cache_epoch >>-{{ .Environment.CIRCLE_JOB }}-build-{{ arch }}-{{ checksum "base/cache-key" }}'
|
||||
- restore_cache:
|
||||
name: Restore build cache
|
||||
keys:
|
||||
- build-{{ arch }}-{{ checksum "git-rev-base" }}
|
||||
- run: echo 'export PATH=${HOME}/bin:${PATH}' >> $BASH_ENV
|
||||
|
||||
# installs and caches testing tools
|
||||
- run:
|
||||
name: install
|
||||
command: .ci/install.sh
|
||||
- save_cache:
|
||||
key: deps-{{ arch }}-{{ checksum ".ci/install.sh" }}-{{ checksum ".ci/helper_luarocks.sh" }}
|
||||
paths:
|
||||
- "/home/ko/bin"
|
||||
- "/home/ko/.luarocks"
|
||||
# compiled luarocks binaries
|
||||
- "install"
|
||||
|
||||
# installs everything and caches base
|
||||
- &CACHE_KEY_BUILD_CACHE '<< pipeline.parameters.cache_epoch >>-{{ .Environment.CIRCLE_JOB }}-ccache-{{ arch }}-{{ checksum "base/cache-key" }}'
|
||||
- '<< pipeline.parameters.cache_epoch >>-{{ .Environment.CIRCLE_JOB }}-ccache-{{ arch }}-'
|
||||
- run:
|
||||
name: fetch
|
||||
command: .ci/fetch.sh
|
||||
name: Setup build cache
|
||||
command: |
|
||||
set -x
|
||||
which ccache
|
||||
ccache --version
|
||||
ccache --zero-stats
|
||||
ccache --show-config
|
||||
# }}}
|
||||
# Build.
|
||||
- run:
|
||||
name: check
|
||||
command: .ci/check.sh
|
||||
- run:
|
||||
name: build
|
||||
name: Build
|
||||
command: .ci/build.sh
|
||||
# we want to save cache prior to testing so we don't have to clean it up
|
||||
# Clean / save caches. {{{
|
||||
# We want to save cache prior to testing so we don't have to clean it up.
|
||||
- run:
|
||||
name: Clean caches
|
||||
when: always
|
||||
command: |
|
||||
set -x
|
||||
# Trim the build directory.
|
||||
rm -rf base/build/{cmake,staging,thirdparty}
|
||||
ccache --cleanup >/dev/null
|
||||
ccache --show-stats
|
||||
- save_cache:
|
||||
key: build-{{ arch }}-{{ checksum "git-rev-base" }}
|
||||
name: Save build cache
|
||||
key: *CACHE_KEY_BUILD_CACHE
|
||||
paths:
|
||||
- "/home/ko/.ccache"
|
||||
- "base"
|
||||
|
||||
# our lovely unit tests
|
||||
- /home/ko/.ccache
|
||||
- save_cache:
|
||||
name: Save build directory
|
||||
key: *CACHE_KEY_BUILD_DIR
|
||||
paths:
|
||||
- base/build
|
||||
# }}}
|
||||
# Tests / coverage. {{{
|
||||
# Our lovely unit tests.
|
||||
- run:
|
||||
name: test
|
||||
name: Test
|
||||
command: .ci/test.sh
|
||||
|
||||
# docs, coverage, and test timing (can we use two outputs at once?); master branch only
|
||||
# Docs, coverage, and test timing (can we use two outputs at once?); master branch only.
|
||||
- run:
|
||||
name: coverage
|
||||
name: Coverage
|
||||
command: .ci/after_success.sh
|
||||
# by storing the test results CircleCI automatically distributes tests based on execution time
|
||||
# By storing the test results CircleCI automatically distributes tests based on execution time.
|
||||
- store_test_results:
|
||||
path: koreader-emulator-x86_64-linux-gnu/koreader
|
||||
# CircleCI doesn't make the test results available as artifacts (October 2017)
|
||||
path: &TESTS_XML install/koreader/junit-test-results.xml
|
||||
# CircleCI doesn't make the test results available as artifacts (October 2017).
|
||||
- store_artifacts:
|
||||
path: koreader-emulator-x86_64-linux-gnu/koreader/junit-test-results.xml
|
||||
path: *TESTS_XML
|
||||
# }}}
|
||||
|
||||
# }}}
|
||||
|
||||
# Docs. {{{
|
||||
|
||||
docs:
|
||||
docker:
|
||||
- image: koreader/kobase:0.3.0
|
||||
auth:
|
||||
username: $DOCKER_USERNAME
|
||||
password: $DOCKER_PASSWORD
|
||||
environment:
|
||||
EMULATE_READER: 1
|
||||
executor: base
|
||||
resource_class: small
|
||||
environment:
|
||||
BASH_ENV: "~/.bashrc"
|
||||
parallelism: 1
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
keys:
|
||||
# binary dependencies require {{ arch }} because there are different CPUs in use on the servers
|
||||
- deps-{{ arch }}-{{ checksum ".ci/install.sh" }}-{{ checksum ".ci/helper_luarocks.sh" }}
|
||||
# need to init some stuff first or git will complain when sticking in base cache
|
||||
- run: git submodule init base && git submodule update base && pushd base && git submodule init && git submodule update && popd
|
||||
# we can't use command output directly for cache check so we write it to git-rev-base
|
||||
- run: pushd base && git_rev_base=$(git describe HEAD) && popd && echo $git_rev_base && echo $git_rev_base >git-rev-base
|
||||
|
||||
- run:
|
||||
name: init-submodules
|
||||
command: git submodule init && git submodule sync && git submodule update
|
||||
|
||||
name: fetch
|
||||
command: .ci/fetch.sh
|
||||
# docs, coverage, and test timing (can we use two outputs at once?); master branch only
|
||||
- run:
|
||||
name: docs-and-translation
|
||||
command: .ci/after_success_docs_translation.sh
|
||||
|
||||
# }}}
|
||||
|
||||
# }}}
|
||||
|
||||
# Workflows. {{{
|
||||
|
||||
workflows:
|
||||
|
||||
version: 2
|
||||
|
||||
build:
|
||||
|
||||
jobs:
|
||||
|
||||
- build
|
||||
|
||||
- docs:
|
||||
context: koreader-vars
|
||||
filters:
|
||||
branches:
|
||||
only: master
|
||||
requires:
|
||||
- build
|
||||
|
||||
# }}}
|
||||
|
||||
# vim: foldmethod=marker foldlevel=0
|
||||
|
@ -1,48 +0,0 @@
|
||||
language: c
|
||||
|
||||
# sudo: false
|
||||
sudo: true
|
||||
dist: trusty
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
|
||||
env:
|
||||
global:
|
||||
- "PATH=${HOME}/bin:${PATH}"
|
||||
matrix:
|
||||
- EMULATE_READER=1
|
||||
|
||||
cache:
|
||||
apt: true
|
||||
directories:
|
||||
- "${HOME}/bin"
|
||||
# compiled luarocks binaries
|
||||
- "${TRAVIS_BUILD_DIR}/install"
|
||||
# base build
|
||||
- "${TRAVIS_BUILD_DIR}/base"
|
||||
- "${HOME}/.ccache"
|
||||
- "${HOME}/.luarocks"
|
||||
before_cache:
|
||||
# don't quote like you normally would or it won't expand
|
||||
- rm -frv ${TRAVIS_BUILD_DIR}/base/build/*/cache/*
|
||||
# don't cache unit tests
|
||||
- rm -frv ${TRAVIS_BUILD_DIR}/base/build/*/spec
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.8
|
||||
- libsdl1.2-dev
|
||||
# luasec dependencies
|
||||
- libssl1.0.0
|
||||
- nasm
|
||||
# OpenSSL likes this (package contains makedepend)
|
||||
- xutils-dev
|
||||
|
||||
before_install: .ci/before_install.sh
|
||||
install: .ci/install.sh
|
||||
script: .ci/script.sh
|
||||
after_success: .ci/after_success.sh
|
@ -1 +1 @@
|
||||
Subproject commit bab6f040e73a5118335a777849c2f6e896f40638
|
||||
Subproject commit a6e112a5ee06e6939203accbd0736134af8939cd
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,423 @@
|
||||
local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
||||
local logger = require("logger")
|
||||
local _ = require("gettext")
|
||||
local T = require("ffi/util").template
|
||||
|
||||
local ReaderAnnotation = WidgetContainer:extend{
|
||||
annotations = nil, -- array sorted by annotation position order, ascending
|
||||
}
|
||||
|
||||
-- build, read, save
|
||||
|
||||
function ReaderAnnotation:buildAnnotation(bm, highlights, init)
|
||||
-- bm: associated single bookmark ; highlights: tables with all highlights
|
||||
local note = bm.text
|
||||
if note == "" then
|
||||
note = nil
|
||||
end
|
||||
local chapter = bm.chapter
|
||||
local hl, pageno = self:getHighlightByDatetime(highlights, bm.datetime)
|
||||
if init then
|
||||
if note and self.ui.bookmark:isBookmarkAutoText(bm) then
|
||||
note = nil
|
||||
end
|
||||
if chapter == nil then
|
||||
chapter = self.ui.toc:getTocTitleByPage(bm.page)
|
||||
end
|
||||
pageno = self.ui.paging and bm.page or self.document:getPageFromXPointer(bm.page)
|
||||
end
|
||||
if self.ui.paging and bm.pos0 and not bm.pos0.page then
|
||||
-- old single-page reflow highlights do not have page in position
|
||||
bm.pos0.page = bm.page
|
||||
bm.pos1.page = bm.page
|
||||
end
|
||||
if not hl then -- page bookmark or orphaned bookmark
|
||||
hl = {}
|
||||
if bm.highlighted then -- orphaned bookmark
|
||||
hl.drawer = self.view.highlight.saved_drawer
|
||||
hl.color = self.view.highlight.saved_color
|
||||
if self.ui.paging then
|
||||
if bm.pos0.page == bm.pos1.page then
|
||||
hl.pboxes = self.document:getPageBoxesFromPositions(bm.page, bm.pos0, bm.pos1)
|
||||
else -- multi-page highlight, restore the first box only
|
||||
hl.pboxes = self.document:getPageBoxesFromPositions(bm.page, bm.pos0, bm.pos0)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return { -- annotation
|
||||
datetime = bm.datetime, -- creation time, not changeable
|
||||
drawer = hl.drawer, -- highlight drawer
|
||||
color = hl.color, -- highlight color
|
||||
text = bm.notes, -- highlighted text, editable
|
||||
text_edited = hl.edited, -- true if highlighted text has been edited
|
||||
note = note, -- user's note, editable
|
||||
chapter = chapter, -- book chapter title
|
||||
pageno = pageno, -- book page number
|
||||
page = bm.page, -- highlight location, xPointer or number (pdf)
|
||||
pos0 = bm.pos0, -- highlight start position, xPointer (== page) or table (pdf)
|
||||
pos1 = bm.pos1, -- highlight end position, xPointer or table (pdf)
|
||||
pboxes = hl.pboxes, -- pdf pboxes, used only and changeable by addMarkupAnnotation
|
||||
ext = hl.ext, -- pdf multi-page highlight
|
||||
}
|
||||
end
|
||||
|
||||
function ReaderAnnotation:getHighlightByDatetime(highlights, datetime)
|
||||
for pageno, page_highlights in pairs(highlights) do
|
||||
for _, highlight in ipairs(page_highlights) do
|
||||
if highlight.datetime == datetime then
|
||||
return highlight, pageno
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderAnnotation:getAnnotationsFromBookmarksHighlights(bookmarks, highlights, init)
|
||||
local annotations = {}
|
||||
for i = #bookmarks, 1, -1 do
|
||||
table.insert(annotations, self:buildAnnotation(bookmarks[i], highlights, init))
|
||||
end
|
||||
if init then
|
||||
self:sortItems(annotations)
|
||||
end
|
||||
return annotations
|
||||
end
|
||||
|
||||
function ReaderAnnotation:onReadSettings(config)
|
||||
local annotations = config:readSetting("annotations")
|
||||
if annotations then
|
||||
-- KOHighlights may set this key when it has merged annotations from different sources:
|
||||
-- we want to make sure they are updated and sorted
|
||||
local needs_update = config:isTrue("annotations_externally_modified")
|
||||
local needs_sort -- if incompatible annotations were built of old highlights/bookmarks
|
||||
-- Annotation formats in crengine and mupdf are incompatible.
|
||||
local has_annotations = #annotations > 0
|
||||
local annotations_type = has_annotations and type(annotations[1].page)
|
||||
if self.ui.rolling and annotations_type ~= "string" then -- incompatible format loaded, or empty
|
||||
if has_annotations then -- backup incompatible format if not empty
|
||||
config:saveSetting("annotations_paging", annotations)
|
||||
end
|
||||
-- load compatible format
|
||||
annotations = config:readSetting("annotations_rolling") or {}
|
||||
config:delSetting("annotations_rolling")
|
||||
needs_sort = true
|
||||
elseif self.ui.paging and annotations_type ~= "number" then
|
||||
if has_annotations then
|
||||
config:saveSetting("annotations_rolling", annotations)
|
||||
end
|
||||
annotations = config:readSetting("annotations_paging") or {}
|
||||
config:delSetting("annotations_paging")
|
||||
needs_sort = true
|
||||
end
|
||||
self.annotations = annotations
|
||||
if needs_update or needs_sort then
|
||||
if self.ui.rolling then
|
||||
self.ui:registerPostInitCallback(function()
|
||||
self:updatedAnnotations(needs_update, needs_sort)
|
||||
end)
|
||||
else
|
||||
self:updatedAnnotations(needs_update, needs_sort)
|
||||
end
|
||||
config:delSetting("annotations_externally_modified")
|
||||
end
|
||||
else -- first run
|
||||
if self.ui.rolling then
|
||||
self.ui:registerPostInitCallback(function()
|
||||
self:migrateToAnnotations(config)
|
||||
end)
|
||||
else
|
||||
self:migrateToAnnotations(config)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderAnnotation:migrateToAnnotations(config)
|
||||
local bookmarks = config:readSetting("bookmarks") or {}
|
||||
local highlights = config:readSetting("highlight") or {}
|
||||
|
||||
if config:hasNot("highlights_imported") then
|
||||
-- before 2014, saved highlights were not added to bookmarks when they were created.
|
||||
for page, hls in pairs(highlights) do
|
||||
for _, hl in ipairs(hls) do
|
||||
local hl_page = self.ui.paging and page or hl.pos0
|
||||
-- highlights saved by some old versions don't have pos0 field
|
||||
-- we just ignore those highlights
|
||||
if hl_page then
|
||||
local item = {
|
||||
datetime = hl.datetime,
|
||||
highlighted = true,
|
||||
notes = hl.text,
|
||||
page = hl_page,
|
||||
pos0 = hl.pos0,
|
||||
pos1 = hl.pos1,
|
||||
}
|
||||
if self.ui.paging then
|
||||
item.pos0.page = page
|
||||
item.pos1.page = page
|
||||
end
|
||||
table.insert(bookmarks, item)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Bookmarks/highlights formats in crengine and mupdf are incompatible.
|
||||
local has_bookmarks = #bookmarks > 0
|
||||
local bookmarks_type = has_bookmarks and type(bookmarks[1].page)
|
||||
if self.ui.rolling then
|
||||
if bookmarks_type == "string" then -- compatible format loaded, check for incompatible old backup
|
||||
if config:has("bookmarks_paging") then -- save incompatible old backup
|
||||
local bookmarks_paging = config:readSetting("bookmarks_paging")
|
||||
local highlights_paging = config:readSetting("highlight_paging")
|
||||
local annotations = self:getAnnotationsFromBookmarksHighlights(bookmarks_paging, highlights_paging)
|
||||
config:saveSetting("annotations_paging", annotations)
|
||||
config:delSetting("bookmarks_paging")
|
||||
config:delSetting("highlight_paging")
|
||||
end
|
||||
else -- incompatible format loaded, or empty
|
||||
if has_bookmarks then -- save incompatible format if not empty
|
||||
local annotations = self:getAnnotationsFromBookmarksHighlights(bookmarks, highlights)
|
||||
config:saveSetting("annotations_paging", annotations)
|
||||
end
|
||||
-- load compatible format
|
||||
bookmarks = config:readSetting("bookmarks_rolling") or {}
|
||||
highlights = config:readSetting("highlight_rolling") or {}
|
||||
config:delSetting("bookmarks_rolling")
|
||||
config:delSetting("highlight_rolling")
|
||||
end
|
||||
else -- self.ui.paging
|
||||
if bookmarks_type == "number" then
|
||||
if config:has("bookmarks_rolling") then
|
||||
local bookmarks_rolling = config:readSetting("bookmarks_rolling")
|
||||
local highlights_rolling = config:readSetting("highlight_rolling")
|
||||
local annotations = self:getAnnotationsFromBookmarksHighlights(bookmarks_rolling, highlights_rolling)
|
||||
config:saveSetting("annotations_rolling", annotations)
|
||||
config:delSetting("bookmarks_rolling")
|
||||
config:delSetting("highlight_rolling")
|
||||
end
|
||||
else
|
||||
if has_bookmarks then
|
||||
local annotations = self:getAnnotationsFromBookmarksHighlights(bookmarks, highlights)
|
||||
config:saveSetting("annotations_rolling", annotations)
|
||||
end
|
||||
bookmarks = config:readSetting("bookmarks_paging") or {}
|
||||
highlights = config:readSetting("highlight_paging") or {}
|
||||
config:delSetting("bookmarks_paging")
|
||||
config:delSetting("highlight_paging")
|
||||
end
|
||||
end
|
||||
|
||||
self.annotations = self:getAnnotationsFromBookmarksHighlights(bookmarks, highlights, true)
|
||||
end
|
||||
|
||||
function ReaderAnnotation:onDocumentRerendered()
|
||||
self.needs_update = true
|
||||
end
|
||||
|
||||
function ReaderAnnotation:onCloseDocument()
|
||||
self:updatePageNumbers()
|
||||
end
|
||||
|
||||
function ReaderAnnotation:onSaveSettings()
|
||||
self:updatePageNumbers()
|
||||
self.ui.doc_settings:saveSetting("annotations", self.annotations)
|
||||
end
|
||||
|
||||
-- items handling
|
||||
|
||||
function ReaderAnnotation:updatePageNumbers()
|
||||
if self.needs_update and self.ui.rolling then -- triggered by ReaderRolling on document layout change
|
||||
for _, item in ipairs(self.annotations) do
|
||||
item.pageno = self.document:getPageFromXPointer(item.page)
|
||||
end
|
||||
end
|
||||
self.needs_update = nil
|
||||
end
|
||||
|
||||
function ReaderAnnotation:sortItems(items)
|
||||
if #items > 1 then
|
||||
local sort_func = self.ui.rolling and function(a, b) return self:isItemInPositionOrderRolling(a, b) end
|
||||
or function(a, b) return self:isItemInPositionOrderPaging(a, b) end
|
||||
table.sort(items, sort_func)
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderAnnotation:updatedAnnotations(needs_update, needs_sort)
|
||||
if needs_update then
|
||||
self.needs_update = true
|
||||
self:updatePageNumbers()
|
||||
needs_sort = true
|
||||
end
|
||||
if needs_sort then
|
||||
self:sortItems(self.annotations)
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderAnnotation:updateItemByXPointer(item)
|
||||
-- called by ReaderRolling:checkXPointersAndProposeDOMVersionUpgrade()
|
||||
local chapter = self.ui.toc:getTocTitleByPage(item.page)
|
||||
if chapter == "" then
|
||||
chapter = nil
|
||||
end
|
||||
if not item.drawer then -- page bookmark
|
||||
item.text = chapter and T(_("in %1"), chapter) or nil
|
||||
end
|
||||
item.chapter = chapter
|
||||
item.pageno = self.document:getPageFromXPointer(item.page)
|
||||
end
|
||||
|
||||
function ReaderAnnotation:isItemInPositionOrderRolling(a, b)
|
||||
local a_page = self.document:getPageFromXPointer(a.page)
|
||||
local b_page = self.document:getPageFromXPointer(b.page)
|
||||
if a_page == b_page then -- both items in the same page
|
||||
if a.drawer and b.drawer then -- both items are highlights, compare positions
|
||||
local compare_xp = self.document:compareXPointers(a.page, b.page)
|
||||
if compare_xp then
|
||||
if compare_xp == 0 then -- both highlights with the same start, compare ends
|
||||
compare_xp = self.document:compareXPointers(a.pos1, b.pos1)
|
||||
if compare_xp then
|
||||
return compare_xp > 0
|
||||
end
|
||||
logger.warn("Invalid xpointer in highlight:", a.pos1, b.pos1)
|
||||
return true
|
||||
end
|
||||
return compare_xp > 0
|
||||
end
|
||||
-- if compare_xp is nil, some xpointer is invalid and "a" will be sorted first to page 1
|
||||
logger.warn("Invalid xpointer in highlight:", a.page, b.page)
|
||||
return true
|
||||
end
|
||||
return not a.drawer -- have page bookmarks before highlights
|
||||
end
|
||||
return a_page < b_page
|
||||
end
|
||||
|
||||
function ReaderAnnotation:isItemInPositionOrderPaging(a, b)
|
||||
if a.page == b.page then -- both items in the same page
|
||||
if a.drawer and b.drawer then -- both items are highlights, compare positions
|
||||
local is_reflow = self.document.configurable.text_wrap -- save reflow mode
|
||||
self.document.configurable.text_wrap = 0 -- native positions
|
||||
-- sort start and end positions of each highlight
|
||||
local a_start, a_end, b_start, b_end, result
|
||||
if self.document:comparePositions(a.pos0, a.pos1) > 0 then
|
||||
a_start, a_end = a.pos0, a.pos1
|
||||
else
|
||||
a_start, a_end = a.pos1, a.pos0
|
||||
end
|
||||
if self.document:comparePositions(b.pos0, b.pos1) > 0 then
|
||||
b_start, b_end = b.pos0, b.pos1
|
||||
else
|
||||
b_start, b_end = b.pos1, b.pos0
|
||||
end
|
||||
-- compare start positions
|
||||
local compare_pos = self.document:comparePositions(a_start, b_start)
|
||||
if compare_pos == 0 then -- both highlights with the same start, compare ends
|
||||
result = self.document:comparePositions(a_end, b_end) > 0
|
||||
else
|
||||
result = compare_pos > 0
|
||||
end
|
||||
self.document.configurable.text_wrap = is_reflow -- restore reflow mode
|
||||
return result
|
||||
end
|
||||
return not a.drawer -- have page bookmarks before highlights
|
||||
end
|
||||
return a.page < b.page
|
||||
end
|
||||
|
||||
function ReaderAnnotation:getItemIndex(item, no_binary)
|
||||
local doesMatch
|
||||
if item.datetime then
|
||||
doesMatch = function(a, b)
|
||||
return a.datetime == b.datetime
|
||||
end
|
||||
else
|
||||
if self.ui.rolling then
|
||||
doesMatch = function(a, b)
|
||||
if a.text ~= b.text or a.pos0 ~= b.pos0 or a.pos1 ~= b.pos1 then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
else
|
||||
doesMatch = function(a, b)
|
||||
if a.text ~= b.text or a.pos0.page ~= b.pos0.page
|
||||
or a.pos0.x ~= b.pos0.x or a.pos1.x ~= b.pos1.x
|
||||
or a.pos0.y ~= b.pos0.y or a.pos1.y ~= b.pos1.y then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not no_binary then
|
||||
local isInOrder = self.ui.rolling and self.isItemInPositionOrderRolling or self.isItemInPositionOrderPaging
|
||||
local _start, _end, _middle = 1, #self.annotations
|
||||
while _start <= _end do
|
||||
_middle = bit.rshift(_start + _end, 1)
|
||||
local v = self.annotations[_middle]
|
||||
if doesMatch(item, v) then
|
||||
return _middle
|
||||
elseif isInOrder(self, item, v) then
|
||||
_end = _middle - 1
|
||||
else
|
||||
_start = _middle + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for i, v in ipairs(self.annotations) do
|
||||
if doesMatch(item, v) then
|
||||
return i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderAnnotation:getInsertionIndex(item)
|
||||
local isInOrder = self.ui.rolling and self.isItemInPositionOrderRolling or self.isItemInPositionOrderPaging
|
||||
local _start, _end, _middle, direction = 1, #self.annotations, 1, 0
|
||||
while _start <= _end do
|
||||
_middle = bit.rshift(_start + _end, 1)
|
||||
if isInOrder(self, item, self.annotations[_middle]) then
|
||||
_end, direction = _middle - 1, 0
|
||||
else
|
||||
_start, direction = _middle + 1, 1
|
||||
end
|
||||
end
|
||||
return _middle + direction
|
||||
end
|
||||
|
||||
function ReaderAnnotation:addItem(item)
|
||||
item.datetime = os.date("%Y-%m-%d %H:%M:%S")
|
||||
item.pageno = self.ui.paging and item.page or self.document:getPageFromXPointer(item.page)
|
||||
local index = self:getInsertionIndex(item)
|
||||
table.insert(self.annotations, index, item)
|
||||
return index
|
||||
end
|
||||
|
||||
-- info
|
||||
|
||||
function ReaderAnnotation:hasAnnotations()
|
||||
return #self.annotations > 0
|
||||
end
|
||||
|
||||
function ReaderAnnotation:getNumberOfAnnotations()
|
||||
return #self.annotations
|
||||
end
|
||||
|
||||
function ReaderAnnotation:getNumberOfHighlightsAndNotes() -- for Statistics plugin
|
||||
local highlights = 0
|
||||
local notes = 0
|
||||
for _, item in ipairs(self.annotations) do
|
||||
if item.drawer then
|
||||
if item.note then
|
||||
notes = notes + 1
|
||||
else
|
||||
highlights = highlights + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
return highlights, notes
|
||||
end
|
||||
|
||||
return ReaderAnnotation
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,719 @@
|
||||
local ConfirmBox = require("ui/widget/confirmbox")
|
||||
local Device = require("device")
|
||||
local Event = require("ui/event")
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local InputDialog = require("ui/widget/inputdialog")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
||||
local util = require("util")
|
||||
local T = require("ffi/util").template
|
||||
local _ = require("gettext")
|
||||
|
||||
local ReaderHandMade = WidgetContainer:extend{
|
||||
custom_toc_symbol = "\u{EAEC}", -- used in a few places
|
||||
}
|
||||
|
||||
function ReaderHandMade:init()
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
end
|
||||
|
||||
function ReaderHandMade:onReadSettings(config)
|
||||
self.toc_enabled = config:isTrue("handmade_toc_enabled")
|
||||
self.toc_edit_enabled = config:nilOrTrue("handmade_toc_edit_enabled")
|
||||
self.toc = config:readSetting("handmade_toc") or {}
|
||||
self.flows_enabled = config:isTrue("handmade_flows_enabled")
|
||||
self.flows_edit_enabled = config:nilOrTrue("handmade_flows_edit_enabled")
|
||||
self.flow_points = config:readSetting("handmade_flow_points") or {}
|
||||
self.inactive_flow_points = {}
|
||||
|
||||
-- Don't mess toc and flow_points made on that document if saved when
|
||||
-- we were using a different engine - backup them if that's the case.
|
||||
if #self.toc > 0 then
|
||||
local has_xpointers = self.toc[1].xpointer ~= nil
|
||||
if self.ui.rolling and not has_xpointers then
|
||||
config:saveSetting("handmade_toc_paging", self.toc)
|
||||
self.toc = config:readSetting("handmade_toc_rolling") or {}
|
||||
config:delSetting("handmade_toc_rolling")
|
||||
elseif self.ui.paging and has_xpointers then
|
||||
config:saveSetting("handmade_toc_rolling", self.toc)
|
||||
self.toc = config:readSetting("handmade_toc_paging") or {}
|
||||
config:delSetting("handmade_toc_paging")
|
||||
end
|
||||
else
|
||||
if self.ui.rolling and config:has("handmade_toc_rolling") then
|
||||
self.toc = config:readSetting("handmade_toc_rolling")
|
||||
config:delSetting("handmade_toc_rolling")
|
||||
elseif self.ui.paging and config:has("handmade_toc_paging") then
|
||||
self.toc = config:readSetting("handmade_toc_paging")
|
||||
config:delSetting("handmade_toc_paging")
|
||||
end
|
||||
end
|
||||
if #self.flow_points > 0 then
|
||||
local has_xpointers = self.flow_points[1].xpointer ~= nil
|
||||
if self.ui.rolling and not has_xpointers then
|
||||
config:saveSetting("handmade_flow_points_paging", self.flow_points)
|
||||
self.flow_points = config:readSetting("handmade_flow_points_rolling") or {}
|
||||
config:delSetting("handmade_flow_points_rolling")
|
||||
elseif self.ui.paging and has_xpointers then
|
||||
config:saveSetting("handmade_flow_points_rolling", self.flow_points)
|
||||
self.flow_points = config:readSetting("handmade_flow_points_paging") or {}
|
||||
config:delSetting("handmade_flow_points_paging")
|
||||
end
|
||||
else
|
||||
if self.ui.rolling and config:has("handmade_flow_points_rolling") then
|
||||
self.flow_points = config:readSetting("handmade_flow_points_rolling")
|
||||
config:delSetting("handmade_flow_points_rolling")
|
||||
elseif self.ui.paging and config:has("handmade_flow_points_paging") then
|
||||
self.flow_points = config:readSetting("handmade_flow_points_paging")
|
||||
config:delSetting("handmade_flow_points_paging")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderHandMade:onSaveSettings()
|
||||
self.ui.doc_settings:saveSetting("handmade_toc_enabled", self.toc_enabled)
|
||||
self.ui.doc_settings:saveSetting("handmade_toc_edit_enabled", self.toc_edit_enabled)
|
||||
if #self.toc > 0 then
|
||||
self.ui.doc_settings:saveSetting("handmade_toc", self.toc)
|
||||
else
|
||||
self.ui.doc_settings:delSetting("handmade_toc")
|
||||
end
|
||||
self.ui.doc_settings:saveSetting("handmade_flows_enabled", self.flows_enabled)
|
||||
self.ui.doc_settings:saveSetting("handmade_flows_edit_enabled", self.flows_edit_enabled)
|
||||
if #self.flow_points > 0 then
|
||||
self.ui.doc_settings:saveSetting("handmade_flow_points", self.flow_points)
|
||||
else
|
||||
self.ui.doc_settings:delSetting("handmade_flow_points")
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderHandMade:isHandmadeTocEnabled()
|
||||
return self.toc_enabled
|
||||
end
|
||||
|
||||
function ReaderHandMade:isHandmadeTocEditEnabled()
|
||||
return self.toc_edit_enabled
|
||||
end
|
||||
|
||||
function ReaderHandMade:isHandmadeHiddenFlowsEnabled()
|
||||
-- Even if currently empty, we return true, which allows showing '//' in
|
||||
-- the footer and let know hidden flows are enabled.
|
||||
return self.flows_enabled
|
||||
end
|
||||
|
||||
function ReaderHandMade:isHandmadeHiddenFlowsEditEnabled()
|
||||
return self.flows_edit_enabled
|
||||
end
|
||||
|
||||
function ReaderHandMade:onToggleHandmadeToc()
|
||||
self.toc_enabled = not self.toc_enabled
|
||||
self:setupToc()
|
||||
-- Have footer updated, so we may see this took effect
|
||||
self.view.footer:onUpdateFooter(self.view.footer_visible)
|
||||
end
|
||||
|
||||
function ReaderHandMade:onToggleHandmadeFlows()
|
||||
self.flows_enabled = not self.flows_enabled
|
||||
self:setupFlows()
|
||||
-- Have footer updated, so we may see this took effect
|
||||
self.view.footer:onUpdateFooter(self.view.footer_visible)
|
||||
end
|
||||
|
||||
function ReaderHandMade:addToMainMenu(menu_items)
|
||||
-- As it's currently impossible to create custom hidden flows on non-touch, and really impractical to create a custom toc, it's better hide these features completely for now.
|
||||
if not Device:isTouchDevice() then
|
||||
return
|
||||
end
|
||||
menu_items.handmade_toc = {
|
||||
text = _("Custom table of contents") .. " " .. self.custom_toc_symbol,
|
||||
checked_func = function() return self.toc_enabled end,
|
||||
callback = function()
|
||||
self:onToggleHandmadeToc()
|
||||
end,
|
||||
}
|
||||
menu_items.handmade_hidden_flows = {
|
||||
text = _("Custom hidden flows"),
|
||||
checked_func = function() return self.flows_enabled end,
|
||||
callback = function()
|
||||
self:onToggleHandmadeFlows()
|
||||
end,
|
||||
}
|
||||
--[[ Not yet implemented
|
||||
menu_items.handmade_page_numbers = {
|
||||
text = _("Custom page numbers"),
|
||||
checked_func = function() return false end,
|
||||
callback = function()
|
||||
end,
|
||||
}
|
||||
]]--
|
||||
menu_items.handmade_settings = {
|
||||
text = _("Custom layout features"),
|
||||
sub_item_table_func = function()
|
||||
return {
|
||||
{
|
||||
text = _("About custom table of contents") .. " " .. self.custom_toc_symbol,
|
||||
callback = function()
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _([[
|
||||
If the book has no table of contents or you would like to substitute it with your own, you can create a custom TOC. The original TOC (if available) will not be altered.
|
||||
|
||||
You can create, edit and remove chapters:
|
||||
- in Page browser, by long-pressing on a thumbnail;
|
||||
- on a book page, by selecting some text to be used as the chapter title.
|
||||
(Once you're done building it and don't want to see the buttons anymore, you can disable Edit mode.)
|
||||
|
||||
This custom table of contents is currently limited to a single level and can't have sub-chapters.]])
|
||||
})
|
||||
end,
|
||||
keep_menu_open = true,
|
||||
},
|
||||
{
|
||||
text = _("Edit mode"),
|
||||
enabled_func = function()
|
||||
return self:isHandmadeTocEnabled()
|
||||
end,
|
||||
checked_func = function()
|
||||
return self:isHandmadeTocEditEnabled()
|
||||
end,
|
||||
callback = function()
|
||||
self.toc_edit_enabled = not self.toc_edit_enabled
|
||||
self:updateHighlightDialog()
|
||||
end,
|
||||
},
|
||||
--[[ Not yet implemented
|
||||
{
|
||||
text = _("Add multiple chapter start page numbers"),
|
||||
},
|
||||
]]--
|
||||
{
|
||||
text = _("Clear custom table of contents"),
|
||||
enabled_func = function()
|
||||
return #self.toc > 0
|
||||
end,
|
||||
callback = function(touchmenu_instance)
|
||||
UIManager:show(ConfirmBox:new{
|
||||
text = _("Are you sure you want to clear your custom table of contents?"),
|
||||
ok_callback = function()
|
||||
self.toc = {}
|
||||
self.ui:handleEvent(Event:new("UpdateToc"))
|
||||
-- The footer may be visible, so have it update its chapter related items
|
||||
self.view.footer:onUpdateFooter(self.view.footer_visible)
|
||||
if touchmenu_instance then
|
||||
touchmenu_instance:updateItems()
|
||||
end
|
||||
end,
|
||||
})
|
||||
end,
|
||||
keep_menu_open = true,
|
||||
separator = true,
|
||||
},
|
||||
{
|
||||
text = _("About custom hidden flows"),
|
||||
callback = function()
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _([[
|
||||
Custom hidden flows can be created to exclude sections of the book from your normal reading flow:
|
||||
- hidden flows will automatically be skipped when turning pages within the regular flow;
|
||||
- pages part of hidden flows are assigned distinct page numbers and won't be considered in the various book & chapter progress and time to read features;
|
||||
- following direct links to pages in hidden flows will still work, including from the TOC or Book map.
|
||||
|
||||
This can be useful to exclude long footnotes or bibliography sections.
|
||||
It can also be handy when interested in reading only a subset of a book.
|
||||
|
||||
In Page browser, you can long-press on a thumbnail to start a hidden flow or restart the regular flow on this page.
|
||||
(Once you're done building it and don't want to see the button anymore, you can disable Edit mode.)
|
||||
|
||||
Hidden flows are shown with gray or hatched background in Book map and Page browser.]])
|
||||
})
|
||||
end,
|
||||
keep_menu_open = true,
|
||||
},
|
||||
{
|
||||
text = _("Edit mode"),
|
||||
enabled_func = function()
|
||||
return self:isHandmadeHiddenFlowsEnabled()
|
||||
end,
|
||||
checked_func = function()
|
||||
return self:isHandmadeHiddenFlowsEditEnabled()
|
||||
end,
|
||||
callback = function()
|
||||
self.flows_edit_enabled = not self.flows_edit_enabled
|
||||
end,
|
||||
},
|
||||
{
|
||||
text_func = function()
|
||||
return T(_("Clear inactive marked pages (%1)"), #self.inactive_flow_points)
|
||||
end,
|
||||
enabled_func = function()
|
||||
return #self.inactive_flow_points > 0
|
||||
end,
|
||||
callback = function(touchmenu_instance)
|
||||
UIManager:show(ConfirmBox:new{
|
||||
text = _("Inactive marked pages are pages that you tagged as start hidden flow or restart regular flow, but that other marked pages made them have no effect.\nAre you sure you want to clear them?"),
|
||||
ok_callback = function()
|
||||
for i=#self.inactive_flow_points, 1, -1 do
|
||||
table.remove(self.flow_points, self.inactive_flow_points[i])
|
||||
end
|
||||
self:updateDocFlows()
|
||||
self.ui:handleEvent(Event:new("UpdateToc"))
|
||||
self.ui:handleEvent(Event:new("InitScrollPageStates"))
|
||||
-- The footer may be visible, so have it update its dependant items
|
||||
self.view.footer:onUpdateFooter(self.view.footer_visible)
|
||||
if touchmenu_instance then
|
||||
touchmenu_instance:updateItems()
|
||||
end
|
||||
end,
|
||||
})
|
||||
end,
|
||||
keep_menu_open = true,
|
||||
},
|
||||
{
|
||||
text = _("Clear all marked pages"),
|
||||
enabled_func = function()
|
||||
return #self.flow_points > 0
|
||||
end,
|
||||
callback = function(touchmenu_instance)
|
||||
UIManager:show(ConfirmBox:new{
|
||||
text = _("Are you sure you want to clear all your custom hidden flows?"),
|
||||
ok_callback = function()
|
||||
self.flow_points = {}
|
||||
self:updateDocFlows()
|
||||
self.ui:handleEvent(Event:new("UpdateToc"))
|
||||
self.ui:handleEvent(Event:new("InitScrollPageStates"))
|
||||
-- The footer may be visible, so have it update its dependant items
|
||||
self.view.footer:onUpdateFooter(self.view.footer_visible)
|
||||
if touchmenu_instance then
|
||||
touchmenu_instance:updateItems()
|
||||
end
|
||||
end,
|
||||
})
|
||||
end,
|
||||
keep_menu_open = true,
|
||||
separator = true,
|
||||
},
|
||||
--[[ Not yet implemented
|
||||
{
|
||||
text = _("About custom page numbers"),
|
||||
},
|
||||
{
|
||||
text = _("Clear custom page numbers"),
|
||||
},
|
||||
]]--
|
||||
}
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
function ReaderHandMade:updateHandmagePages()
|
||||
if not self.ui.rolling then
|
||||
return
|
||||
end
|
||||
for _, item in ipairs(self.toc) do
|
||||
item.page = self.document:getPageFromXPointer(item.xpointer)
|
||||
end
|
||||
for _, item in ipairs(self.flow_points) do
|
||||
item.page = self.document:getPageFromXPointer(item.xpointer)
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderHandMade:onReaderReady()
|
||||
-- Called on load, and with a CRE document when reloading after partial rerendering.
|
||||
-- Notes:
|
||||
-- - ReaderFooter (from ReaderView) will have its onReaderReady() called before ours,
|
||||
-- and it may fillToc(). So, it may happen that the expensive validateAndFixToc()
|
||||
-- is called twice (first with the original ToC, then with ours).
|
||||
-- - ReaderRolling will have its onReaderReady() called after ours, and if we
|
||||
-- have set up hidden flows, we'll have overriden some documents methods so
|
||||
-- its cacheFlows() is a no-op.
|
||||
self:updateHandmagePages()
|
||||
-- Don't have each of these send their own events: we'll send them once afterwards
|
||||
self:setupFlows(true)
|
||||
self:setupToc(true)
|
||||
-- Now send the events
|
||||
if self.toc_enabled or self.flows_enabled then
|
||||
self.ui:handleEvent(Event:new("UpdateToc"))
|
||||
end
|
||||
if self.flows_enabled then
|
||||
-- Needed to skip hidden flows if PDF in scroll mode
|
||||
self.ui:handleEvent(Event:new("InitScrollPageStates"))
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderHandMade:onDocumentRerendered()
|
||||
-- Called with CRE document when partial rerendering not enabled
|
||||
self:updateHandmagePages()
|
||||
-- Don't have these send events their own events
|
||||
self:setupFlows(true)
|
||||
self:setupToc(true)
|
||||
-- ReaderToc will process this event just after us, and will
|
||||
-- call its onUpdateToc: we don't need to send it.
|
||||
-- (Also, no need for InitScrollPageStates with CRE.)
|
||||
end
|
||||
|
||||
function ReaderHandMade:setupToc(no_event)
|
||||
if self.toc_enabled then
|
||||
-- If enabled, plug one method into the document object,
|
||||
-- so it is used instead of the method from its class.
|
||||
self.document.getToc = function(this)
|
||||
-- ReaderToc may add fieds to ToC items: return a copy,
|
||||
-- so the one we will save doesn't get polluted.
|
||||
return util.tableDeepCopy(self.toc)
|
||||
end
|
||||
else
|
||||
-- If disabled, remove our plug so the method from the
|
||||
-- class gets used again.
|
||||
self.document.getToc = nil
|
||||
end
|
||||
self:updateHighlightDialog()
|
||||
if not no_event then
|
||||
self.ui:handleEvent(Event:new("UpdateToc"))
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderHandMade:updateHighlightDialog()
|
||||
if self.toc_enabled and self.toc_edit_enabled then
|
||||
-- We don't want this button to be the last wide one, and rather
|
||||
-- keep having the Search button being that one: so plug this one
|
||||
-- just before 12_search.
|
||||
self.ui.highlight:addToHighlightDialog("12_0_make_handmade_toc_item", function(this)
|
||||
return {
|
||||
text_func = function()
|
||||
local selected_text = this.selected_text
|
||||
local pageno, xpointer
|
||||
if self.ui.rolling then
|
||||
xpointer = selected_text.pos0
|
||||
else
|
||||
pageno = selected_text.pos0.page
|
||||
end
|
||||
local text
|
||||
if self:hasPageTocItem(pageno, xpointer) then
|
||||
text = _("Edit TOC chapter")
|
||||
else
|
||||
text = _("Start TOC chapter")
|
||||
end
|
||||
text = text .. " " .. self.custom_toc_symbol
|
||||
return text
|
||||
end,
|
||||
callback = function()
|
||||
local selected_text = this.selected_text
|
||||
this:onClose()
|
||||
self:addOrEditPageTocItem(nil, nil, selected_text)
|
||||
end,
|
||||
}
|
||||
end)
|
||||
else
|
||||
self.ui.highlight:removeFromHighlightDialog("12_0_make_handmade_toc_item")
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderHandMade:_getItemIndex(tab, pageno, xpointer)
|
||||
if not pageno and xpointer then
|
||||
pageno = self.document:getPageFromXPointer(xpointer)
|
||||
end
|
||||
-- (No need to use a binary search, our user made tables should
|
||||
-- not be too large)
|
||||
local matching_idx
|
||||
local insertion_idx = #tab + 1
|
||||
for i, item in ipairs(tab) do
|
||||
if item.page >= pageno then
|
||||
if item.page > pageno then
|
||||
insertion_idx = i
|
||||
break
|
||||
end
|
||||
-- Same page numbers.
|
||||
-- (We can trust page numbers, and only compare xpointers when both
|
||||
-- resolve to the same page.)
|
||||
if xpointer and item.xpointer then
|
||||
local order = self.document:compareXPointers(xpointer, item.xpointer)
|
||||
if order > 0 then -- item.xpointer after xpointer
|
||||
insertion_idx = i
|
||||
break
|
||||
elseif order == 0 then
|
||||
matching_idx = i
|
||||
break
|
||||
end
|
||||
else
|
||||
matching_idx = i
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
-- We always return an index, and a boolean stating if this index is a match or not
|
||||
-- (if not, the index is the insertion index if we ever want to insert an item with
|
||||
-- the asked pageno/xpointer)
|
||||
return matching_idx or insertion_idx, matching_idx and true or false
|
||||
end
|
||||
|
||||
function ReaderHandMade:hasPageTocItem(pageno, xpointer)
|
||||
local _, is_match = self:_getItemIndex(self.toc, pageno, xpointer)
|
||||
return is_match
|
||||
end
|
||||
|
||||
function ReaderHandMade:addOrEditPageTocItem(pageno, when_updated_callback, selected_text)
|
||||
local xpointer, title
|
||||
if selected_text then
|
||||
-- If we get selected_text, it's from the highlight dialog after text selection
|
||||
title = selected_text.text
|
||||
if self.ui.rolling then
|
||||
xpointer = selected_text.pos0
|
||||
pageno = self.document:getPageFromXPointer(xpointer)
|
||||
else
|
||||
pageno = selected_text.pos0.page
|
||||
end
|
||||
end
|
||||
local idx, item_found = self:_getItemIndex(self.toc, pageno, xpointer)
|
||||
local item
|
||||
if item_found then
|
||||
-- Chapter found: it's an update (edit text or remove item)
|
||||
item = self.toc[idx]
|
||||
else
|
||||
-- No chapter starting on this page or at this xpointer:
|
||||
-- we'll add a new item
|
||||
if not xpointer and self.ui.rolling and type(pageno) == "number" then
|
||||
xpointer = self.document:getPageXPointer(pageno)
|
||||
end
|
||||
item = {
|
||||
title = title or "",
|
||||
page = pageno,
|
||||
xpointer = xpointer,
|
||||
depth = 1, -- we only support 1-level chapters to keep the UX simple
|
||||
}
|
||||
end
|
||||
local dialog
|
||||
dialog = InputDialog:new{
|
||||
title = item_found and _("Edit custom TOC chapter") or _("Create new custom ToC chapter"),
|
||||
input = item.title,
|
||||
input_hint = _("TOC chapter title"),
|
||||
description = T(_([[On page %1.]]), pageno),
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
text = _("Cancel"),
|
||||
id = "close",
|
||||
callback = function()
|
||||
UIManager:close(dialog)
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = item_found and _("Save") or _("Create"),
|
||||
is_enter_default = true,
|
||||
callback = function()
|
||||
item.title = dialog:getInputText()
|
||||
UIManager:close(dialog)
|
||||
if not item_found then
|
||||
table.insert(self.toc, idx, item)
|
||||
end
|
||||
self.ui:handleEvent(Event:new("UpdateToc"))
|
||||
if when_updated_callback then
|
||||
when_updated_callback()
|
||||
end
|
||||
end,
|
||||
},
|
||||
},
|
||||
item_found and {
|
||||
{
|
||||
text = _("Remove"),
|
||||
callback = function()
|
||||
UIManager:close(dialog)
|
||||
table.remove(self.toc, idx)
|
||||
self.ui:handleEvent(Event:new("UpdateToc"))
|
||||
if when_updated_callback then
|
||||
when_updated_callback()
|
||||
end
|
||||
end,
|
||||
},
|
||||
selected_text and
|
||||
{
|
||||
text = _("Use selected text"),
|
||||
callback = function()
|
||||
-- Just replace the text without saving, to allow editing/fixing it
|
||||
dialog:setInputText(selected_text.text, nil, false)
|
||||
end,
|
||||
} or nil,
|
||||
} or nil,
|
||||
},
|
||||
}
|
||||
UIManager:show(dialog)
|
||||
dialog:onShowKeyboard()
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderHandMade:isInHiddenFlow(pageno)
|
||||
local idx, is_match = self:_getItemIndex(self.flow_points, pageno)
|
||||
if is_match then
|
||||
return self.flow_points[idx].hidden
|
||||
else
|
||||
if idx > 1 then
|
||||
return self.flow_points[idx-1].hidden
|
||||
end
|
||||
end
|
||||
-- Before any first flow_point: not hidden
|
||||
return false
|
||||
end
|
||||
|
||||
function ReaderHandMade:toggleHiddenFlow(pageno)
|
||||
local idx, is_match = self:_getItemIndex(self.flow_points, pageno)
|
||||
if is_match then
|
||||
-- Just remove the item (it feels we can, and that we don't
|
||||
-- have to just toggle its hidden value)
|
||||
table.remove(self.flow_points, idx)
|
||||
self:updateDocFlows()
|
||||
return
|
||||
end
|
||||
local hidden
|
||||
if idx > 1 then
|
||||
local previous_item = self.flow_points[idx-1]
|
||||
hidden = not previous_item.hidden
|
||||
else
|
||||
-- First item, can only start an hidden flow
|
||||
hidden = true
|
||||
end
|
||||
local xpointer
|
||||
if self.ui.rolling and type(pageno) == "number" then
|
||||
xpointer = self.document:getPageXPointer(pageno)
|
||||
end
|
||||
local item = {
|
||||
hidden = hidden,
|
||||
page = pageno,
|
||||
xpointer = xpointer,
|
||||
}
|
||||
table.insert(self.flow_points, idx, item)
|
||||
-- We could remove any followup item(s) with the same hidden state, but by keeping them,
|
||||
-- we allow users to adjust the start of a flow without killing its end. One can clean
|
||||
-- all the unnefective ones via the "Clear inactive marked pages" menu item.
|
||||
self:updateDocFlows()
|
||||
end
|
||||
|
||||
function ReaderHandMade:updateDocFlows()
|
||||
local flows = {}
|
||||
local inactive_flow_points = {}
|
||||
-- (getPageCount(), needing the document to be fully loaded, is not available
|
||||
-- until ReaderReady, so be sure this is called only after ReaderReady.)
|
||||
local nb_pages = self.document:getPageCount()
|
||||
local nb_hidden_pages = 0
|
||||
local cur_hidden_flow
|
||||
for i, point in ipairs(self.flow_points) do
|
||||
if point.hidden and not cur_hidden_flow then
|
||||
cur_hidden_flow = {point.page, 0}
|
||||
elseif not point.hidden and cur_hidden_flow then
|
||||
local cur_hidden_pages = point.page - cur_hidden_flow[1]
|
||||
if cur_hidden_pages > 0 then
|
||||
cur_hidden_flow[2] = cur_hidden_pages
|
||||
nb_hidden_pages = nb_hidden_pages + cur_hidden_pages
|
||||
table.insert(flows, cur_hidden_flow)
|
||||
end
|
||||
cur_hidden_flow = nil
|
||||
else
|
||||
table.insert(inactive_flow_points, i)
|
||||
end
|
||||
end
|
||||
if cur_hidden_flow then
|
||||
local cur_hidden_pages = nb_pages + 1 - cur_hidden_flow[1]
|
||||
if cur_hidden_pages > 0 then
|
||||
cur_hidden_flow[2] = cur_hidden_pages
|
||||
nb_hidden_pages = nb_hidden_pages + cur_hidden_pages
|
||||
table.insert(flows, cur_hidden_flow)
|
||||
end
|
||||
end
|
||||
local first_linear_page
|
||||
local last_linear_page
|
||||
local prev_flow
|
||||
for i, flow in ipairs(flows) do
|
||||
if not prev_flow or prev_flow[1] + prev_flow[2] < flow[1] then
|
||||
if not first_linear_page and flow[1] > 1 then
|
||||
first_linear_page = prev_flow and prev_flow[1] + prev_flow[2] or 1
|
||||
end
|
||||
last_linear_page = flow[1] - 1
|
||||
end
|
||||
prev_flow = flow
|
||||
end
|
||||
if not prev_flow or prev_flow[1] + prev_flow[2] < nb_pages then
|
||||
last_linear_page = nb_pages
|
||||
end
|
||||
if not first_linear_page then -- no flow met
|
||||
first_linear_page = 1
|
||||
end
|
||||
-- CreDocument adds and item with key [0] with info about the main flow
|
||||
flows[0] = {first_linear_page, nb_pages - nb_hidden_pages}
|
||||
self.last_linear_page = last_linear_page
|
||||
self.flows = flows
|
||||
self.inactive_flow_points = inactive_flow_points
|
||||
-- We plug our flows table into the document, as some code peeks into it
|
||||
self.document.flows = self.flows
|
||||
end
|
||||
|
||||
function ReaderHandMade:setupFlows(no_event)
|
||||
if self.flows_enabled then
|
||||
self:updateDocFlows()
|
||||
-- If enabled, plug some methods into the document object,
|
||||
-- so they are used instead of the methods from its class.
|
||||
self.document.hasHiddenFlows = function(this)
|
||||
return true
|
||||
end
|
||||
self.document.cacheFlows = function(this)
|
||||
return
|
||||
end
|
||||
self.document.getPageFlow = function(this, page)
|
||||
for i, flow in ipairs(self.flows) do
|
||||
if page < flow[1] then
|
||||
return 0 -- page is not in a hidden flow
|
||||
end
|
||||
if page < flow[1] + flow[2] then
|
||||
return i
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
self.document.getFirstPageInFlow = function(this, flow)
|
||||
return self.flows[flow][1]
|
||||
end
|
||||
self.document.getTotalPagesInFlow = function(this, flow)
|
||||
return self.flows[flow][2]
|
||||
end
|
||||
self.document.getPageNumberInFlow = function(this, page)
|
||||
local nb_hidden_pages = 0
|
||||
for i, flow in ipairs(self.flows) do
|
||||
if page < flow[1] then
|
||||
break -- page is not in a hidden flow
|
||||
end
|
||||
if page < flow[1] + flow[2] then
|
||||
return page - flow[1] + 1
|
||||
end
|
||||
nb_hidden_pages = nb_hidden_pages + flow[2]
|
||||
end
|
||||
return page - nb_hidden_pages
|
||||
end
|
||||
self.document.getLastLinearPage = function(this)
|
||||
return self.last_linear_page
|
||||
end
|
||||
-- We can reuse as-is these ones from CreDocument, which uses the ones defined above.
|
||||
-- Note: these could probably be rewritten and simplified.
|
||||
local CreDocument = require("document/credocument")
|
||||
self.document.getTotalPagesLeft = CreDocument.getTotalPagesLeft
|
||||
self.document.getNextPage = CreDocument.getNextPage
|
||||
self.document.getPrevPage = CreDocument.getPrevPage
|
||||
else
|
||||
-- Remove all our overrides, so the class methods can be used again
|
||||
self.document.hasHiddenFlows = nil
|
||||
self.document.cacheFlows = nil
|
||||
self.document.getPageFlow = nil
|
||||
self.document.getFirstPageInFlow = nil
|
||||
self.document.getTotalPagesInFlow = nil
|
||||
self.document.getPageNumberInFlow = nil
|
||||
self.document.getLastLinearPage = nil
|
||||
self.document.getTotalPagesLeft = nil
|
||||
self.document.getNextPage = nil
|
||||
self.document.getPrevPage = nil
|
||||
self.document.flows = nil
|
||||
if self.document.cacheFlows then
|
||||
self.document:cacheFlows()
|
||||
end
|
||||
end
|
||||
if not no_event then
|
||||
self.ui:handleEvent(Event:new("UpdateToc"))
|
||||
-- Needed to skip hidden flows if PDF in scroll mode
|
||||
self.ui:handleEvent(Event:new("InitScrollPageStates"))
|
||||
end
|
||||
end
|
||||
|
||||
return ReaderHandMade
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,57 @@
|
||||
local cs_keyboard = require("util").tableDeepCopy(require("ui/data/keyboardlayouts/sk_keyboard"))
|
||||
|
||||
local keys = cs_keyboard.keys
|
||||
|
||||
keys[1][2][1] = {
|
||||
"2",
|
||||
north = "ě",
|
||||
northeast = "Ě",
|
||||
east = "~",
|
||||
southeast = "/",
|
||||
south = "@",
|
||||
southwest = "https://",
|
||||
west = "http://",
|
||||
northwest = "Ĺ",
|
||||
alt_label = "ě",
|
||||
}
|
||||
keys[1][2][2] = {
|
||||
"ě",
|
||||
north = "2",
|
||||
northeast = "Ě",
|
||||
east = "~",
|
||||
southeast = "/",
|
||||
south = "@",
|
||||
southwest = "https://",
|
||||
west = "http://",
|
||||
northwest = "ĺ",
|
||||
alt_label = "2",
|
||||
}
|
||||
|
||||
keys[1][5][1] = {
|
||||
"5",
|
||||
north = "ř",
|
||||
northeast = "Ř",
|
||||
east = "¾",
|
||||
southeast = "‱",
|
||||
south = "%",
|
||||
southwest = "‰",
|
||||
west = "⅔",
|
||||
northwest = "Ŕ",
|
||||
alt_label = "ř",
|
||||
}
|
||||
keys[1][5][2] = {
|
||||
"ř",
|
||||
north = "5",
|
||||
northeast = "Ř",
|
||||
east = "¼",
|
||||
southeast = "‱",
|
||||
south = "%",
|
||||
southwest = "‰",
|
||||
west = "½",
|
||||
northwest = "ŕ",
|
||||
alt_label = "5",
|
||||
}
|
||||
|
||||
keys[5][4].label = "mezera"
|
||||
|
||||
return cs_keyboard
|
@ -0,0 +1,10 @@
|
||||
-- Start with the norwegian keyboard layout (deep copy, to not alter it)
|
||||
local da_keyboard = require("util").tableDeepCopy(require("ui/data/keyboardlayouts/no_keyboard"))
|
||||
|
||||
local keys = da_keyboard.keys
|
||||
|
||||
-- swap "Ø" and "Æ", and "ø" and "æ"
|
||||
keys[3][10][1], keys[3][11][1] = keys[3][11][1], keys[3][10][1]
|
||||
keys[3][10][2], keys[3][11][2] = keys[3][11][2], keys[3][10][2]
|
||||
|
||||
return da_keyboard
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue