mirror of
https://gitee.com/spark-store-project/spark-store
synced 2025-12-15 21:32:05 +08:00
Compare commits
761 Commits
non-dtk
...
4.2.3.2Rea
| Author | SHA1 | Date | |
|---|---|---|---|
| e6561e0a07 | |||
| 9616deb4b6 | |||
| 96d2ea6669 | |||
| d57c43a2b7 | |||
| 40eadaca35 | |||
| 21bcb67a73 | |||
| 890718fdbb | |||
| 1613825b7c | |||
| bcb399dc30 | |||
| cd581d4de9 | |||
| 41ef63ec4a | |||
| 02419bfdcb | |||
| b67fd11fd5 | |||
| 9a7a80223a | |||
| aa85ee53a8 | |||
| ac45f5eec9 | |||
| 84cc4a9208 | |||
| 795a6ca709 | |||
| dab4606e9b | |||
| 1954196ba1 | |||
| fc0edab44c | |||
| a04cf4e6d9 | |||
| e85576e5f0 | |||
| efba72002a | |||
| 8ff46e554f | |||
| 57db01aeaf | |||
| 0ceb99e121 | |||
| 83b539e7da | |||
| ce6c0a4613 | |||
| cf59aeb4eb | |||
| 17ca13cf00 | |||
|
|
b99225bd3c | ||
| 8f39710cdb | |||
| 7ec6be1969 | |||
| 1543d75339 | |||
| 77eb0d84c7 | |||
| 68ddb3ffcc | |||
| 58ea0249d8 | |||
| eb01bf253e | |||
| c22ce6290b | |||
| 1f7608bf77 | |||
| 16115a455b | |||
| ce680d54f9 | |||
| a90699163f | |||
| 3edf39b4ef | |||
| f5c879b369 | |||
| 2bd9c4a440 | |||
| f494f15922 | |||
| d5df4057e9 | |||
| dc07b7cb02 | |||
| 1bb0bf7d71 | |||
| cf00d54355 | |||
| 1ea7067379 | |||
| 29ad3cc72d | |||
| dfe57bf2c3 | |||
| b37f8d7f7e | |||
| b51b248566 | |||
| 21baf598d7 | |||
| 2c6d706c58 | |||
| 1b1f7578d0 | |||
| 9275425bdf | |||
| 22b1d66c07 | |||
| a3e1d19ac3 | |||
| 762caae49f | |||
| 4e4ee205de | |||
| 9d4e19e606 | |||
| 4d142ec614 | |||
| 80cf746f90 | |||
| 3b83b335be | |||
| 1f0a0e48ff | |||
| 432215e040 | |||
| 1a65386c6b | |||
|
|
757dced302 | ||
|
|
854caafd6b | ||
| 1332107642 | |||
|
|
4825417de8 | ||
| 0001df153b | |||
| f88b38dd39 | |||
| 3f2404ec1c | |||
| 5b822194fa | |||
| 33ea9ee065 | |||
| d742e85332 | |||
|
|
8dfb1fbe2f | ||
| 4114b51d87 | |||
|
|
deec70f14b | ||
| ee0d3f87ec | |||
| 80adfd5dc1 | |||
| e81c846432 | |||
| 03d60d74f1 | |||
| 4f2c5f1bdc | |||
|
|
da03261cbb | ||
|
|
48d551424a | ||
|
|
ab6c3d37d2 | ||
| de2db98324 | |||
|
|
66d1aacbbe | ||
| 57f1b69663 | |||
|
|
cb093dcc2b | ||
| eaf268a10d | |||
|
|
1074e941a6 | ||
|
|
05cb318737 | ||
| 4ce19e25e5 | |||
| 17c152ce8b | |||
|
|
9275074e10 | ||
| e69eaa6296 | |||
| 35bc1efbad | |||
| 9420959023 | |||
| 7a16b5c52f | |||
| 24519e6560 | |||
| 2104b99208 | |||
|
|
cf549c540d | ||
|
|
4b40e3caca | ||
| 1a89c2a1a6 | |||
| b1fd1a3c3c | |||
| 50e895938b | |||
| 18d2b1edbb | |||
|
|
f91ee56d97 | ||
| 41a6a3fc04 | |||
| 1266b16d83 | |||
| 4359a9c58d | |||
| c243a30dec | |||
| f629dca03c | |||
| f2e1219a83 | |||
| e2f27c7746 | |||
| 72ba481180 | |||
| 8d41966d67 | |||
| f2a4ce3b25 | |||
| 0b2290344b | |||
| a7cb44348d | |||
| 384d4b300d | |||
| 19a1ba4289 | |||
| c160f4105d | |||
| 682a6e38d6 | |||
| e4a3a974b5 | |||
| eb38f2af05 | |||
| 7163f8ee80 | |||
| a934373f1e | |||
| ce6ded25f2 | |||
| f707fef65b | |||
| 721e6580c9 | |||
| e20572b28d | |||
| 05a6af8f86 | |||
| d4e84344c3 | |||
| f856060d3d | |||
| 49829f8d3c | |||
| 4cd3ca56e0 | |||
| 0538777ceb | |||
| d3b303c66c | |||
| 98c4e8a699 | |||
| 69b7cbe472 | |||
| 539a21ccec | |||
| eb40a32cc2 | |||
| 440b7ea88d | |||
| 36d273dd5e | |||
| 6bdc1ee51c | |||
| ecfa9a166d | |||
| 199700495c | |||
| 0bafab7f94 | |||
| dd4deff19d | |||
| 8b88573283 | |||
| 2717cf695c | |||
| 385803754f | |||
| 8ba377cf0b | |||
| c21d4dac96 | |||
| a85200338c | |||
| 5d34dd6413 | |||
| bd3daeba75 | |||
|
|
8b2a61e4b2 | ||
| 116f14845e | |||
| 77bf544c59 | |||
| f809d7c15d | |||
| 1f7f3edbba | |||
| 90f6b6a574 | |||
| 3e51ce8381 | |||
| b7df4a5801 | |||
| 980e4a17d9 | |||
| d5248f4c1b | |||
|
|
c169622806 | ||
|
|
cc54014b29 | ||
|
|
c636e0882b | ||
|
|
4120af7e24 | ||
| 09a5789c26 | |||
| fc658f324d | |||
| 2861b0573b | |||
| 2ab4ebc0e3 | |||
| e344b16aa0 | |||
| 30b65350ca | |||
| 0db8c8b1bb | |||
| 9e25584bdc | |||
| ee6d6f145f | |||
| 347f6e918f | |||
| 0fcbd15ab4 | |||
| 6bdac50059 | |||
| f45b2af260 | |||
| d744c1d978 | |||
| 0544761094 | |||
| e645c5e526 | |||
| d75fdd9f80 | |||
| 30f74db0dc | |||
| 2d0069ce18 | |||
| 48b91d1887 | |||
| 32cb3d7453 | |||
|
|
ba3071d62b | ||
|
|
dca80a3fbb | ||
| f99c0839dd | |||
| 8850cfd4a3 | |||
| bec8a14baf | |||
| 1b9c925183 | |||
| 09221bc2e9 | |||
| 98da0c22fc | |||
| cadbb351fb | |||
| 2de237ce83 | |||
| 511fbaa0b0 | |||
| a6d85b6ade | |||
| 5889ac3045 | |||
| c1ba14bbd0 | |||
| 7bdccc7783 | |||
|
|
3a54cba3e5 | ||
| 79463246fb | |||
| cc8ff5eff2 | |||
| 613327b2cc | |||
| 8b31db843c | |||
| fd4fdbe970 | |||
| 89a3ab0b4c | |||
| 0179c2f04f | |||
| 8918e63484 | |||
| 6d1fb80f0f | |||
| 4add78c6d7 | |||
|
|
89c32013bf | ||
|
|
8f7ce54584 | ||
| 65f3114078 | |||
| 00386c7aeb | |||
|
|
3a89394838 | ||
| a3f3a9153a | |||
| cc582da96b | |||
| d5877ffe00 | |||
| 58f590560e | |||
| f636b82f02 | |||
| 877c3aafd1 | |||
|
|
65c26f035b | ||
|
|
ba331cb3fb | ||
|
|
27c95991c5 | ||
| ffd31445b9 | |||
| 02fd887116 | |||
| fd3df91017 | |||
| c9d0c8b751 | |||
| adf9032897 | |||
| 2c1679d0af | |||
| 95f9806c1c | |||
| 252d2f491d | |||
| e2f6d97f94 | |||
| 48fd79e9be | |||
| 07eb9493cb | |||
| 217b299a67 | |||
| 9738c41bb9 | |||
| e17c50d396 | |||
| 795c3308d3 | |||
| f026844dba | |||
| 1a05ad05aa | |||
| 9c91d0a5a0 | |||
| a27c8b9ace | |||
| 68d91f71ba | |||
| fca2086d9f | |||
| 83ee212484 | |||
| 922cb6a34f | |||
| eb00159691 | |||
| 3b18fc94b5 | |||
| 375243503f | |||
| 9b31040efd | |||
| ac5d86db92 | |||
| 86f270eca9 | |||
| f5bb95da12 | |||
| eadc8dd875 | |||
| 91b628e7a6 | |||
| 6bd8fc7a1e | |||
| c2e665ecb6 | |||
| 50cf537e1d | |||
| 0f0a5795af | |||
| 09f96d596a | |||
| a2cb7ef112 | |||
| 2ed2512d6c | |||
| d720d0670d | |||
| da2c019da0 | |||
| ce8c058265 | |||
| 7f3eadf3a7 | |||
| 44ea6755f9 | |||
| 9df0e3a3b3 | |||
| 13550ebbec | |||
| 077034b1d6 | |||
| ac21f67030 | |||
| 292d4aa5c9 | |||
| fb4d78ce1d | |||
| ad25606ef9 | |||
| 6ace772a09 | |||
| bfc68fbf6f | |||
| e2c9f1100d | |||
| 77c2e2ebc8 | |||
| eb06f33269 | |||
| e2c8eb79a0 | |||
| c825e4b39c | |||
| 79d12f2409 | |||
| 382b2de5ca | |||
| 0fea4c13ef | |||
| ff84576aab | |||
| 2b2ebc111e | |||
| 20fc6f5a77 | |||
| 83bfb8dfd5 | |||
| db5b85db7d | |||
| 271a7e33f4 | |||
| 478db77d36 | |||
| a787745752 | |||
| 758b752d6e | |||
| 60ed4c5aff | |||
| 2d3366990a | |||
| b63ae13a3e | |||
| 6ff58adffa | |||
| f948c8905a | |||
| a31f724b65 | |||
| 8c9c2fcf11 | |||
| e251616129 | |||
| 6655e14b6c | |||
|
|
b3aa2036f8 | ||
| 8ad1156e3c | |||
| b5495fa66e | |||
| 333a1168d4 | |||
| 8a54dd92a3 | |||
| ae1c50893d | |||
| dd0605d0ba | |||
| 0817901a59 | |||
| e171904a34 | |||
| abd0e47c69 | |||
| 1c24079406 | |||
| 67c0cbf27b | |||
| 5cc34e7e3d | |||
| 98cf333386 | |||
| 562b582f72 | |||
| 73917eeeb1 | |||
| c5913b4198 | |||
| c0e9815d9d | |||
| 050fe964dd | |||
| 6981a4f476 | |||
| e72d123a40 | |||
| a10390a6e3 | |||
| 3fecd41c4f | |||
| f0604afcfc | |||
| 2ec4b1f4d4 | |||
| fbffe12501 | |||
| df7b49dbe2 | |||
| 9d93966124 | |||
| 977b2ebdc9 | |||
| 28ed452bb0 | |||
| 512d86feac | |||
| 8e1e0cea7a | |||
| d2214114fb | |||
| c90232022e | |||
| 84a1554b4b | |||
| 71dbf9b958 | |||
| 9d12086f09 | |||
|
|
54a55e15a9 | ||
| 5385e2d1b1 | |||
| 1e468ba774 | |||
| 25efce0017 | |||
| 707a2b5e4c | |||
| b9121c13ab | |||
| 9c80179493 | |||
| 2a89135d1a | |||
| b91e0142f4 | |||
| 55897e3cb9 | |||
| f17fcdfe85 | |||
| 9046a3a965 | |||
| 1e72fcb7f2 | |||
| 9007bdf3d3 | |||
| afd926ae4a | |||
| 4949d67852 | |||
| 5f5d71fbd0 | |||
| 9fd8f64195 | |||
| c32ffb7cd2 | |||
| af9217b1dc | |||
| 93e218dd53 | |||
| 4de32fa8a6 | |||
| 2d59a61796 | |||
| 7abdd90215 | |||
| cbd594e217 | |||
| 42b6a20c97 | |||
| 110adc995d | |||
| cd6d0ac133 | |||
| 568e73de07 | |||
| 62c8841c50 | |||
| 6fd611919b | |||
| 77a84785de | |||
| 9969f4f2fc | |||
| 833a8ec14b | |||
| dd679f3f26 | |||
| 5411a832dc | |||
| 0aeadb5526 | |||
| 91fd97b878 | |||
| f2cf344f62 | |||
| 8d84e433a6 | |||
| a6e9dac2f9 | |||
| 495ef3292e | |||
| 5900b3cdf3 | |||
| e644214263 | |||
| 2b76f5e202 | |||
| 6fe06667eb | |||
| f61e3a6ede | |||
| bddbbcc2e8 | |||
| 8310a59df8 | |||
| 05cfdbb318 | |||
| b5488b6c32 | |||
| 6cec12be9d | |||
| 53f9746ebf | |||
| b68ef5aab1 | |||
| c6daf5159c | |||
| b0453c7a8a | |||
| c7ee32a452 | |||
| e1d25e401f | |||
| 6b78dce87e | |||
| e5a198e1d8 | |||
| 1780110e33 | |||
| 19901b0d7d | |||
| d24af0461b | |||
| 31a574ec8b | |||
| 3feae61b1b | |||
| eaf65a326c | |||
| 13da2bc441 | |||
| 5420bad0ee | |||
| 8465c9ad2d | |||
| 5562e2b5d1 | |||
| a09425f361 | |||
| 18db530c0d | |||
| 03263edf8c | |||
| cd13a1ce08 | |||
| 1c5f31da6f | |||
| cafb4d1dfe | |||
| 828f1a0f05 | |||
| b03795e364 | |||
| c54c13d822 | |||
| fdc9550100 | |||
| 458cc49302 | |||
| e11afad89b | |||
| 43ae031131 | |||
| dd6780d636 | |||
| 42368a0245 | |||
| 8ca0035107 | |||
| 10332c59e0 | |||
| 09a1c9f710 | |||
| ba29c4171c | |||
| 3b9dde23e7 | |||
| 746e9bd3d6 | |||
| d7f0ee983b | |||
| 3feec88f7b | |||
| c0ffb64a86 | |||
| 8c08b7e995 | |||
| 4d7e766d75 | |||
| 09115c3961 | |||
| 63998bbce4 | |||
| 967f62f825 | |||
| e8ae0325e0 | |||
| 66a4563b51 | |||
| 330ae3eeb8 | |||
| 0534c39ee5 | |||
| 04047c1e44 | |||
| 5e501b9d17 | |||
| 5a434a9b7d | |||
| e554aec98d | |||
| ab0f5e6613 | |||
| 59607f6b34 | |||
| a13f0ddcb7 | |||
| fec604b481 | |||
| 085eddd66f | |||
| 30860802dd | |||
| 30f36ff35d | |||
|
|
81993625ba | ||
| 87b68aca1e | |||
| 10125c5816 | |||
| 21d33ec347 | |||
| ad57aa26ff | |||
| 8902c81b9e | |||
| 0ad4b6c82c | |||
| 189a0b4939 | |||
| c65d7b86df | |||
| e269e6ca57 | |||
| aff593eba8 | |||
| beaeac60a3 | |||
| 11d68fb4b5 | |||
| e7680fe2a0 | |||
| 19dff7fb56 | |||
| 67b314d0d2 | |||
| 63b28adaf8 | |||
| 8741973cca | |||
| 8e3787ab07 | |||
| f7d07e0bf9 | |||
| 9e4df5c5c2 | |||
| 829a08d40a | |||
| 411bbe5935 | |||
| 5d5fbfbad4 | |||
| af89e64478 | |||
| c93c221cf1 | |||
| afee0966c8 | |||
| 2df5363c2c | |||
| 971a5dcc63 | |||
| a252e7b724 | |||
| d3987a20ec | |||
| 932e754b88 | |||
| 72a771b0f1 | |||
| b75fbe5674 | |||
| 6617522a7c | |||
| 1733d9853d | |||
| 55c6c13e50 | |||
| 9c2f326268 | |||
| b1a6f79961 | |||
| 1561d511d1 | |||
| 2d2b431df7 | |||
| c87272b463 | |||
| da632d41e7 | |||
| 96b0f0f2be | |||
| 8a7d09b716 | |||
| fcdcd84462 | |||
| 8f63b58062 | |||
| 2c8d38a0da | |||
| 807777e3dc | |||
| 86a9e66e29 | |||
| 15938d0da4 | |||
| 1331c369ad | |||
| d5182c760b | |||
| f9dc1cd09d | |||
| 230c860d91 | |||
| 69f2d6e626 | |||
| 6b560492e8 | |||
| 8886016357 | |||
| 9a74368ef5 | |||
| cf5e1cae76 | |||
| 6d23aaa07c | |||
| 3740b551ef | |||
| 4c7d50d117 | |||
| 6318b5f51d | |||
| 2f94e78c32 | |||
| fecda52294 | |||
| 8cefdbaca0 | |||
| 0da714b35a | |||
| 379c5a857d | |||
| 3b349d43ad | |||
| b856734843 | |||
| 238c43b79e | |||
| 855b18cfa6 | |||
| bc897969f8 | |||
| 52af8a8229 | |||
| 5220b886de | |||
| 5be7923e60 | |||
| 6ca6f63b1f | |||
| bda0426a3b | |||
| a75b7b1e57 | |||
| 8054f85ada | |||
| 6f23d07929 | |||
| b73d97d65d | |||
| bc6584eacc | |||
| c9e01d10fe | |||
| c3b9763aa8 | |||
| 398cd512d7 | |||
| 0c0ff452ae | |||
| e6d3b035db | |||
| 5e88f7c1eb | |||
| b639a9d726 | |||
| e2f6a2b3c2 | |||
| c826a3927c | |||
| 0c367799b7 | |||
| 0e351a667a | |||
| e8612f304a | |||
| 114b5cdfe5 | |||
| a563d99bc4 | |||
| b1cb765b6e | |||
| 49c5583ea9 | |||
| b0dfd6a3da | |||
| a63c1202bd | |||
| dfe30f9d6d | |||
| b00f3fa501 | |||
| 03f35782c6 | |||
| 8f192d17ec | |||
| 57bbc9536a | |||
| 9f7b46b600 | |||
| 0dc594b3f1 | |||
| cdb4fc05a1 | |||
| 198384c552 | |||
| 958988d93c | |||
| 5f9599c47d | |||
| 766dc8b88a | |||
| 20d34a7369 | |||
| a0c14e7397 | |||
| f24565804d | |||
| 244176098c | |||
| ac0a38e670 | |||
| af7990e069 | |||
| f8dbca8f6f | |||
| a064b7b534 | |||
| 289f3020fe | |||
| 9cd974fed9 | |||
| 4d97a1e87b | |||
|
|
d326e8919f | ||
|
|
1828a60ff1 | ||
| 865322c85f | |||
| c22c76efc2 | |||
| 415dd1a63c | |||
|
|
7e105b59b0 | ||
| 84b3340687 | |||
| 2da576aeab | |||
| fb94448692 | |||
| 6ba7601efa | |||
| 4ea6c90e78 | |||
| f3633bb19d | |||
| 090b9a279f | |||
| 1bf8a57802 | |||
| 01f2610e0a | |||
| 3e3c3140d0 | |||
| 6ca024b6f3 | |||
| c0ea5824b1 | |||
| ee60b2e7f6 | |||
| 53ae863823 | |||
| 3dae7db89a | |||
| 3b3bf8f0de | |||
| 00f9b62b80 | |||
| 0916a0a97e | |||
|
|
c6505c1c14 | ||
| 4f600f3ec7 | |||
| bf5d0cb75f | |||
| 4ca292bd34 | |||
| 12cf0a3515 | |||
| 18279ec00d | |||
| e415798ee0 | |||
| 89740ad953 | |||
| 3eddb4ce71 | |||
| 239a788019 | |||
| dc6210b545 | |||
| 94d6a566ca | |||
| c66c5c6ca3 | |||
| c974349c9f | |||
| 42362fd0ca | |||
| 63bc01c43d | |||
| 280cd983cb | |||
| 05e95b42e0 | |||
| 2614b4ae05 | |||
| e8d55cadb6 | |||
| 3534b815cc | |||
| ef75e89916 | |||
| e4daffd052 | |||
| 9c29ca2e38 | |||
| 733751db8e | |||
| db739181f2 | |||
| 0bd87eb100 | |||
| 8b690e8dea | |||
| 9329c939d7 | |||
| 232fe777e5 | |||
| 000fcf8c9d | |||
| 30bc12a8b6 | |||
| a7385aff1e | |||
| c5b786d9e6 | |||
| 55d254e147 | |||
| cccad380a4 | |||
| afe5c00af7 | |||
| 55e7fd836c | |||
| 2959d72d1c | |||
| 95b4608e82 | |||
| edef44eea8 | |||
| a4b9bd6a17 | |||
| a165cd7d67 | |||
| 387d21b29f | |||
| 63b8ae5ae7 | |||
| 9ae4fa8372 | |||
| 1eb2f8df91 | |||
| ce1de9c367 | |||
| 80284b22cb | |||
| ad1b69493a | |||
| 7ca5e9b0d0 | |||
| 873a83e6b9 | |||
| da8ee30fbd | |||
| 6d84fa0fe5 | |||
| 41d6272526 | |||
| 0f7bdf484f | |||
| bc67bcb6f0 | |||
| 134586b580 | |||
| d645b26c62 | |||
| fdc818cdb4 | |||
| 1f493a8aca | |||
| 463a8d0c04 | |||
| 932bbd7995 | |||
| 5f45abc484 | |||
| 820ad08bf4 | |||
| 2ddfb3f192 | |||
| b3ca6878ec | |||
| ae6f2354bb | |||
| 591556a7c8 | |||
| 0bcf8a1ee9 | |||
| 15b6a22f49 | |||
| 7f1f5528ef | |||
| 158ba884b1 | |||
| d9a50e7b44 | |||
| 72019f7cce | |||
| c4b26045d9 | |||
| e14b1baaab | |||
| 0bfa7c9136 | |||
| 6d38c0bf70 | |||
| a932966795 | |||
| a63c7ec750 | |||
| ad53669098 | |||
| 69b42f2afe | |||
| c4f4465e87 | |||
| f292f954f7 | |||
| 161c9e320b | |||
| f33386ee5c | |||
|
|
61c10944c9 | ||
|
|
6db6fe6060 | ||
|
|
14506b18b2 | ||
| 44d1041087 | |||
| dd941bcf8e | |||
| 75fc22d2a2 | |||
| ee549b91f1 | |||
| 38209d0efb | |||
| b7dcca35b5 | |||
| bb39fe386b | |||
|
|
3d02922751 | ||
| e5ea3c3477 | |||
| 0b00cd2f4d | |||
| 7f6b8c1f5e | |||
|
|
3bfc183c89 | ||
| 45e1970186 | |||
| c8e8560584 | |||
| 5bdf9c69ea | |||
|
|
e48438b5a6 | ||
| 00cb5d2442 | |||
| 9a84dfffd0 | |||
| 45a2b0b8c8 | |||
| a947963fc1 | |||
| 6982a97d22 | |||
| 1ba01588f0 | |||
| 4a7f9f7500 | |||
| 47690ee666 | |||
| 3477d50689 | |||
| abf1e0df71 | |||
| 1ac033e850 | |||
| c2d9b0324a | |||
| 5727b54c3f | |||
| d796d296c0 | |||
| 31ecde133e | |||
| d6d40d2b78 | |||
| ed220702b3 | |||
|
|
bdef388b2e | ||
| a31a36dbd8 | |||
| f23809b28e | |||
| 7d4944279f | |||
| 3dfca9a17d | |||
| 9b189f276e | |||
| 51518e4e88 | |||
|
|
961d174bf7 | ||
| 10b758d8f3 | |||
| 78c5d31a29 | |||
| adf8b478a8 | |||
|
|
1c748219f8 | ||
|
|
9def55a2c2 | ||
|
|
cd1892fd66 | ||
|
|
83e2302cf8 | ||
|
|
4deaf28659 | ||
|
|
04d6174875 | ||
|
|
0d64bff7fa |
@@ -1,2 +1,4 @@
|
||||
FROM python:3
|
||||
RUN pip3 install requests
|
||||
FROM shenmo7192/uos-21-dtk5.4:1.0
|
||||
ADD . /root/workdir
|
||||
WORKDIR /root/workdir
|
||||
RUN dpkg-buildpackage
|
||||
|
||||
58
.gitignore
vendored
58
.gitignore
vendored
@@ -1,4 +1,54 @@
|
||||
*.pro.user*
|
||||
build/
|
||||
.vscode/
|
||||
Lib/
|
||||
# C++ objects and libs
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.a
|
||||
*.la
|
||||
*.lai
|
||||
*.so
|
||||
*.dll
|
||||
*.dylib
|
||||
|
||||
# Qt-es
|
||||
object_script.*.Release
|
||||
object_script.*.Debug
|
||||
*_plugin_import.cpp
|
||||
/.qmake.cache
|
||||
/.qmake.stash
|
||||
*.pro.user
|
||||
*.pro.user.*
|
||||
*.qbs.user
|
||||
*.qbs.user.*
|
||||
*.moc
|
||||
moc_*.cpp
|
||||
moc_*.h
|
||||
qrc_*.cpp
|
||||
ui_*.h
|
||||
*.qmlc
|
||||
*.jsc
|
||||
Makefile*
|
||||
*build-*
|
||||
|
||||
# Qt unit tests
|
||||
target_wrapper.*
|
||||
|
||||
# Qt qm files
|
||||
translations/*.qm
|
||||
|
||||
# QtCreator
|
||||
*.autosave
|
||||
|
||||
# QtCreator Qml
|
||||
*.qmlproject.user
|
||||
*.qmlproject.user.*
|
||||
|
||||
# QtCreator CMake
|
||||
CMakeLists.txt.user*
|
||||
build
|
||||
|
||||
# Debian dpkg-buildpackage
|
||||
debian/*.debhelper*
|
||||
debian/files
|
||||
debian/*.substvars
|
||||
debian/spark-store
|
||||
|
||||
|
||||
39
.workflow/dtk-build-commit-20220425.yml
Normal file
39
.workflow/dtk-build-commit-20220425.yml
Normal file
@@ -0,0 +1,39 @@
|
||||
version: '1.0'
|
||||
name: dtk-build-commit-20220425
|
||||
displayName: dtk-build-commit
|
||||
triggers:
|
||||
trigger: auto
|
||||
pr:
|
||||
branches:
|
||||
prefix:
|
||||
- ''
|
||||
stages:
|
||||
- name: stage-4e566164
|
||||
displayName: build
|
||||
strategy: naturally
|
||||
trigger: auto
|
||||
executor: []
|
||||
steps:
|
||||
- step: execute@docker
|
||||
name: execute_by_docker
|
||||
displayName: 基于镜像的脚本执行
|
||||
certificate: ''
|
||||
image: docker.io/debian:buster
|
||||
command:
|
||||
- sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
|
||||
- '# 换源'
|
||||
- apt update
|
||||
- export DEBIAN_FRONTEND=noninteractive
|
||||
- echo "安装git devscripts equivs ..."
|
||||
- apt install git devscripts equivs curl -y >/dev/null 2>&1
|
||||
- git clone https://gitlink.org.cn/shenmo7192/dtk-old-bundle.git
|
||||
- cd dtk-old-bundle
|
||||
- apt install ./*.deb -y
|
||||
- cd ..
|
||||
- rm -rf dtk-old-bundle
|
||||
- 'mk-build-deps --install --tool "apt-get -o Debug::pkgProblemResolver=yes -y" '
|
||||
- dpkg-buildpackage -j2 -b -us -uc
|
||||
- cd ..
|
||||
- ls -all
|
||||
- pwd
|
||||
strategy: {}
|
||||
66
.workflow/dtk-build-release-tag-20220425.yml
Normal file
66
.workflow/dtk-build-release-tag-20220425.yml
Normal file
@@ -0,0 +1,66 @@
|
||||
version: '1.0'
|
||||
name: dtk-build-release-tag-20220425
|
||||
displayName: dtk-build-release-tag
|
||||
triggers:
|
||||
trigger: auto
|
||||
push:
|
||||
tags:
|
||||
prefix:
|
||||
- ''
|
||||
stages:
|
||||
- name: stage-4e566164
|
||||
displayName: build
|
||||
strategy: naturally
|
||||
trigger: auto
|
||||
executor: []
|
||||
steps:
|
||||
- step: execute@docker
|
||||
name: execute_by_docker
|
||||
displayName: 基于镜像的DTK构建
|
||||
certificate: ''
|
||||
image: docker.io/debian:buster
|
||||
command:
|
||||
- sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
|
||||
- '# 换源'
|
||||
- apt update
|
||||
- export DEBIAN_FRONTEND=noninteractive
|
||||
- echo "安装git devscripts equivs curl..."
|
||||
- 'apt install git devscripts equivs curl -y '
|
||||
- git clone https://gitlink.org.cn/shenmo7192/dtk-old-bundle.git
|
||||
- cd dtk-old-bundle
|
||||
- apt install ./*.deb -y
|
||||
- cd ..
|
||||
- rm -rf dtk-old-bundle
|
||||
- ''
|
||||
- 'mk-build-deps --install --tool "apt-get -o Debug::pkgProblemResolver=yes -y" '
|
||||
- dpkg-buildpackage -j2 -b -us -uc
|
||||
- cd ..
|
||||
- ls -all
|
||||
- pwd
|
||||
- ''
|
||||
- 'mkdir target '
|
||||
- for f in $(find . -type f -name "*.deb")
|
||||
- do
|
||||
- ' mv $f target'
|
||||
- done
|
||||
artifacts:
|
||||
- name: BUILD_ARTIFACT
|
||||
path:
|
||||
- ../target
|
||||
notify: []
|
||||
strategy:
|
||||
retry: '0'
|
||||
- name: stage-29f3ffbb
|
||||
displayName: 上传
|
||||
strategy: naturally
|
||||
trigger: auto
|
||||
executor: []
|
||||
steps:
|
||||
- step: publish@general_artifacts
|
||||
name: publish_general_artifacts
|
||||
displayName: 上传制品
|
||||
dependArtifact: BUILD_ARTIFACT
|
||||
artifactName: output
|
||||
notify: []
|
||||
strategy:
|
||||
retry: '0'
|
||||
143
CMakeLists.txt
143
CMakeLists.txt
@@ -1,143 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(spark_store)
|
||||
set(EXECUTABLE_NAME spark-store)
|
||||
|
||||
# Begin Compilation Options
|
||||
|
||||
# When set to ON, DTK Plugin for DDE platform will be built.
|
||||
# Note that only machines with DTK and dev packages installed can build the plugin.
|
||||
set(SPARK_BUILD_DTK_PLUGIN ON)
|
||||
|
||||
# When set to ON, store will transmit telemetry even in Debug builds.
|
||||
set(SPARK_FORCE_TELEMETRY OFF)
|
||||
|
||||
# End Compilation Options
|
||||
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
#set(CMAKE_AUTOUIC ON)
|
||||
|
||||
set(QT_VERSION 5)
|
||||
set(REQUIRED_LIBS
|
||||
Core
|
||||
Gui
|
||||
Widgets
|
||||
Network
|
||||
Concurrent
|
||||
LinguistTools)
|
||||
set(REQUIRED_LIBS_QUALIFIED
|
||||
Qt5::Core
|
||||
Qt5::Gui
|
||||
Qt5::Widgets
|
||||
Qt5::Network
|
||||
Qt5::Concurrent)
|
||||
|
||||
include_directories(inc)
|
||||
include_directories(plugin)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
set(PRE_CONFIGURE_FILE "src/gitver.cpp.in")
|
||||
set(POST_CONFIGURE_FILE "${CMAKE_CURRENT_BINARY_DIR}/src/gitver.cpp")
|
||||
include(cmake/git_watcher.cmake)
|
||||
add_library(gitver STATIC ${POST_CONFIGURE_FILE})
|
||||
#target_include_directories(gitver PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
add_dependencies(gitver check_git)
|
||||
|
||||
set(SOURCE_FILES
|
||||
src/main.cpp
|
||||
|
||||
resource/resource.qrc
|
||||
|
||||
gui/page/ui/settings.ui
|
||||
gui/page/ui/homepage.ui
|
||||
${WRAPPED_UI_FILES}
|
||||
|
||||
inc/gitver.h
|
||||
inc/deepinplatform.h
|
||||
inc/dtk/spkdtkplugin.h
|
||||
inc/spkutils.h src/spkutils.cpp
|
||||
inc/telemetry/collectid.h
|
||||
inc/spkqsshelper.h gui/spkqsshelper.cpp
|
||||
|
||||
inc/qt/elidedlabel.h gui/qt/elidedlabel.cpp
|
||||
|
||||
inc/spkwindow.h gui/spkwindow.cpp
|
||||
inc/spktitlebar.h gui/spktitlebar.cpp
|
||||
inc/spkiconbutton.h gui/spkiconbutton.cpp
|
||||
inc/spkui_general.h gui/spkui_general.cpp
|
||||
inc/spkmainwindow.h gui/spkmainwindow.cpp
|
||||
inc/spkmsgbox.h gui/spkmsgbox.cpp
|
||||
inc/spkdialog.h gui/spkdialog.cpp
|
||||
inc/spkabout.h gui/spkabout.cpp
|
||||
inc/spkloading.h gui/spkloading.cpp
|
||||
inc/spksidebartree.h gui/spksidebartree.cpp
|
||||
inc/spkappitem.h gui/spkappitem.cpp
|
||||
inc/spkdownloadentry.h gui/spkdownloadentry.cpp
|
||||
inc/spkpopup.h gui/spkpopup.cpp
|
||||
inc/spkstretchlayout.h gui/spkstretchlayout.cpp
|
||||
inc/spkfocuslineedit.h
|
||||
inc/spknotifydot.h gui/spknotifydot.cpp
|
||||
inc/spkimgviewer.h gui/spkimgviewer.cpp
|
||||
|
||||
inc/page/spkpagebase.h gui/page/spkpagebase.cpp
|
||||
inc/page/spkpagehome.h gui/page/spkpagehome.cpp
|
||||
inc/page/spkpageuitest.h gui/page/spkpageuitest.cpp
|
||||
inc/page/spkpageapplist.h gui/page/spkpageapplist.cpp
|
||||
inc/page/spkpageappdetails.h gui/page/spkpageappdetails.cpp
|
||||
inc/page/spkpagedownloads.h gui/page/spkpagedownloads.cpp
|
||||
inc/page/spkpagesettings.h gui/page/spkpagesettings.cpp
|
||||
|
||||
inc/pkgs/spkpkgmgrbase.h
|
||||
inc/pkgs/spkpkgmgrpacman.h src/pkgs/spkpkgmgrpacman.cpp
|
||||
inc/pkgs/spkpkgmgrapt.h src/pkgs/spkpkgmgrapt.cpp
|
||||
|
||||
inc/spkstore.h src/spkstore.cpp
|
||||
inc/spkuimsg.h src/spkuimsg.cpp
|
||||
inc/spklogging.h src/spklogging.cpp
|
||||
inc/spkresource.h src/spkresource.cpp
|
||||
inc/spkdownload.h src/spkdownload.cpp
|
||||
inc/spkconfig.h src/spkconfig.cpp
|
||||
)
|
||||
|
||||
include(cmake/FindLibNotify.cmake)
|
||||
include(cmake/FindGlib.cmake)
|
||||
include(cmake/FindGdk3.cmake)
|
||||
|
||||
include_directories(${GLIB_INCLUDE_DIRS})
|
||||
include_directories(${GDK3_INCLUDE_DIRS})
|
||||
set(LIBLINKING ${LIBLINKING}
|
||||
gitver
|
||||
${LIBNOTIFY_LIBRARIES}
|
||||
${GLIB_LIBRARIES}
|
||||
${GDK3_LIBRARIES}
|
||||
${CMAKE_DL_LIBS})
|
||||
|
||||
# Required for a good backtrace
|
||||
add_compile_options(-g)
|
||||
add_link_options(-rdynamic)
|
||||
|
||||
# Find Qt before adding other build targets
|
||||
find_package(Qt${QT_VERSION} COMPONENTS ${REQUIRED_LIBS} REQUIRED)
|
||||
|
||||
QT5_WRAP_UI(WRAPPED_UI_FILES
|
||||
gui/page/ui/settings.ui
|
||||
gui/page/ui/homepage.ui)
|
||||
|
||||
add_custom_target(run_lupdate
|
||||
COMMAND lupdate . -ts lang/zh.ts
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
|
||||
qt5_add_translation(QM_FILES lang/zh.ts)
|
||||
|
||||
add_executable(${EXECUTABLE_NAME} ${SOURCE_FILES} ${QM_FILES})
|
||||
|
||||
if(SPARK_BUILD_DTK_PLUGIN)
|
||||
add_subdirectory(plugin/dtkplugin)
|
||||
add_dependencies(${EXECUTABLE_NAME} spkdtkplugin)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${EXECUTABLE_NAME} ${REQUIRED_LIBS_QUALIFIED} ${LIBLINKING})
|
||||
|
||||
install(TARGETS ${EXECUTABLE_NAME} RUNTIME DESTINATION bin)
|
||||
328
DOCS/code-analyze.md
Normal file
328
DOCS/code-analyze.md
Normal file
@@ -0,0 +1,328 @@
|
||||
|
||||
#### 说明
|
||||
|
||||
当前服务器线路列表(项目中包含):
|
||||
|
||||
```
|
||||
https://d.store.deepinos.org.cn/
|
||||
https://store.deepinos.org.cn/
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# 星火应用商店文档
|
||||
|
||||
# 目录结构
|
||||
几个目录结构
|
||||
```
|
||||
/
|
||||
/icons 图标文件夹
|
||||
/tags 首页图标
|
||||
/tras 多语言翻译
|
||||
```
|
||||
|
||||
主要的文件分析
|
||||
```js
|
||||
spark-store.pro Qt工程配置文件
|
||||
ssinstall 调用包安装器的脚本
|
||||
icons.qrc 图标资源文件
|
||||
main.cpp 入口文件
|
||||
widget.h widget.cpp widget.ui 主要窗口控件
|
||||
downloadlist.h downloadlist.cpp downloadlist.ui 单个软件的下载安装展示控件
|
||||
progressload.h progressload.cpp 网页加载显示? 得在deepin上编译运行才能搞清楚
|
||||
workerthreads.h workerthreads.cpp 应用信息加载线程
|
||||
image_show.h image_show.cpp 应用页面截图预览控件
|
||||
big_image.h big_image.cpp 大图查看控件
|
||||
```
|
||||
|
||||
# 使用的开源库及第三方工具
|
||||
* GDebi 一个 Ubuntu 软件中心的轻量级替代品 https://linux.cn/article-4982-1.html
|
||||
* libnotify 系统通知 https://developer.gnome.org/libnotify/unstable/
|
||||
|
||||
|
||||
# 源码分析
|
||||
## 应用的组成部分
|
||||
左侧应用分类菜单
|
||||
主窗口的下拉菜单
|
||||
应用列表页面
|
||||
应用详情页面
|
||||
应用首页,有几个链接跳转
|
||||
商店设置页面
|
||||
下载列表页面
|
||||
|
||||
## 应用初始化,及主控件加载
|
||||
初始化 `DApplication` 进入事件循环。
|
||||
设置关于我们弹窗 `DAboutDialog`。
|
||||
主控件 Widget 根据不同屏幕大小自适应。
|
||||
首页打开webview页面,如果传入了`spk://`参数,会打开应用详情页。
|
||||
```cpp
|
||||
// main.cpp
|
||||
QString arg1=argv[1];
|
||||
if(arg1.left(6)=="spk://"){
|
||||
w.openUrl(QUrl(argv[1]));
|
||||
}
|
||||
|
||||
// widget.cpp
|
||||
void Widget::openUrl(QUrl u)
|
||||
{
|
||||
QString app=serverUrl + "store"+u.path()+"/app.json";
|
||||
ui->webEngineView->setUrl(app); // 会触发 webEngineView 的
|
||||
}
|
||||
|
||||
```
|
||||
## Tags处理方式
|
||||
|
||||
**Tags处理方式**
|
||||
```cpp
|
||||
// widget.cpp
|
||||
QString tags=json["Tags"].toString(); //Read the Tags
|
||||
QStringList tagList=tags.split(";");
|
||||
for (int i=0;i<tagList.size();i++) {
|
||||
if(tagList[i]=="community")
|
||||
ui->tag_community->show();//Tags icon shows like this
|
||||
if(tagList[i]=="ubuntu")
|
||||
ui->tag_ubuntu->show();
|
||||
if(tagList[i]=="deepin")
|
||||
ui->tag_deepin->show();
|
||||
if(tagList[i]=="uos")
|
||||
ui->tag_uos->show();
|
||||
if(tagList[i]=="dtk5")
|
||||
ui->tag_dtk5->show();
|
||||
if(tagList[i]=="dwine2")
|
||||
ui->tag_dwine2->show();
|
||||
if(tagList[i]=="dwine5")
|
||||
ui->tag_dwine5->show();
|
||||
if(tagList[i]=="a2d")
|
||||
ui->tag_a2d->show();
|
||||
}
|
||||
```
|
||||
|
||||
**Widget 初始化**
|
||||
```cpp
|
||||
void Widget::initConfig()
|
||||
{
|
||||
...
|
||||
// 读取服务器URL并初始化菜单项的链接
|
||||
QSettings readConfig(QDir::homePath()+"/.config/spark-store/config.ini",QSettings::IniFormat);
|
||||
if(readConfig.value("server/choose").toString()!=""){
|
||||
ui->comboBox_server->setCurrentText(readConfig.value("server/choose").toString());
|
||||
appinfoLoadThread.setServer(serverUrl=readConfig.value("server/choose").toString());
|
||||
}else {
|
||||
appinfoLoadThread.setServer(serverUrl="http://sucdn.jerrywang.top/"); // 默认URL
|
||||
}
|
||||
configCanSave=true; // 防止触发保存配置信号
|
||||
menuUrl[0]=serverUrl + "store/#/"; // 首页
|
||||
// 下面是各个应用分类页面,直接加载的webview的
|
||||
// 每个连接对应一个左侧的菜单项,在构造函数用连接到 chooseLeftMenu 槽函数
|
||||
menuUrl[1]=serverUrl + "store/#/network";
|
||||
...
|
||||
menuUrl[12]=serverUrl + "store/#/others";
|
||||
...
|
||||
ui->webfoot->hide();
|
||||
|
||||
//初始化首页
|
||||
ui->webEngineView->setUrl(menuUrl[0]);
|
||||
}
|
||||
/**
|
||||
* 菜单切换逻辑
|
||||
*
|
||||
*/
|
||||
void Widget::chooseLeftMenu(int index)
|
||||
{
|
||||
nowMenu=index;
|
||||
updateUI();
|
||||
left_list[index]->setStyleSheet("color:#FFFFFF;background-color:"+main_color.name()+";border-radius:8;border:0px");
|
||||
// index <=12 加载某个分类的应用列表的webviejw
|
||||
// index == 13 加载下载列表页面
|
||||
if(index<=12){
|
||||
if(themeIsDark){
|
||||
darkurl = 夜间模式的URL
|
||||
ui->webEngineView->setUrl(darkurl);
|
||||
}else {
|
||||
ui->webEngineView->setUrl(menuUrl[index]);
|
||||
}
|
||||
ui->stackedWidget->setCurrentIndex(0);
|
||||
}else if (index==13) {
|
||||
ui->stackedWidget->setCurrentIndex(1);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 应用下载安装卸载分析
|
||||
**应用详情页面加载**
|
||||
```cpp
|
||||
/**
|
||||
* 加载单个应用的信息
|
||||
*/
|
||||
void Widget::on_webEngineView_urlChanged(const QUrl &arg1)
|
||||
{
|
||||
//分析出服务器中的分类名称
|
||||
...
|
||||
//如果是app.json就打开详情页
|
||||
if(arg1.path().right(8)=="app.json"){
|
||||
...
|
||||
// 读取相应的应用信息
|
||||
appinfoLoadThread.requestInterruption();
|
||||
appinfoLoadThread.wait(100);
|
||||
appinfoLoadThread.setUrl(arg1);
|
||||
appinfoLoadThread.start();
|
||||
}
|
||||
}
|
||||
// 设置详情页的APP信息
|
||||
SpkAppInfoLoaderThread::requestSetAppInformation() -> Widget::sltAppinfoDetails()
|
||||
// 设置详情页的APP图标
|
||||
SpkAppInfoLoaderThread::finishedIconLoad() -> Widget::sltAppinfoIcon()
|
||||
// 设置详情页的APP截图
|
||||
SpkAppInfoLoaderThread::finishedScreenshotLoad() -> Widget::sltAppinfoScreenshot()
|
||||
|
||||
// 下载APP详情信息线程
|
||||
void SpkAppInfoLoaderThread::run()
|
||||
{
|
||||
QProcess get_json;
|
||||
get_json.start("curl -o app.json " + targetUrl.toString());
|
||||
QFile app_json("app.json");
|
||||
读取 app.json 里的信息,提取应用名、描述、图标、截图
|
||||
处理完毕后发射相应的信号
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
**应用下载**
|
||||
Widget::on_pushButton_download_clicked() 是点击下载的安装方法。
|
||||
最终使用的是 `QNetwrokAccessManager` 进行GET请求获取数据写入文件。
|
||||
```cpp
|
||||
void Widget::on_pushButton_download_clicked()
|
||||
{
|
||||
if(!isBusy){
|
||||
file = new QFile(fileName);
|
||||
...
|
||||
nowDownload+=1;
|
||||
startRequest(urList.at(nowDownload-1)); // 进行链接请求
|
||||
}
|
||||
}
|
||||
void Widget::startRequest(QUrl url)
|
||||
{
|
||||
reply = manager->get(QNetworkRequest(url));
|
||||
// 请求响应完成,关闭文件,清理下载队列
|
||||
connect(reply,SIGNAL(finished()),this,SLOT(httpFinished()));
|
||||
// 接收应用下载数据
|
||||
connect(reply,SIGNAL(readyRead()),this,SLOT(httpReadyRead()));
|
||||
// 更新应用下载进度
|
||||
connect(reply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(updateDataReadProgress(qint64,qint64)));
|
||||
}
|
||||
```
|
||||
|
||||
使用 QSettings 来读取配置,更换服务源
|
||||
```cpp
|
||||
void Widget::on_comboBox_server_currentIndexChanged(const QString &arg1)
|
||||
{
|
||||
appinfoLoadThread.setServer(arg1); // 服务器信息更新
|
||||
if(configCanSave){
|
||||
ui->label_setting1->show();
|
||||
QSettings *setConfig=new QSettings(QDir::homePath()+"/.config/spark-store/config.ini",QSettings::IniFormat);
|
||||
setConfig->setValue("server/choose",arg1);
|
||||
}
|
||||
}
|
||||
```
|
||||
使用 `QProcess` 来调用各种小文件下载、包安装卸载的命令。
|
||||
|
||||
**应用安装**
|
||||
```cpp
|
||||
void Widget::httpFinished() // 完成下载
|
||||
{
|
||||
...清理资源
|
||||
download_list[nowDownload-1].readyInstall();
|
||||
download_list[nowDownload-1].free=true;
|
||||
if(nowDownload<allDownload){ // 如果有排队则下载下一个
|
||||
...队列的下一个下载请求
|
||||
}
|
||||
}
|
||||
void downloadlist::readyInstall()
|
||||
{
|
||||
...将安装按钮设置为允许点击
|
||||
ui->pushButton_install->setEnabled(true);
|
||||
ui->pushButton_install->show();
|
||||
ui->pushButton_2->hide();
|
||||
Widget::sendNotification(tr("Finished downloading %1, awaiting to install").arg(ui->label->text()), 5000,
|
||||
"/tmp/spark-store/icon_"+QString::number(num).toUtf8()+".png");
|
||||
}
|
||||
void downloadlist::on_pushButton_install_clicked()
|
||||
{
|
||||
//弹出菜单
|
||||
menu_install->exec(cursor().pos());
|
||||
}
|
||||
在 downloadlist 构造函数里将三种安装方式的按钮按条件放入了 menu_install 菜单里
|
||||
用户点击时,downloadlist::install() 方法
|
||||
三种安装方式为: gdebi, dpkg, deepin-deb-installer
|
||||
void downloadlist::install(int t)
|
||||
{
|
||||
QtConcurrent::run([=](){
|
||||
QProcess installer;
|
||||
installer.start("pkexec gdebi -n /tmp/spark-store/"+ui->label_filename->text().toUtf8());
|
||||
installer.start("pkexec ssinstall /tmp/spark-store/"+ui->label_filename->text().toUtf8());
|
||||
installer.start("deepin-deb-installer /tmp/spark-store/"+ui->label_filename->text().toUtf8());
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
**应用卸载**
|
||||
```cpp
|
||||
void Widget::on_pushButton_uninstall_clicked()
|
||||
{
|
||||
QtConcurrent::run([=](){
|
||||
uninstall.start("pkexec apt purge -y "+pkgName);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
**仓库源更新**
|
||||
```cpp
|
||||
// 更新源列表
|
||||
void Widget::on_pushButton_updateServer_clicked()
|
||||
{
|
||||
QtConcurrent::run([=](){
|
||||
...
|
||||
QFile::remove(QDir::homePath().toUtf8()+"/.config/spark-store/server.list");
|
||||
system("curl -o "+QDir::homePath().toUtf8()+"/.config/spark-store/server.list http://dcstore.shenmo.tech/store/server.list");
|
||||
server.open(QDir::homePath().toUtf8()+"/.config/spark-store/server.list",std::ios::in);
|
||||
...
|
||||
while (getline(server,lineTmp)) {
|
||||
ui->comboBox_server->addItem(QString::fromStdString(lineTmp));
|
||||
}
|
||||
});
|
||||
}
|
||||
// 更新星火商店apt源
|
||||
void Widget::on_pushButton_updateApt_clicked()
|
||||
{
|
||||
QtConcurrent::run([=](){
|
||||
读取 comboBox_server 的内容,写入 /tmp/spark-store/sparkstore.list 文件
|
||||
创建bash脚本,内容为将 sparkstore.list 移动到 /etc/apt/sources.list.d/ 目录下
|
||||
使用QProcess 执行命令 pkexec update.sh
|
||||
}):
|
||||
}
|
||||
```
|
||||
|
||||
## 发送系统通知
|
||||
```cpp
|
||||
#include <libnotify/notify.h>
|
||||
|
||||
static NotifyNotification *_notify = nullptr; // 初始化
|
||||
notify_init(tr("Spark\\ Store").toLocal8Bit()); // 构造函数初始化
|
||||
notify_uninit(); // 析构函数调用
|
||||
|
||||
void Widget::sendNotification(const QString &message, const int msTimeout, const QString &icon)
|
||||
{
|
||||
if(_notify == nullptr)
|
||||
{
|
||||
_notify = notify_notification_new(tr("Spark\\ Store").toLocal8Bit(), message.toLocal8Bit(), icon.toLocal8Bit());
|
||||
notify_notification_set_timeout(_notify, msTimeout);
|
||||
}
|
||||
else
|
||||
notify_notification_update(_notify, tr("Spark\\ Store").toLocal8Bit(), message.toLocal8Bit(), icon.toLocal8Bit());
|
||||
|
||||
notify_notification_show(_notify, nullptr);
|
||||
}
|
||||
```
|
||||
27
DOCS/spk-doc.md
Normal file
27
DOCS/spk-doc.md
Normal file
@@ -0,0 +1,27 @@
|
||||
#### 调用参数(spk规则)
|
||||
|
||||
参数只有一个Url,该url应当遵循这种格式:`spk://<任意合法字符>/web分类/包名`
|
||||
|
||||
目前第一字段不进行处理,以后可能会对此识别。在目前阶段,这个字段可以填写任意合法字符
|
||||
|
||||
例如:
|
||||
|
||||
[spk://abcdefg/games/store.spark-app.hmcl](spk://abcdefg/games/store.spark-app.hmcl)
|
||||
|
||||
|
||||
可选的web分类:
|
||||
|
||||
| 分类名称 | web分类 |
|
||||
| -------- | -------------- |
|
||||
| 网络 | network |
|
||||
| 社交 | chat |
|
||||
| 音乐 | music |
|
||||
| 视频 | video |
|
||||
| 图像 | image_graphics |
|
||||
| 游戏 | games |
|
||||
| 办公 | office |
|
||||
| 阅读 | reading |
|
||||
| 开发 | development |
|
||||
| 工具 | tools |
|
||||
| 主题 | themes |
|
||||
| 其他 | others |
|
||||
82
DOCS/write-preview-skeleton.md
Normal file
82
DOCS/write-preview-skeleton.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# 关于编写 "描述主体结构预览说明" 的规范
|
||||
|
||||
1. 主体结构预览
|
||||
|
||||
一般以 `tree` 命令进行获取目录结构进行展示所需要描述的预览内容。
|
||||
|
||||
2. 对主体结构中的内容单独说明
|
||||
|
||||
并使用所用语言进行非侵入式独立描述,而不是在代码中填充说明与注释。
|
||||
|
||||
在单行描述中,尽量不超过您认为最大的字符数量宽度,可以收缩内容的重要性。
|
||||
|
||||
在此种说明文档中,尽量使用您所描述的对象支持的代码注释,而不是以白底黑字进行描述。
|
||||
|
||||
对于规范的全部:主体结构 + 单独内容中进行简单(而不是简少)的说明。
|
||||
|
||||
一个简单的例子,例如: 有关项目源代码结构的预览说明
|
||||
|
||||
- 项目结构预览
|
||||
|
||||
```
|
||||
.
|
||||
├── assets
|
||||
├── debian
|
||||
├── DOCS
|
||||
├── patchs
|
||||
├── src
|
||||
├── tool
|
||||
└── translations
|
||||
|
||||
10 directories, 9 files
|
||||
```
|
||||
|
||||
- 来自 debian 目录的说明
|
||||
|
||||
```shell
|
||||
# 将此项目进行 debian 的标志,基于 debian 系列的发行版可对包含
|
||||
# 此种目录的开源项目进行构建 deb 软件包。
|
||||
|
||||
# 1. 构建软件包(打包)
|
||||
# 执行 dpkg-buildpackage 命令以尝试构建此软件包
|
||||
dpkg-buildpackage
|
||||
# 如果构建将会在上级目录中产生一个 deb,而源代码目录不会有任何变化。
|
||||
|
||||
# 如果出现以下内容可忽视,仅需要查看是否已成功构建软件包:
|
||||
# gpg: 已跳过 "": 无效的用户ID
|
||||
# gpg: ...: clear-sign failed: 无效的用户ID
|
||||
# dpkg-buildpackage: error: failed to sign .dsc file
|
||||
```
|
||||
|
||||
- 来自 patchs 目录的说明
|
||||
|
||||
```shell
|
||||
# 一种用于可扩展的补丁,主要目的是为项目提供可选的应用方案,而不是直接堆砌到
|
||||
# 当前项目的分支中。您可以认为所有分支都是主线分支。
|
||||
# 例如:
|
||||
# 主线稳定分支: master
|
||||
# 主线开发分支: dev
|
||||
# 主线其它: ...
|
||||
|
||||
# 注意:
|
||||
# 当您认为您所提交的内容并不会为主线带来 bug fix 之类的内容,请使用补丁。
|
||||
# 当您所提交的内容会带来不可预知的问题的时候,或会改变目前主线的开发模式时,
|
||||
# 此种方式可确保您提交的方案可被任意时间被弃用,而不是由其它维护者耗费精力
|
||||
# 去试图移除您提交的内容,而不是等待由提交者进行新的维护。
|
||||
```
|
||||
|
||||
- 来自其它的内容...可随时由任何人进行补充
|
||||
|
||||
|
||||
- 一些在关此种预览描述的文档
|
||||
|
||||
```shell
|
||||
# 此种描述还将出现在 `src/README.md` 的描述中。
|
||||
# 当然,我预期会由其它维护者进行移动到 `DOCS` 之下。
|
||||
|
||||
# 另外在 `patchs/zinface-community-cmake-build-system.patch` 补丁文件中,
|
||||
# 也随附过一个简要的文档内容,而它是记录了 `Spark` 为名的构建模式。
|
||||
|
||||
# 在未应用此补丁时,将不会出现在任何地方。
|
||||
```
|
||||
|
||||
7
DOCS/内网部署.md
Normal file
7
DOCS/内网部署.md
Normal file
@@ -0,0 +1,7 @@
|
||||
需要修改的内容:商店默认源位置,aptss获取apt-fast.conf和sparkstore.list的地址,ssinstall做安装检查的源位置
|
||||
|
||||
服务器使用update.sh进行同步。
|
||||
|
||||
为方便使用(其实是早期屎山使然),请将仓库放置于 `/home/ftp/spark-store`
|
||||
|
||||
仓库管理相关代码请移步 [这里](https://gitee.com/deepin-community-store/repo_auto_update_script),update.sh请联系 @shenmo 获取
|
||||
4
Jenkinsfile
vendored
4
Jenkinsfile
vendored
@@ -4,12 +4,12 @@ pipeline {
|
||||
stage('build') {
|
||||
agent {
|
||||
docker {
|
||||
image 'jerry979/dtke:5.11'
|
||||
image 'jerry979/dtke:5.11.1'
|
||||
}
|
||||
|
||||
}
|
||||
steps {
|
||||
sh 'mkdir build && cd build && cmake .. && make -j'
|
||||
sh 'mkdir build && cd build && qmake .. && make '
|
||||
archiveArtifacts(artifacts: 'build/src/spark-store', allowEmptyArchive: true, defaultExcludes: true)
|
||||
}
|
||||
}
|
||||
|
||||
BIN
Logo-Spark.png
BIN
Logo-Spark.png
Binary file not shown.
|
Before Width: | Height: | Size: 46 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 43 KiB |
122
README.md
122
README.md
@@ -1,73 +1,87 @@
|
||||
# 星火应用商店
|
||||
# Spark App Store
|
||||
[](https://gitee.com/deepin-community-store/spark-store/stargazers) [](https://gitee.com/deepin-community-store/spark-store/members)
|
||||
|
||||
## Branch: Reason
|
||||
|
||||
This branch is for aarch64-store support
|
||||
|
||||
---
|
||||
## You are informed that the aarch64 support is EXPERIMENTAL and there is NO GUARANTEE that this branch will be supported in the future
|
||||
|
||||
Spark Store aims to collect Linux apps for the convieniece of Linux new comers
|
||||
|
||||
The collecting process needs everyone's help
|
||||
|
||||
We set up this APP Store and collect APPs/tools that everyone need widely. Also we pack Windows apps with wine.
|
||||
|
||||
All packages will be shared in our repository for users to get freely.
|
||||
|
||||
Distrobution supported:Deepin 20 ; Ubuntu 22.04 LTS / Ubuntu 20.04 LTS(May stop support in the future) ; UniontechOS Home 21
|
||||
|
||||
*About OpenKylin and deepin 23*
|
||||
|
||||
The adaptation work is scheduled after their official release.
|
||||
|
||||
You can track our Issue resoving progress here https://gitee.com/deepin-community-store/spark-store/board
|
||||
|
||||
|
||||
众所周知,国内的Linux应用比较少,wine应用难以获取,优质工具分散在民间各大论坛,无法形成合力,难以改善生态
|
||||
We hope people who see here can also join our team,development help or submit applications are welcomed
|
||||
|
||||
生态构建需要的不是某一方的单打独斗,而是人人行动起来,汇聚星火,产生燎原之势
|
||||
|
||||
我们创建了这个应用商店,广泛收录大家需要的软件包,搜集优质小工具,主动适配wine应用,存放到储存库供大家获取
|
||||
|
||||
我们支持:Deepin 20 ; Ubuntu 20.04 LTS ; UOS Home 20
|
||||
|
||||
希望看到这里的人也可以加入我们的队伍,开发或者投递应用都很欢迎,共同构建Linux应用生态
|
||||
|
||||
### [在这里投稿](http://upload.spark-app.store)
|
||||
|
||||
web页面部分正在开发当中,详情请见[web仓库](https://gitee.com/deepin-community-store/DCSAPP_WEB)
|
||||
If you want to submit an APP to share with others,Please [Click here](https://upload.deepinos.org/index)
|
||||
|
||||
|
||||
#### 说明
|
||||
## 🙌 A simple start
|
||||
|
||||
当前服务器线路列表(项目中包含):
|
||||
If you simply want to install the Spark Store,just enter the [Release] page, find the version you want and install.
|
||||
|
||||
```
|
||||
https://d.store.deepinos.org.cn/
|
||||
https://store.deepinos.org.cn/
|
||||
```
|
||||
If you are using Debian11/Ubuntu 20.04, you will need extra dependency package. Available [here](https://code.gitlink.org.cn/shenmo7192/spark-store-dependencies/raw/branch/master/spark-store-dependencies-kylin.zip)
|
||||
|
||||
#### 调用参数(spk规则)
|
||||
|
||||
参数只有一个Url,该url应当遵循这种格式:`spk://<任意合法字符>/web分类/包名`
|
||||
|
||||
例如:
|
||||
|
||||
[spk://abcdefg/games/store.spark-app.hmcl](spk://abcdefg/games/store.spark-app.hmcl)
|
||||
---
|
||||
#### Compile and developement
|
||||
|
||||
|
||||
可选的web分类:
|
||||
|
||||
| 分类名称 | web分类 |
|
||||
| -------- | -------------- |
|
||||
| 网络应用 | network |
|
||||
| 社交沟通 | chat |
|
||||
| 音乐欣赏 | music |
|
||||
| 视频播放 | video |
|
||||
| 图形图像 | graphics |
|
||||
| 游戏娱乐 | games |
|
||||
| 办公学习 | office |
|
||||
| 阅读翻译 | reading |
|
||||
| 编程开发 | development |
|
||||
| 系统工具 | tools |
|
||||
| 主题美化 | beautify |
|
||||
| 其他应用 | others |
|
||||
|
||||
|
||||
|
||||
#### 如何编译
|
||||
|
||||
Deepin V20/UOS 系统下, 安装依赖
|
||||
For Deepin V20/UOS 21/ Debian 11
|
||||
|
||||
```shell
|
||||
sudo apt install qt5-default libdtkcore-dev libdtkwidget-dev qtwebengine5-dev libnotify-dev
|
||||
sudo apt install git qt5-default debhelper pkg-config qtchooser libqt5core5a libqt5gui5 libqt5widgets5 libqt5network5 libqt5concurrent5 libdtkcore-dev libdtkgui-dev libdtkwidget-dev qttools5-private-dev libnotify-dev qtwebengine5-dev fakeroot qtwayland5 qtwayland5-dev-tools dde-qt5wayland-plugin
|
||||
|
||||
```
|
||||
|
||||
Ubuntu 22.04
|
||||
```shell
|
||||
sudo apt install git qtbase5-dev debhelper pkg-config qtchooser libqt5core5a libqt5gui5 libqt5widgets5 libqt5network5 libqt5concurrent5 libdtkcore-dev libdtkgui-dev libdtkwidget-dev qttools5-private-dev libnotify-dev qtwebengine5-dev qtwayland5 qtwayland5-dev-tools
|
||||
|
||||
```
|
||||
|
||||
Then
|
||||
|
||||
```shell
|
||||
git clone https://gitee.com/deepin-community-store/spark-store.git
|
||||
cd spark-store
|
||||
mkdir build
|
||||
cd build
|
||||
qmake ..
|
||||
make -j
|
||||
dpkg-buildpackage -j
|
||||
```
|
||||
|
||||
./build文件下的spark-store即为可执行文件
|
||||
Or:
|
||||
```shell
|
||||
git clone https://gitee.com/deepin-community-store/spark-store.git
|
||||
cd spark-store
|
||||
./build_and_install.sh
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 🚀 Coorperation
|
||||
|
||||
We use Gitee as our code hosting platform. Please click here to contact us.
|
||||
|
||||
https://gitee.com/deepin-community-store/spark-store
|
||||
|
||||
### Rocket Chat
|
||||
|
||||
https://chat.shenmo.tech/
|
||||
|
||||
PWA Client:
|
||||
|
||||
spk://store/chat/store.spark-app.feedback
|
||||
|
||||
(Copy and paste to search bar or in browser address bar after installing Spark Store)
|
||||
|
||||
81
README.zh.md
Normal file
81
README.zh.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# 星火应用商店
|
||||
[](https://gitee.com/deepin-community-store/spark-store/stargazers) [](https://gitee.com/deepin-community-store/spark-store/members)
|
||||
|
||||
## 分支:原理
|
||||
|
||||
此分支用于aarch64-store支持
|
||||
|
||||
---
|
||||
## 请注意,aarch64的支持是实验性的,并未确认持续支持!
|
||||
|
||||
众所周知,国内的Linux应用比较少,wine应用难以获取,优质工具分散在民间各大论坛,无法形成合力,难以改善生态
|
||||
|
||||
生态构建需要的不是某一方的单打独斗,而是人人行动起来,汇聚星火,产生燎原之势
|
||||
|
||||
我们创建了这个应用商店,广泛收录大家需要的软件包,搜集优质小工具,主动适配wine应用,存放到储存库供大家获取
|
||||
我们支持:Deepin 20 ; Ubuntu 22.04 LTS / Ubuntu 20.04 LTS(将会逐渐停止支持) ; UOS Home 21
|
||||
|
||||
## 关于协作:分支相关的文档见 [这里](https://deepin-community-store.gitee.io/spark-wiki/#/Dev/Spark-Store-Git-Repo)
|
||||
|
||||
*关于OpenKylin和deepin 23*
|
||||
|
||||
支持计划将会在对应系统发布正式版之后开始评估和执行
|
||||
|
||||
希望看到这里的人也可以加入我们的队伍,开发或者投递应用都很欢迎,共同构建Linux应用生态
|
||||
|
||||
在这里追踪我们的Issue处理情况 https://gitee.com/deepin-community-store/spark-store/board
|
||||
|
||||
如果有想要提交的软件包,请 [在这里投稿](https://upload.deepinos.org/index)
|
||||
|
||||
|
||||
## 🙌 简单的开始
|
||||
|
||||
如果想安装 `星火应用商店` ,请打开右侧的 [Release] 页面,找到最新版本,并选择适用于当前系统的安装包下载。
|
||||
|
||||
如果你在使用 `Debian 11/Ubuntu 20.04`,你需要额外下载[依赖补充包](https://code.gitlink.org.cn/shenmo7192/spark-store-dependencies/raw/branch/master/spark-store-dependencies-kylin.zip)
|
||||
|
||||
---
|
||||
#### 编译安装
|
||||
|
||||
|
||||
Deepin V20/UOS 21 系统下, 安装依赖
|
||||
|
||||
```shell
|
||||
sudo apt install git qt5-default debhelper pkg-config qtchooser libqt5core5a libqt5gui5 libqt5widgets5 libqt5network5 libqt5concurrent5 libdtkcore-dev libdtkgui-dev libdtkwidget-dev qttools5-private-dev libnotify-dev qtwebengine5-dev fakeroot qtwayland5 qtwayland5-dev-tools dde-qt5wayland-plugin libqt5svg5*
|
||||
|
||||
```
|
||||
|
||||
Ubuntu 22.04 系统下, 安装依赖
|
||||
```shell
|
||||
sudo apt install git qtbase5-dev debhelper pkg-config qtchooser libqt5core5a libqt5gui5 libqt5widgets5 libqt5network5 libqt5concurrent5 libdtkcore-dev libdtkgui-dev libdtkwidget-dev qttools5-private-dev libnotify-dev qtwebengine5-dev qtwayland5 qtwayland5-dev-tools libqt5svg5*
|
||||
|
||||
```
|
||||
|
||||
然后
|
||||
```shell
|
||||
git clone https://gitee.com/deepin-community-store/spark-store.git
|
||||
cd spark-store
|
||||
dpkg-buildpackage -j
|
||||
```
|
||||
|
||||
或者: 编译并安装
|
||||
```shell
|
||||
git clone https://gitee.com/deepin-community-store/spark-store.git
|
||||
cd spark-store
|
||||
./build_and_install.sh
|
||||
```
|
||||
|
||||
|
||||
## 🚀 协作
|
||||
|
||||
非常感谢有兴趣的开发者或爱好者参与 `星火应用商店` 项目,分享你的见解与思路。
|
||||
|
||||
### 交流平台
|
||||
|
||||
https://chat.shenmo.tech/
|
||||
|
||||
客户端PWA:
|
||||
|
||||
spk://store/chat/store.spark-app.feedback
|
||||
|
||||
(安装星火商店后在浏览器打开或复制到搜索栏打开)
|
||||
24
build_and_install.sh
Executable file
24
build_and_install.sh
Executable file
@@ -0,0 +1,24 @@
|
||||
|
||||
# Deepin V20/UOS 21 系统下, 安装依赖
|
||||
|
||||
# ```shell
|
||||
# sudo apt install git qt5-default debhelper pkg-config qtchooser libqt5core5a libqt5gui5 libqt5widgets5 libqt5network5 libqt5concurrent5 libdtkcore-dev libdtkgui-dev libdtkwidget-dev qttools5-private-dev libnotify-dev qtwebengine5-dev fakeroot qtwayland5 qtwayland5-dev-tools dde-qt5wayland-plugin
|
||||
|
||||
# ```
|
||||
|
||||
# Ubuntu 22.04 系统下, 安装依赖
|
||||
# ```shell
|
||||
# sudo apt install git qtbase5-dev debhelper pkg-config qtchooser libqt5core5a libqt5gui5 libqt5widgets5 libqt5network5 libqt5concurrent5 libdtkcore-dev libdtkgui-dev libdtkwidget-dev qttools5-private-dev libnotify-dev qtwebengine5-dev qtwayland5 qtwayland5-dev-tools
|
||||
|
||||
# ```
|
||||
|
||||
echo "Deepin V20/UOS 21 系统下, 安装依赖"
|
||||
echo "sudo apt install git qt5-default debhelper pkg-config qtchooser libqt5core5a libqt5gui5 libqt5widgets5 libqt5network5 libqt5concurrent5 libdtkcore-dev libdtkgui-dev libdtkwidget-dev qttools5-private-dev libnotify-dev qtwebengine5-dev fakeroot qtwayland5 qtwayland5-dev-tools dde-qt5wayland-plugin"
|
||||
|
||||
echo "Ubuntu 22.04 系统下, 安装依赖"
|
||||
echo "sudo apt install git qtbase5-dev debhelper pkg-config qtchooser libqt5core5a libqt5gui5 libqt5widgets5 libqt5network5 libqt5concurrent5 libdtkcore-dev libdtkgui-dev libdtkwidget-dev qttools5-private-dev libnotify-dev qtwebengine5-dev qtwayland5 qtwayland5-dev-tools"
|
||||
|
||||
dpkg-buildpackage -j
|
||||
sudo apt reinstall ../spark-store_*.deb
|
||||
|
||||
rm ../spark-store_*
|
||||
@@ -1,52 +0,0 @@
|
||||
# - Try to find GDK 3
|
||||
# Once done, this will define
|
||||
#
|
||||
# GDK3_FOUND - system has GDK 3
|
||||
# GDK3_INCLUDE_DIRS - the GDK 3 include directories
|
||||
# GDK3_LIBRARIES - link these to use GDK 3
|
||||
#
|
||||
# Copyright (C) 2012 Raphael Kubo da Costa <rakuco@webkit.org>
|
||||
# Copyright (C) 2013 Igalia S.L.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS
|
||||
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# Source from:
|
||||
# https://sources.debian.org/src/qtwebkit-opensource-src/5.212.0%7Ealpha2-21/Source/cmake/FindGDK3.cmake/
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(GDK3 gdk-3.0)
|
||||
|
||||
set(VERSION_OK TRUE)
|
||||
if (GDK3_VERSION)
|
||||
if (GDK3_FIND_VERSION_EXACT)
|
||||
if (NOT("${GDK3_FIND_VERSION}" VERSION_EQUAL "${GDK3_VERSION}"))
|
||||
set(VERSION_OK FALSE)
|
||||
endif ()
|
||||
else ()
|
||||
if ("${GDK3_VERSION}" VERSION_LESS "${GDK3_FIND_VERSION}")
|
||||
set(VERSION_OK FALSE)
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(GDK3 DEFAULT_MSG GDK3_INCLUDE_DIRS GDK3_LIBRARIES VERSION_OK)
|
||||
@@ -1,125 +0,0 @@
|
||||
# - Try to find Glib and its components (gio, gobject etc)
|
||||
# Once done, this will define
|
||||
#
|
||||
# GLIB_FOUND - system has Glib
|
||||
# GLIB_INCLUDE_DIRS - the Glib include directories
|
||||
# GLIB_LIBRARIES - link these to use Glib
|
||||
#
|
||||
# Optionally, the COMPONENTS keyword can be passed to find_package()
|
||||
# and Glib components can be looked for. Currently, the following
|
||||
# components can be used, and they define the following variables if
|
||||
# found:
|
||||
#
|
||||
# gio: GLIB_GIO_LIBRARIES
|
||||
# gobject: GLIB_GOBJECT_LIBRARIES
|
||||
# gmodule: GLIB_GMODULE_LIBRARIES
|
||||
# gthread: GLIB_GTHREAD_LIBRARIES
|
||||
#
|
||||
# Note that the respective _INCLUDE_DIR variables are not set, since
|
||||
# all headers are in the same directory as GLIB_INCLUDE_DIRS.
|
||||
#
|
||||
# Copyright (C) 2012 Raphael Kubo da Costa <rakuco@webkit.org>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS
|
||||
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# Source from:
|
||||
# https://sources.debian.org/src/qtwebkit-opensource-src/5.212.0%7Ealpha2-21/Source/cmake/FindGLIB.cmake/
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(PC_GLIB QUIET glib-2.0)
|
||||
|
||||
find_library(GLIB_LIBRARIES
|
||||
NAMES glib-2.0
|
||||
HINTS ${PC_GLIB_LIBDIR}
|
||||
${PC_GLIB_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
# Files in glib's main include path may include glibconfig.h, which,
|
||||
# for some odd reason, is normally in $LIBDIR/glib-2.0/include.
|
||||
get_filename_component(_GLIB_LIBRARY_DIR ${GLIB_LIBRARIES} PATH)
|
||||
find_path(GLIBCONFIG_INCLUDE_DIR
|
||||
NAMES glibconfig.h
|
||||
HINTS ${PC_LIBDIR} ${PC_LIBRARY_DIRS} ${_GLIB_LIBRARY_DIR}
|
||||
${PC_GLIB_INCLUDEDIR} ${PC_GLIB_INCLUDE_DIRS}
|
||||
PATH_SUFFIXES glib-2.0/include
|
||||
)
|
||||
|
||||
find_path(GLIB_INCLUDE_DIR
|
||||
NAMES glib.h
|
||||
HINTS ${PC_GLIB_INCLUDEDIR}
|
||||
${PC_GLIB_INCLUDE_DIRS}
|
||||
PATH_SUFFIXES glib-2.0
|
||||
)
|
||||
|
||||
set(GLIB_INCLUDE_DIRS ${GLIB_INCLUDE_DIR} ${GLIBCONFIG_INCLUDE_DIR})
|
||||
|
||||
# Version detection
|
||||
if (EXISTS "${GLIBCONFIG_INCLUDE_DIR}/glibconfig.h")
|
||||
file(READ "${GLIBCONFIG_INCLUDE_DIR}/glibconfig.h" GLIBCONFIG_H_CONTENTS)
|
||||
string(REGEX MATCH "#define GLIB_MAJOR_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}")
|
||||
set(GLIB_VERSION_MAJOR "${CMAKE_MATCH_1}")
|
||||
string(REGEX MATCH "#define GLIB_MINOR_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}")
|
||||
set(GLIB_VERSION_MINOR "${CMAKE_MATCH_1}")
|
||||
string(REGEX MATCH "#define GLIB_MICRO_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}")
|
||||
set(GLIB_VERSION_MICRO "${CMAKE_MATCH_1}")
|
||||
set(GLIB_VERSION "${GLIB_VERSION_MAJOR}.${GLIB_VERSION_MINOR}.${GLIB_VERSION_MICRO}")
|
||||
endif ()
|
||||
|
||||
# Additional Glib components. We only look for libraries, as not all of them
|
||||
# have corresponding headers and all headers are installed alongside the main
|
||||
# glib ones.
|
||||
foreach (_component ${GLIB_FIND_COMPONENTS})
|
||||
if (${_component} STREQUAL "gio")
|
||||
find_library(GLIB_GIO_LIBRARIES NAMES gio-2.0 HINTS ${_GLIB_LIBRARY_DIR})
|
||||
set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GIO_LIBRARIES)
|
||||
elseif (${_component} STREQUAL "gobject")
|
||||
find_library(GLIB_GOBJECT_LIBRARIES NAMES gobject-2.0 HINTS ${_GLIB_LIBRARY_DIR})
|
||||
set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GOBJECT_LIBRARIES)
|
||||
elseif (${_component} STREQUAL "gmodule")
|
||||
find_library(GLIB_GMODULE_LIBRARIES NAMES gmodule-2.0 HINTS ${_GLIB_LIBRARY_DIR})
|
||||
set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GMODULE_LIBRARIES)
|
||||
elseif (${_component} STREQUAL "gthread")
|
||||
find_library(GLIB_GTHREAD_LIBRARIES NAMES gthread-2.0 HINTS ${_GLIB_LIBRARY_DIR})
|
||||
set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GTHREAD_LIBRARIES)
|
||||
elseif (${_component} STREQUAL "gio-unix")
|
||||
# gio-unix is compiled as part of the gio library, but the include paths
|
||||
# are separate from the shared glib ones. Since this is currently only used
|
||||
# by WebKitGTK+ we don't go to extraordinary measures beyond pkg-config.
|
||||
pkg_check_modules(GIO_UNIX QUIET gio-unix-2.0)
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLIB REQUIRED_VARS GLIB_INCLUDE_DIRS GLIB_LIBRARIES ${ADDITIONAL_REQUIRED_VARS}
|
||||
VERSION_VAR GLIB_VERSION)
|
||||
|
||||
mark_as_advanced(
|
||||
GLIBCONFIG_INCLUDE_DIR
|
||||
GLIB_GIO_LIBRARIES
|
||||
GLIB_GIO_UNIX_LIBRARIES
|
||||
GLIB_GMODULE_LIBRARIES
|
||||
GLIB_GOBJECT_LIBRARIES
|
||||
GLIB_GTHREAD_LIBRARIES
|
||||
GLIB_INCLUDE_DIR
|
||||
GLIB_INCLUDE_DIRS
|
||||
GLIB_LIBRARIES
|
||||
)
|
||||
@@ -1,58 +0,0 @@
|
||||
# - Try to find LibNotify
|
||||
# This module defines the following variables:
|
||||
#
|
||||
# LIBNOTIFY_FOUND - LibNotify was found
|
||||
# LIBNOTIFY_INCLUDE_DIRS - the LibNotify include directories
|
||||
# LIBNOTIFY_LIBRARIES - link these to use LibNotify
|
||||
#
|
||||
# Copyright (C) 2012 Raphael Kubo da Costa <rakuco@webkit.org>
|
||||
# Copyright (C) 2014 Collabora Ltd.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS
|
||||
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# Source from:
|
||||
# https://sources.debian.org/src/qtwebkit-opensource-src/5.212.0~alpha2-21/Source/cmake/FindLibNotify.cmake/
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(LIBNOTIFY QUIET libnotify)
|
||||
|
||||
find_path(LIBNOTIFY_INCLUDE_DIRS
|
||||
NAMES notify.h
|
||||
HINTS ${LIBNOTIFY_INCLUDEDIR}
|
||||
${LIBNOTIFY_INCLUDE_DIRS}
|
||||
PATH_SUFFIXES libnotify
|
||||
)
|
||||
|
||||
find_library(LIBNOTIFY_LIBRARIES
|
||||
NAMES notify
|
||||
HINTS ${LIBNOTIFY_LIBDIR}
|
||||
${LIBNOTIFY_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibNotify REQUIRED_VARS LIBNOTIFY_INCLUDE_DIRS LIBNOTIFY_LIBRARIES
|
||||
VERSION_VAR LIBNOTIFY_VERSION)
|
||||
|
||||
mark_as_advanced(
|
||||
LIBNOTIFY_INCLUDE_DIRS
|
||||
LIBNOTIFY_LIBRARIES
|
||||
)
|
||||
@@ -1,51 +0,0 @@
|
||||
# - FindXCB
|
||||
#
|
||||
# Copyright 2015 Valve Coporation
|
||||
|
||||
find_package(PkgConfig)
|
||||
|
||||
if(NOT XCB_FIND_COMPONENTS)
|
||||
set(XCB_FIND_COMPONENTS xcb)
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
set(XCB_FOUND true)
|
||||
set(XCB_INCLUDE_DIRS "")
|
||||
set(XCB_LIBRARIES "")
|
||||
foreach(comp ${XCB_FIND_COMPONENTS})
|
||||
# component name
|
||||
string(TOUPPER ${comp} compname)
|
||||
string(REPLACE "-" "_" compname ${compname})
|
||||
# header name
|
||||
string(REPLACE "xcb-" "" headername xcb/${comp}.h)
|
||||
# library name
|
||||
set(libname ${comp})
|
||||
|
||||
pkg_check_modules(PC_${comp} QUIET ${comp})
|
||||
|
||||
find_path(${compname}_INCLUDE_DIR NAMES ${headername}
|
||||
HINTS
|
||||
${PC_${comp}_INCLUDEDIR}
|
||||
${PC_${comp}_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
find_library(${compname}_LIBRARY NAMES ${libname}
|
||||
HINTS
|
||||
${PC_${comp}_LIBDIR}
|
||||
${PC_${comp}_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
find_package_handle_standard_args(${comp}
|
||||
FOUND_VAR ${comp}_FOUND
|
||||
REQUIRED_VARS ${compname}_INCLUDE_DIR ${compname}_LIBRARY)
|
||||
mark_as_advanced(${compname}_INCLUDE_DIR ${compname}_LIBRARY)
|
||||
|
||||
list(APPEND XCB_INCLUDE_DIRS ${${compname}_INCLUDE_DIR})
|
||||
list(APPEND XCB_LIBRARIES ${${compname}_LIBRARY})
|
||||
|
||||
if(NOT ${comp}_FOUND)
|
||||
set(XCB_FOUND false)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
list(REMOVE_DUPLICATES XCB_INCLUDE_DIRS)
|
||||
@@ -1,335 +0,0 @@
|
||||
# git_watcher.cmake
|
||||
# https://raw.githubusercontent.com/andrew-hardin/cmake-git-version-tracking/master/git_watcher.cmake
|
||||
#
|
||||
# Released under the MIT License.
|
||||
# https://raw.githubusercontent.com/andrew-hardin/cmake-git-version-tracking/master/LICENSE
|
||||
|
||||
|
||||
# This file defines a target that monitors the state of a git repo.
|
||||
# If the state changes (e.g. a commit is made), then a file gets reconfigured.
|
||||
# Here are the primary variables that control script behavior:
|
||||
#
|
||||
# PRE_CONFIGURE_FILE (REQUIRED)
|
||||
# -- The path to the file that'll be configured.
|
||||
#
|
||||
# POST_CONFIGURE_FILE (REQUIRED)
|
||||
# -- The path to the configured PRE_CONFIGURE_FILE.
|
||||
#
|
||||
# GIT_STATE_FILE (OPTIONAL)
|
||||
# -- The path to the file used to store the previous build's git state.
|
||||
# Defaults to the current binary directory.
|
||||
#
|
||||
# GIT_WORKING_DIR (OPTIONAL)
|
||||
# -- The directory from which git commands will be run.
|
||||
# Defaults to the directory with the top level CMakeLists.txt.
|
||||
#
|
||||
# GIT_EXECUTABLE (OPTIONAL)
|
||||
# -- The path to the git executable. It'll automatically be set if the
|
||||
# user doesn't supply a path.
|
||||
#
|
||||
# GIT_FAIL_IF_NONZERO_EXIT (optional)
|
||||
# -- Raise a FATAL_ERROR if any of the git commands return a non-zero
|
||||
# exit code. This is set to TRUE by default. You can set this to FALSE
|
||||
# if you'd like the build to continue even if a git command fails.
|
||||
#
|
||||
# DESIGN
|
||||
# - This script was designed similar to a Python application
|
||||
# with a Main() function. I wanted to keep it compact to
|
||||
# simplify "copy + paste" usage.
|
||||
#
|
||||
# - This script is invoked under two CMake contexts:
|
||||
# 1. Configure time (when build files are created).
|
||||
# 2. Build time (called via CMake -P).
|
||||
# The first invocation is what registers the script to
|
||||
# be executed at build time.
|
||||
#
|
||||
# MODIFICATIONS
|
||||
# You may wish to track other git properties like when the last
|
||||
# commit was made. There are two sections you need to modify,
|
||||
# and they're tagged with a ">>>" header.
|
||||
|
||||
# Short hand for converting paths to absolute.
|
||||
macro(PATH_TO_ABSOLUTE var_name)
|
||||
get_filename_component(${var_name} "${${var_name}}" ABSOLUTE)
|
||||
endmacro()
|
||||
|
||||
# Check that a required variable is set.
|
||||
macro(CHECK_REQUIRED_VARIABLE var_name)
|
||||
if(NOT DEFINED ${var_name})
|
||||
message(FATAL_ERROR "The \"${var_name}\" variable must be defined.")
|
||||
endif()
|
||||
PATH_TO_ABSOLUTE(${var_name})
|
||||
endmacro()
|
||||
|
||||
# Check that an optional variable is set, or, set it to a default value.
|
||||
macro(CHECK_OPTIONAL_VARIABLE_NOPATH var_name default_value)
|
||||
if(NOT DEFINED ${var_name})
|
||||
set(${var_name} ${default_value})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Check that an optional variable is set, or, set it to a default value.
|
||||
# Also converts that path to an abspath.
|
||||
macro(CHECK_OPTIONAL_VARIABLE var_name default_value)
|
||||
CHECK_OPTIONAL_VARIABLE_NOPATH(${var_name} ${default_value})
|
||||
PATH_TO_ABSOLUTE(${var_name})
|
||||
endmacro()
|
||||
|
||||
CHECK_REQUIRED_VARIABLE(PRE_CONFIGURE_FILE)
|
||||
CHECK_REQUIRED_VARIABLE(POST_CONFIGURE_FILE)
|
||||
CHECK_OPTIONAL_VARIABLE(GIT_STATE_FILE "${CMAKE_BINARY_DIR}/git-state-hash")
|
||||
CHECK_OPTIONAL_VARIABLE(GIT_WORKING_DIR "${CMAKE_SOURCE_DIR}")
|
||||
CHECK_OPTIONAL_VARIABLE_NOPATH(GIT_FAIL_IF_NONZERO_EXIT TRUE)
|
||||
|
||||
# Check the optional git variable.
|
||||
# If it's not set, we'll try to find it using the CMake packaging system.
|
||||
if(NOT DEFINED GIT_EXECUTABLE)
|
||||
find_package(Git QUIET REQUIRED)
|
||||
endif()
|
||||
CHECK_REQUIRED_VARIABLE(GIT_EXECUTABLE)
|
||||
|
||||
|
||||
set(_state_variable_names
|
||||
GIT_RETRIEVED_STATE
|
||||
GIT_HEAD_SHA1
|
||||
GIT_IS_DIRTY
|
||||
GIT_AUTHOR_NAME
|
||||
GIT_AUTHOR_EMAIL
|
||||
GIT_COMMIT_DATE_ISO8601
|
||||
GIT_COMMIT_SUBJECT
|
||||
GIT_COMMIT_BODY
|
||||
GIT_DESCRIBE
|
||||
# >>>
|
||||
# 1. Add the name of the additional git variable you're interested in monitoring
|
||||
# to this list.
|
||||
)
|
||||
|
||||
|
||||
|
||||
# Macro: RunGitCommand
|
||||
# Description: short-hand macro for calling a git function. Outputs are the
|
||||
# "exit_code" and "output" variables.
|
||||
macro(RunGitCommand)
|
||||
execute_process(COMMAND
|
||||
"${GIT_EXECUTABLE}" ${ARGV}
|
||||
WORKING_DIRECTORY "${_working_dir}"
|
||||
RESULT_VARIABLE exit_code
|
||||
OUTPUT_VARIABLE output
|
||||
ERROR_VARIABLE stderr
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT exit_code EQUAL 0)
|
||||
set(ENV{GIT_RETRIEVED_STATE} "false")
|
||||
|
||||
# Issue 26: git info not properly set
|
||||
#
|
||||
# Check if we should fail if any of the exit codes are non-zero.
|
||||
if(GIT_FAIL_IF_NONZERO_EXIT)
|
||||
string(REPLACE ";" " " args_with_spaces "${ARGV}")
|
||||
message(FATAL_ERROR "${stderr} (${GIT_EXECUTABLE} ${args_with_spaces})")
|
||||
endif()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
|
||||
|
||||
# Function: GetGitState
|
||||
# Description: gets the current state of the git repo.
|
||||
# Args:
|
||||
# _working_dir (in) string; the directory from which git commands will be executed.
|
||||
function(GetGitState _working_dir)
|
||||
|
||||
# This is an error code that'll be set to FALSE if the
|
||||
# RunGitCommand ever returns a non-zero exit code.
|
||||
set(ENV{GIT_RETRIEVED_STATE} "true")
|
||||
|
||||
# Get whether or not the working tree is dirty.
|
||||
RunGitCommand(status --porcelain)
|
||||
if(NOT exit_code EQUAL 0)
|
||||
set(ENV{GIT_IS_DIRTY} "false")
|
||||
else()
|
||||
if(NOT "${output}" STREQUAL "")
|
||||
set(ENV{GIT_IS_DIRTY} "true")
|
||||
else()
|
||||
set(ENV{GIT_IS_DIRTY} "false")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# There's a long list of attributes grabbed from git show.
|
||||
set(object HEAD)
|
||||
RunGitCommand(show -s "--format=%H" ${object})
|
||||
if(exit_code EQUAL 0)
|
||||
set(ENV{GIT_HEAD_SHA1} ${output})
|
||||
endif()
|
||||
|
||||
RunGitCommand(show -s "--format=%an" ${object})
|
||||
if(exit_code EQUAL 0)
|
||||
set(ENV{GIT_AUTHOR_NAME} "${output}")
|
||||
endif()
|
||||
|
||||
RunGitCommand(show -s "--format=%ae" ${object})
|
||||
if(exit_code EQUAL 0)
|
||||
set(ENV{GIT_AUTHOR_EMAIL} "${output}")
|
||||
endif()
|
||||
|
||||
RunGitCommand(show -s "--format=%ci" ${object})
|
||||
if(exit_code EQUAL 0)
|
||||
set(ENV{GIT_COMMIT_DATE_ISO8601} "${output}")
|
||||
endif()
|
||||
|
||||
RunGitCommand(show -s "--format=%s" ${object})
|
||||
if(exit_code EQUAL 0)
|
||||
# Escape quotes
|
||||
string(REPLACE "\"" "\\\"" output "${output}")
|
||||
set(ENV{GIT_COMMIT_SUBJECT} "${output}")
|
||||
endif()
|
||||
|
||||
RunGitCommand(show -s "--format=%b" ${object})
|
||||
if(exit_code EQUAL 0)
|
||||
if(output)
|
||||
# Escape quotes
|
||||
string(REPLACE "\"" "\\\"" output "${output}")
|
||||
# Escape line breaks in the commit message.
|
||||
string(REPLACE "\r\n" "\\r\\n\\\r\n" safe "${output}")
|
||||
if(safe STREQUAL output)
|
||||
# Didn't have windows lines - try unix lines.
|
||||
string(REPLACE "\n" "\\n\\\n" safe "${output}")
|
||||
endif()
|
||||
else()
|
||||
# There was no commit body - set the safe string to empty.
|
||||
set(safe "")
|
||||
endif()
|
||||
set(ENV{GIT_COMMIT_BODY} "\"${safe}\"")
|
||||
else()
|
||||
set(ENV{GIT_COMMIT_BODY} "\"\"") # empty string.
|
||||
endif()
|
||||
|
||||
# Get output of git describe
|
||||
RunGitCommand(describe --tags ${object})
|
||||
if(NOT exit_code EQUAL 0)
|
||||
set(ENV{GIT_DESCRIBE} "unknown")
|
||||
else()
|
||||
set(ENV{GIT_DESCRIBE} "${output}")
|
||||
endif()
|
||||
|
||||
# >>>
|
||||
# 2. Additional git properties can be added here via the
|
||||
# "execute_process()" command. Be sure to set them in
|
||||
# the environment using the same variable name you added
|
||||
# to the "_state_variable_names" list.
|
||||
|
||||
endfunction()
|
||||
|
||||
|
||||
|
||||
# Function: GitStateChangedAction
|
||||
# Description: this function is executed when the state of the git
|
||||
# repository changes (e.g. a commit is made).
|
||||
function(GitStateChangedAction)
|
||||
foreach(var_name ${_state_variable_names})
|
||||
set(${var_name} $ENV{${var_name}})
|
||||
endforeach()
|
||||
configure_file("${PRE_CONFIGURE_FILE}" "${POST_CONFIGURE_FILE}" @ONLY)
|
||||
endfunction()
|
||||
|
||||
|
||||
|
||||
# Function: HashGitState
|
||||
# Description: loop through the git state variables and compute a unique hash.
|
||||
# Args:
|
||||
# _state (out) string; a hash computed from the current git state.
|
||||
function(HashGitState _state)
|
||||
set(ans "")
|
||||
foreach(var_name ${_state_variable_names})
|
||||
string(SHA256 ans "${ans}$ENV{${var_name}}")
|
||||
endforeach()
|
||||
set(${_state} ${ans} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
|
||||
# Function: CheckGit
|
||||
# Description: check if the git repo has changed. If so, update the state file.
|
||||
# Args:
|
||||
# _working_dir (in) string; the directory from which git commands will be ran.
|
||||
# _state_changed (out) bool; whether or no the state of the repo has changed.
|
||||
function(CheckGit _working_dir _state_changed)
|
||||
|
||||
# Get the current state of the repo.
|
||||
GetGitState("${_working_dir}")
|
||||
|
||||
# Convert that state into a hash that we can compare against
|
||||
# the hash stored on-disk.
|
||||
HashGitState(state)
|
||||
|
||||
# Issue 14: post-configure file isn't being regenerated.
|
||||
#
|
||||
# Update the state to include the SHA256 for the pre-configure file.
|
||||
# This forces the post-configure file to be regenerated if the
|
||||
# pre-configure file has changed.
|
||||
file(SHA256 ${PRE_CONFIGURE_FILE} preconfig_hash)
|
||||
string(SHA256 state "${preconfig_hash}${state}")
|
||||
|
||||
# Check if the state has changed compared to the backup on disk.
|
||||
if(EXISTS "${GIT_STATE_FILE}")
|
||||
file(READ "${GIT_STATE_FILE}" OLD_HEAD_CONTENTS)
|
||||
if(OLD_HEAD_CONTENTS STREQUAL "${state}")
|
||||
# State didn't change.
|
||||
set(${_state_changed} "false" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# The state has changed.
|
||||
# We need to update the state file on disk.
|
||||
# Future builds will compare their state to this file.
|
||||
file(WRITE "${GIT_STATE_FILE}" "${state}")
|
||||
set(${_state_changed} "true" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
|
||||
# Function: SetupGitMonitoring
|
||||
# Description: this function sets up custom commands that make the build system
|
||||
# check the state of git before every build. If the state has
|
||||
# changed, then a file is configured.
|
||||
function(SetupGitMonitoring)
|
||||
add_custom_target(check_git
|
||||
ALL
|
||||
DEPENDS ${PRE_CONFIGURE_FILE}
|
||||
BYPRODUCTS
|
||||
${POST_CONFIGURE_FILE}
|
||||
${GIT_STATE_FILE}
|
||||
COMMENT "Checking the git repository for changes..."
|
||||
COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
-D_BUILD_TIME_CHECK_GIT=TRUE
|
||||
-DGIT_WORKING_DIR=${GIT_WORKING_DIR}
|
||||
-DGIT_EXECUTABLE=${GIT_EXECUTABLE}
|
||||
-DGIT_STATE_FILE=${GIT_STATE_FILE}
|
||||
-DPRE_CONFIGURE_FILE=${PRE_CONFIGURE_FILE}
|
||||
-DPOST_CONFIGURE_FILE=${POST_CONFIGURE_FILE}
|
||||
-DGIT_FAIL_IF_NONZERO_EXIT=${GIT_FAIL_IF_NONZERO_EXIT}
|
||||
-P "${CMAKE_CURRENT_LIST_FILE}")
|
||||
endfunction()
|
||||
|
||||
|
||||
|
||||
# Function: Main
|
||||
# Description: primary entry-point to the script. Functions are selected based
|
||||
# on whether it's configure or build time.
|
||||
function(Main)
|
||||
if(_BUILD_TIME_CHECK_GIT)
|
||||
# Check if the repo has changed.
|
||||
# If so, run the change action.
|
||||
CheckGit("${GIT_WORKING_DIR}" changed)
|
||||
if(changed OR NOT EXISTS "${POST_CONFIGURE_FILE}")
|
||||
GitStateChangedAction()
|
||||
endif()
|
||||
else()
|
||||
# >> Executes at configure time.
|
||||
SetupGitMonitoring()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# And off we go...
|
||||
Main()
|
||||
628
debian/changelog
vendored
Normal file
628
debian/changelog
vendored
Normal file
@@ -0,0 +1,628 @@
|
||||
spark-store (4.2.3.2~Reason6) stable; urgency=medium
|
||||
* ssinstall发现无法验证时尝试update而不是ssupdate
|
||||
* 启动每日aptss update
|
||||
|
||||
-- shenmo <shenmo@spark-app.store>
|
||||
|
||||
|
||||
spark-store (4.2.3.2~Reason5) stable; urgency=medium
|
||||
* aptss 不再使用bwrap,去除依赖,支持容器中启动
|
||||
* aptss 支持非root模式启动
|
||||
* aptss 添加transhell支持
|
||||
* 关于界面自动获取分支名称
|
||||
* 现在安装成功则自动删除安装包
|
||||
|
||||
-- shenmo <shenmo@spark-app.store>
|
||||
spark-store (4.2.3.2~Reason3) stable; urgency=medium
|
||||
* 现在可在x86上编译,使用同一套代码
|
||||
* 暂时在aarch64上使用旧web----等待柚子
|
||||
* 空间,疾疫,现在是静谧
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Sun, 5 Mar 2022 11:45:14 +0800
|
||||
|
||||
spark-store (4.2.3.2~only-for-test1) stable; urgency=medium
|
||||
* 注意!!!!!! 此版本仅为启动测试,还需要进一步完善——hardcode需要改善——关于web界面的调用方式需要在柚子做好之后修改成新的
|
||||
* fix: hardcode
|
||||
* fix: sender-d
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
spark-store (4.2.3.1) stable; urgency=medium
|
||||
* 修复: ssinstall验证签名出错
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
spark-store (4.2.3) stable; urgency=medium
|
||||
* 修复: 编译依赖不全
|
||||
* 修复: prerm导致的dpkg崩溃
|
||||
* 新增: aptss 检查package配置增加sdu,store
|
||||
* 新增: 一键编译并安装脚本
|
||||
* 新增: 后台安装结束后退出任务栏驻留
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
spark-store (4.2.3~test4) stable; urgency=medium
|
||||
|
||||
* 修复: aptss 无法安装
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
spark-store (4.2.3~test3) stable; urgency=medium
|
||||
|
||||
* 调整:打包时从 debian/changelog 自动获取构建版本号并写入关于窗口保证与deb一致
|
||||
* 新增:支持 DTK 5.6.4 关于对话框“版本特性”显示功能。目前只在deepin编译安装时开启
|
||||
* 修复:修复下载列表对话框中,点击某个 item 取消下载按钮后下载列表无法再次显示的问题
|
||||
* 修复:多个应用安装可能会出现某一个应用没有安装
|
||||
* 修复:修复下载按钮点击/双击/拖动时,主窗口动作与下载管理对话框动作同时触发问题
|
||||
* aptss 获取线路信息 转到从 d. 服务器获取
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
spark-store (4.2.3~test2) stable; urgency=medium
|
||||
|
||||
* 调整:开启安装包加固
|
||||
* 添加:zh_TW翻译
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (4.2.3~test1) stable; urgency=medium
|
||||
|
||||
* 修复:因判断安装状态错误创建多个相同任务的bug
|
||||
* 测试中:尝试修复安装结束的闪退问题 https://gitee.com/deepin-community-store/spark-store/commit/cb093dcc2bb0a193db89aa0ce5f20ea9cc5d56eb
|
||||
* 修复:Deepin 显示开发者模式未开启
|
||||
* 修复:从托盘打开主窗口时透明度动画不流畅
|
||||
* 修复:主窗口关闭后,从托盘打开关于窗口会被主窗口遮挡
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Sun, 05 Feb 2023 23:00:00 +0800
|
||||
|
||||
|
||||
spark-store (4.2.2) stable; urgency=medium
|
||||
|
||||
* 调整:脚本应用的transhell支持转为source导入
|
||||
* 修复:ssinstall弹窗支持wayland
|
||||
* 新增:应用托盘,下载时候可以放心关闭窗口了
|
||||
* 新增:支持spk://search/内容 格式链接
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (4.2.1) stable; urgency=medium
|
||||
|
||||
* 调整:支持在安装前进行测试(ss-do-upgrade-worker),但是未实装到appinfo
|
||||
* 修复:因依赖不完全导致在LinuxMint下无法下载统计
|
||||
* 新增:脚本系列应用支持英文
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (4.2) stable; urgency=medium
|
||||
|
||||
* 调整:UOS开发者模式提示现在不会那么挤了
|
||||
* 修复:wayland下可正常弹出更新提示
|
||||
* 调整:dwine5标签的文案改为:Wine应用
|
||||
* 新增:更新软件时弹窗会显示正在更新的软件包名
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (4.2~test3) stable; urgency=medium
|
||||
|
||||
* 修复: aptss ssupdates
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (4.2~test2) stable; urgency=medium
|
||||
|
||||
* 修复: 420t1版本中ssinstall有时会重新下载软件包的问题
|
||||
* 新增: 安装前会对软件包安装进行dry run以判断是否能正确安装
|
||||
* 调整: aptss在进行任何操作前均检测是否存在Packages文件,若存在,则不进行ssupdate
|
||||
* 调整: 修改apt-fast源代码以指定conf位置为/tmp/apt-fast,这部分不再使用bwrap模拟
|
||||
* 新增: aptss检测Package文件支持分目录(目前指定为store)
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (4.2~test1) stable; urgency=medium
|
||||
|
||||
* 新增: aptss支持显示报错
|
||||
* 新增: aptss部分提示汉化
|
||||
* 修复: 修复部分情况下ssinstall实际未安装但是错误显示
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (4.1.2) stable; urgency=medium
|
||||
|
||||
* feat: 初步的wayland支持
|
||||
* feat: UOS下检测开发者模式是否开启,若未开启则拒绝安装
|
||||
* fix: 首页的捐赠页面在中文环境下显示中文
|
||||
* fix: 更新检测模块在aptss ssupdate操作失败后现在会正确地移除锁而不是错误的残留锁。
|
||||
* chore: ssinstall现在拒绝安装验证失败的包,审核操作现在需要改用ssaudit
|
||||
* fix: Ubuntu下下载列表无法关闭
|
||||
* fix: 修复进入详情页时焦点默认在分享链接按钮上的问题
|
||||
* fix: 修复特定情况下的内存泄漏问题
|
||||
* fix: 适配c11代码规范,消除qt编译警告
|
||||
* fix: 默认服务器域名指向cdn域名
|
||||
* fix: 消除内部函数的无用变量,限制作用域
|
||||
* feat: aptss 除ssupdate外的操作时候如果检测到存在源文件存在则不再重复获取
|
||||
* fix: 修复在apt list锁被锁定的时候异常弹出有更新可用
|
||||
* chore: 去除安装依赖:g++
|
||||
* fix: 修复下载列表中进度提示文字显示不完整的问题
|
||||
* feat: ssinstall支持从单独文件夹中校验软件包
|
||||
* feat: 支持分单文件夹下载。具体内容参见:https://gitee.com/deepin-community-store/repo_auto_update_script/blob/master/mirror-list-for-apt-fast/sources.list.d/sparkstore.list
|
||||
* info: 非常感谢 @jwyh 对星火商店代码仓库设计了很多标准,参见 https://deepin-community-store.gitee.io/spark-wiki/#/Dev/Spark-Store-Git-Repo?id=%e6%9b%b4%e6%96%b0%e6%97%a5%e5%bf%97%e8%a7%84%e5%88%99 ,不过shenmo是自由的
|
||||
|
||||
|
||||
* chore: 添加 Application 类,继承 DApplication,将 main 函数中设置属性、关于信息等操作移至 Application 构造函数中进行
|
||||
* chore: 添加 setOrganizationName 操作,设置组织名称为 spark-union,与 SWRT 保持一致
|
||||
* chore: 设置组织名称后,QStandardPaths::AppConfigLocation 等路径相应改变,修改所有配置文件和缓存文件路径
|
||||
* chore: 关于对话框设置父对象后,对话框背景色受主窗口样式表影响,移动部分控件样式表设置方式与位置
|
||||
* chore: 去除 .pro 文件中无效的更新翻译文件脚本调用,整理 .pro 文件,添加编译时更新 ts 文件脚本调用
|
||||
* chore: 继续修复偶现关闭客户端时崩溃问题(疑似 aria2c 进程未启动,pid 未初始化为随机值,执行 kill 操作时未判断导致)
|
||||
* chore: 新增编译依赖,测试安装时不会出现报错
|
||||
* chore: 暂时去除没有意义的 DBus 接口,使用 DGuiApplicationHelper::newProcessInstance 获取新进程的启动参数
|
||||
* chore: 更新翻译文件,去除已经不存在的翻译
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (4.1.2~test2) stable; urgency=medium
|
||||
|
||||
* feat: ssinstall支持从单独文件夹中校验软件包
|
||||
* feat: 支持分单文件夹下载。具体内容参见:https://gitee.com/deepin-community-store/repo_auto_update_script/blob/master/mirror-list-for-apt-fast/sources.list.d/sparkstore.list
|
||||
* info: 非常感谢 @jwyh 对星火商店代码仓库设计了很多标准,参见 https://deepin-community-store.gitee.io/spark-wiki/#/Dev/Spark-Store-Git-Repo ,不过shenmo是自由的
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (4.1.2~test1) stable; urgency=medium
|
||||
|
||||
* feat: 初步的wayland支持
|
||||
* feat: UOS下检测开发者模式是否开启,若未开启则拒绝安装
|
||||
* fix: 首页的捐赠页面在中文环境下显示中文
|
||||
* fix: 更新检测模块在aptss ssupdate操作失败后现在会正确地移除锁而不是错误的残留锁。
|
||||
* chore: ssinstall现在拒绝安装验证失败的包,审核操作现在需要改用ssaudit
|
||||
* fix: Ubuntu下下载列表无法关闭
|
||||
* fix: 修复进入详情页时焦点默认在分享链接按钮上的问题
|
||||
* fix: 修复特定情况下的内存泄漏问题
|
||||
* fix: 适配c11代码规范,消除qt编译警告
|
||||
* fix: 默认服务器域名指向cdn域名
|
||||
* fix: 消除内部函数的无用变量,限制作用域
|
||||
* feat: aptss 除ssupdate外的操作时候如果检测到存在源文件存在则不再重复获取
|
||||
* fix: 修复在apt list锁被锁定的时候异常弹出有更新可用
|
||||
* chore: 去除安装依赖:g++
|
||||
* fix: 修复下载列表中进度提示文字显示不完整的问题
|
||||
|
||||
|
||||
* chore: 添加 Application 类,继承 DApplication,将 main 函数中设置属性、关于信息等操作移至 Application 构造函数中进行
|
||||
* chore: 添加 setOrganizationName 操作,设置组织名称为 spark-union,与 SWRT 保持一致
|
||||
* chore: 设置组织名称后,QStandardPaths::AppConfigLocation 等路径相应改变,修改所有配置文件和缓存文件路径
|
||||
* chore: 关于对话框设置父对象后,对话框背景色受主窗口样式表影响,移动部分控件样式表设置方式与位置
|
||||
* chore: 去除 .pro 文件中无效的更新翻译文件脚本调用,整理 .pro 文件,添加编译时更新 ts 文件脚本调用
|
||||
* chore: 继续修复偶现关闭客户端时崩溃问题(疑似 aria2c 进程未启动,pid 未初始化为随机值,执行 kill 操作时未判断导致)
|
||||
* chore: 新增编译依赖,测试安装时不会出现报错
|
||||
* chore: 暂时去除没有意义的 DBus 接口,使用 DGuiApplicationHelper::newProcessInstance 获取新进程的启动参数
|
||||
* chore: 更新翻译文件,去除已经不存在的翻译
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (4.1.1) stable; urgency=medium
|
||||
|
||||
* fix:更新失效
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (4.1.0) stable; urgency=medium
|
||||
|
||||
* feat: 现在可以支持UOS签名包问题了
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (4.0.1) stable; urgency=medium
|
||||
|
||||
* feat: 提升Ubuntu下的显示效果
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (4.0.0) stable; urgency=medium
|
||||
|
||||
* feat: 修复了成吨的bug后开始正式版
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (4.0.0~test2) stable; urgency=medium
|
||||
|
||||
* feat: 修复了成吨的bug后开始公测
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (4.0.0~test1) stable; urgency=medium
|
||||
|
||||
* feat: 柚子过来补充一下啦
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.4~test1) stable; urgency=medium
|
||||
|
||||
* feat: aptss不再尝试安装apt-fast,转而自带
|
||||
* chore: 删除password-check模块
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.3.3) stable; urgency=medium
|
||||
|
||||
* feat: 首页链接调用浏览器打开
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.3.3~test5) stable; urgency=medium
|
||||
|
||||
* 修复可能的内存泄漏问题
|
||||
* 修复应用搜索为空但仍显示上一次搜索结果的问题
|
||||
* 修复动画加载延后的问题
|
||||
* 修复统计下载量卡主渲染线程的问题
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.3.3~test4) stable; urgency=medium
|
||||
|
||||
* Enable i386 arch support by default
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.3.3~test3) stable; urgency=medium
|
||||
|
||||
* Now use ss-apt-fast instead of apt-fast
|
||||
* 修复:右上角 更新和安装设置 菜单中进入更新列表失效
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.3.3~test2) stable; urgency=medium
|
||||
|
||||
* bug fix: 更新和检查更新出错时不报错.此更新需要一个推送
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.3.3~test1) stable; urgency=medium
|
||||
|
||||
* 3.3.3将会是修复大部分bug后的最终版本
|
||||
* 图形环境中所有root权限的组件剥离到cli(可用于deepin 23 daily,只保证商店本体正常运作,不处理安装依赖不满足)
|
||||
* 文案更改:更新检查-->检查更新
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.3.1~test1) stable; urgency=medium
|
||||
|
||||
* 安装时不再需要联网
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.3.0.4) stable; urgency=medium
|
||||
|
||||
* 为减轻服务器压力,不再单独更新某一个应用,而是作为整体更新
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.3.0.3) stable; urgency=medium
|
||||
|
||||
* 回滚 更新中行为到进度条而不是实时输出
|
||||
* 更新应用时显示正在更新哪个应用
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.3.0.2) stable; urgency=medium
|
||||
|
||||
* 修复 pkexec未执行
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.3.0.1) stable; urgency=medium
|
||||
|
||||
* 修复 检查更新的更新进程未实际运行
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.3) stable; urgency=medium
|
||||
|
||||
* 修复 检查更新 未刷新软件源
|
||||
* 把检查更新单独拿出作为左列
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.3~test3) stable; urgency=medium
|
||||
|
||||
* 把检查更新加入免密码
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.3~test2) stable; urgency=medium
|
||||
|
||||
* 更新检测功能全部更改到zenity
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.3~test1) stable; urgency=medium
|
||||
|
||||
* zenity,选择可更新应用
|
||||
* 自动更新检测现在会跳过hold
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.2.4) stable; urgency=medium
|
||||
|
||||
* 修改tag相关的文案内容:wine相关环境已可自动配置了
|
||||
* 准备发版
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.2.4~test4) stable; urgency=medium
|
||||
|
||||
* 现在在商店启动后点击spk链接仍会正常启动 https://gitee.com/deepin-community-store/spark-store/commit/dd6780d636042bf12d77414e6f1552cc7d1ed24c
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.2.4~test3) stable; urgency=medium
|
||||
|
||||
* 发版,合入到master
|
||||
* 翻译完毕
|
||||
* 合入先前的各项改动,为:客户端集成投稿器入口和支持,修复:安装依赖时间较长时错误地返回“安装完毕”结果,现在客户端版本更新时不关闭免密码登录,UOS安装进程合并正常aptss中
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.2.4~test2) stable; urgency=medium
|
||||
|
||||
* 客户端集成投稿器入口和支持
|
||||
* 修复:安装依赖时间较长时错误地返回“安装完毕”结果
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.2.4~test1) stable; urgency=medium
|
||||
|
||||
* 客户端更新时不关闭免密码登录
|
||||
* UOS合并正常aptss中
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.2.3) stable; urgency=medium
|
||||
|
||||
* 客户端异常退出时仍然占用资源问题修复
|
||||
* 降低dtk依赖版本,Debian 11 stable可直接安装
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.2.2) stable; urgency=medium
|
||||
|
||||
* aptss will now refresh the system source before doing install, policy....etc
|
||||
* 启动客户端GPU加速支持
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.2.1) stable; urgency=medium
|
||||
|
||||
* 更改刷新系统源的功能
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.2) stable; urgency=medium
|
||||
|
||||
* 新增 下载量统计功能
|
||||
* 新增 显示下载量
|
||||
* 修复 spk链接生成错误
|
||||
* 调整 启动时检测商店applist源
|
||||
* 新增 applist cdn加速
|
||||
* 调整 ssupdate不再更新/etc/aptss下的cache,如要如此,请使用aptss update
|
||||
* 修复 在更新检测设置中的是否开启自动更新检测设置项的显示不随开启或关闭状态改变
|
||||
* 修复 在检测更新时临时降低优先级到100,防止系统中有且版本一致的包被反复来回更新
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.1.6) stable; urgency=medium
|
||||
|
||||
* 修复部分情况下无法选中正确的镜像源的问题
|
||||
* 合入3.1.5以来的各项修改
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.1.5-5) stable; urgency=medium
|
||||
|
||||
* 从所有镜像源中选取最快镜像源高速下载
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.1.5-4) stable; urgency=medium
|
||||
|
||||
* 更改ss-apt-fast策略,现在只会在update,ssupdate和没有检测到配置文件的时候更新配置文件
|
||||
* 新增ss-apt-fast别名:aptss
|
||||
* 更新检测服务优化:从分体改为一体
|
||||
* aptss 支持自动补全
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.1.5-3) stable; urgency=medium
|
||||
|
||||
* 包内自带密钥
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.1.5-2) stable; urgency=medium
|
||||
|
||||
* 下载软件时跳过获取大小,修复部分软件无法下载的问题
|
||||
* 修复 获取key时出错,指定使用http1.1
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.1.5-1) stable; urgency=medium
|
||||
|
||||
* 改变更新策略,UOS也下载加速,但是安装不加速
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.1.5) stable; urgency=medium
|
||||
|
||||
* 改变更新策略,现在支持应用在更新时引入新依赖
|
||||
* ss-apt-fast现在默认允许降级,以与apt使用体验一致
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.1.4-2) stable; urgency=medium
|
||||
|
||||
* 客户端下载使用metalink来支持bt下载加速
|
||||
* 修复使用更新和安装设置更新商店本体时出错
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.1.4-1) stable; urgency=medium
|
||||
|
||||
* 安装脚本和检测更新脚本检查网络时间超时时间延长至5s
|
||||
* 修复:ssinstall在没有安装apt-fast的情况下首次安装需要依赖的软件时安装失败
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.1.4) stable; urgency=medium
|
||||
|
||||
* 发布正式版,同步到官网
|
||||
* 修复安装时使用wget的问题
|
||||
* 合并3.1.3-1和3.1.3-2的更改
|
||||
* 屏蔽了ssinstall之外的安装方式
|
||||
* 调整了报错框的形式
|
||||
* 修复pkexec下ssinstall不处理依赖
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.1.3-2) stable; urgency=medium
|
||||
|
||||
* 调整 现在与系统更新分开,不再导致更新失败
|
||||
* 支持直接更新软件源文件,不再让d.吃全部更新流量
|
||||
* ss-apt-fast不再强制root权限
|
||||
* 修改ss-apt-fast的策略,现在除了安装,下载和更新都改用apt
|
||||
* ssinstall 现在也会在不适用ss-apt-fast的时候模拟源了(针对UOS)
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.1.3-1) stable; urgency=medium
|
||||
|
||||
* 修复 下载提前退出
|
||||
* 移除 下载量显示
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.1.3) stable; urgency=medium
|
||||
|
||||
* Now uses aria2 to download softwares form all mirrors
|
||||
* 新增:ssinstall现在会在没有apt-fast的时候自动安装
|
||||
* 新增:ss-apt-fast现在会在没有apt-fast的时候自动安装
|
||||
* 修改:删除ssinstall中无用的 || dpkg -P $1
|
||||
* 新增:ss-apt-fast会先下载云上的conf以确保mirror是最新的
|
||||
* 修复:去除wget指令
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Fri, 30 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.1.2) stable; urgency=medium
|
||||
|
||||
* Now let apt-fast method support all mirrors
|
||||
* Now will download dependencies and upgrade with all mirrors
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Mon, 17 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.1.1) stable; urgency=medium
|
||||
|
||||
* Now will delete the link of policy file after uninstall or upgrade
|
||||
* Now ss-update-controler will create symbol link instead of hard link
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Mon, 17 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.1.0) stable; urgency=medium
|
||||
|
||||
* Add pkexec policy: ssinstall. Only will be enabled after permitted.
|
||||
* Modify ssinistall script: Now will ask for password when not run as root
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Mon, 17 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.0.3-13) stable; urgency=medium
|
||||
|
||||
* Update the ssinstall script. Now support apt-fast and will temporarily increase the spark store source priority to 500 to make depends install correctly
|
||||
* Change the style of About Dialog
|
||||
* Modified depends to avoid Deb installers can not handle "Provides"
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Mon, 17 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.0.3-12) stable; urgency=medium
|
||||
|
||||
* Rollback to use DApplication::loadDXcbPlugin() to make titlebar behave normally in ubuntu
|
||||
* Now can run on Debian 11
|
||||
* Now can run on Ubuntu 22.04
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Mon, 17 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.0.3-11) stable; urgency=medium
|
||||
|
||||
* Now support autoupdate
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Mon, 17 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.0.3-10) stable; urgency=medium
|
||||
|
||||
* Now also compile dstore patch
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Mon, 17 Jan 2022 00:00:00 +0800
|
||||
|
||||
|
||||
spark-store (3.0.3-9) stable; urgency=medium
|
||||
|
||||
* Support dpkg-buildpackage
|
||||
|
||||
-- shenmo <shenmo@spark-app.store> Mon, 17 Jan 2022 00:00:00 +0800
|
||||
|
||||
1
debian/compat
vendored
Normal file
1
debian/compat
vendored
Normal file
@@ -0,0 +1 @@
|
||||
11
|
||||
48
debian/control
vendored
Normal file
48
debian/control
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
Source: spark-store
|
||||
Maintainer: shenmo <shenmo@spark-app.store>
|
||||
Section: utils
|
||||
Priority: optional
|
||||
Build-Depends:
|
||||
debhelper (>= 9),
|
||||
pkg-config,
|
||||
qtchooser (>= 55-gc9562a1-1~),
|
||||
libqt5core5a,
|
||||
libqt5gui5,
|
||||
libqt5widgets5,
|
||||
libqt5network5,
|
||||
libqt5concurrent5,
|
||||
libdtkcore-dev(>=5.0),
|
||||
libdtkgui-dev(>=5.0),
|
||||
libdtkwidget-dev(>=5.0),
|
||||
libqt5svg5-dev,
|
||||
qttools5-private-dev,
|
||||
qtwebengine5-dev,
|
||||
qtwayland5,
|
||||
qtwayland5-dev-tools,
|
||||
gcc,
|
||||
g++
|
||||
Standards-Version: 4.0.0
|
||||
Homepage: https://www.spark-app.store/
|
||||
|
||||
Package: spark-store
|
||||
Architecture: any
|
||||
Depends:${shlibs:Depends}, ${misc:Depends},
|
||||
libqt5core5a,
|
||||
libqt5gui5,
|
||||
libqt5widgets5,
|
||||
libqt5network5,
|
||||
libqt5concurrent5,
|
||||
qtwayland5,
|
||||
libdtkcore5,
|
||||
libdtkgui5,
|
||||
libdtkwidget5,
|
||||
curl,
|
||||
openssl,
|
||||
dde-qt5integration,
|
||||
aria2,
|
||||
gcc,
|
||||
zenity,
|
||||
libc6-dev,
|
||||
policykit-1
|
||||
Description: Spark Store
|
||||
A community powered app store, based on DTK.
|
||||
22
debian/copyright
vendored
Normal file
22
debian/copyright
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: spark-store
|
||||
Source: https://gitee.com/deepin-community-store/spark-store
|
||||
|
||||
Files: *
|
||||
Copyright: The Spark Project Developers
|
||||
|
||||
License: GPL-3+
|
||||
This package is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
.
|
||||
This package is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
.
|
||||
On Debian systems, the complete text of the GNU General
|
||||
36
debian/rules
vendored
Executable file
36
debian/rules
vendored
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
export QT_SELECT = qt5
|
||||
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||
include /usr/share/dpkg/default.mk
|
||||
|
||||
DEB_BUILD_ARCH ?= $(shell dpkg-architecture -qDEB_BUILD_ARCH)
|
||||
DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE = 1
|
||||
|
||||
%:
|
||||
dh $@ --parallel
|
||||
|
||||
override_dh_auto_clean:
|
||||
rm -rf $(CURDIR)/build
|
||||
|
||||
override_dh_auto_configure:
|
||||
mkdir -p $(CURDIR)/build
|
||||
|
||||
qmake BUILD_VERSION=$(DEB_VERSION_UPSTREAM) spark-store-project.pro \
|
||||
-spec linux-g++ CONFIG+=qtquickcompiler \
|
||||
-o $(CURDIR)/build/
|
||||
|
||||
override_dh_auto_build:
|
||||
make MAKEFLAGS="$(MAKEFLAGS)" -C $(CURDIR)/build
|
||||
|
||||
override_dh_auto_install:
|
||||
make -C $(CURDIR)/build install \
|
||||
INSTALL_ROOT=$(CURDIR)/debian/spark-store
|
||||
|
||||
# Ignore the dpkg-shlibdeps: warning (it uses none of the library's symbols)
|
||||
# Qt Mutidedia lib will ref to network libraray.
|
||||
override_dh_shlibdeps:
|
||||
dh_shlibdeps --dpkg-shlibdeps-params=--warnings=0
|
||||
1
debian/source/format
vendored
Normal file
1
debian/source/format
vendored
Normal file
@@ -0,0 +1 @@
|
||||
1.0
|
||||
84
debian/spark-store.postinst
vendored
Executable file
84
debian/spark-store.postinst
vendored
Executable file
@@ -0,0 +1,84 @@
|
||||
#!/bin/bash
|
||||
|
||||
case "$1" in
|
||||
configure)
|
||||
|
||||
case `arch` in
|
||||
x86_64)
|
||||
echo "Enabling i386 arch..."
|
||||
dpkg --add-architecture i386
|
||||
;;
|
||||
*)
|
||||
echo "Not amd64, skip enable i386 arch"
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
mkdir -p /var/lib/aptss/lists
|
||||
|
||||
|
||||
# Remove the sources.list file
|
||||
rm -f /etc/apt/sources.list.d/sparkstore.list
|
||||
|
||||
# Check if /usr/local/bin existed
|
||||
mkdir -p /usr/local/bin
|
||||
|
||||
# Create symbol links for binary files
|
||||
ln -s -f /opt/durapps/spark-store/bin/spark-store /usr/local/bin/spark-store
|
||||
ln -s -f /opt/durapps/spark-store/bin/ssinstall /usr/local/bin/ssinstall
|
||||
ln -s -f /opt/durapps/spark-store/bin/ssaudit /usr/local/bin/ssaudit
|
||||
ln -s -f /opt/durapps/spark-store/bin/spark-dstore-patch /usr/local/bin/spark-dstore-patch
|
||||
ln -s -f /opt/durapps/spark-store/bin/aptss /usr/local/bin/ss-apt-fast
|
||||
|
||||
ln -s -f /opt/durapps/spark-store/bin/aptss /usr/bin/aptss
|
||||
|
||||
# Create symbol links for SSINSTALL
|
||||
ln -s -f /opt/durapps/spark-store/bin/auto-install-policy/store.spark-app.ssinstall.policy /usr/share/polkit-1/actions/store.spark-app.ssinstall.policy
|
||||
|
||||
# Compile sender module
|
||||
echo "Compiling the Sender module..."
|
||||
gcc -Wformat -Wformat-security -Werror=format-security /opt/durapps/spark-store/bin/ss-feedback/sender-d_$(arch).sh.c -o /opt/durapps/spark-store/bin/ss-feedback/sender-d
|
||||
|
||||
# Install key
|
||||
mkdir -p /tmp/spark-store-install/
|
||||
cp -f /opt/durapps/spark-store/bin/spark-store.asc /tmp/spark-store-install/spark-store.asc
|
||||
gpg --dearmor /tmp/spark-store-install/spark-store.asc
|
||||
cp -f /tmp/spark-store-install/spark-store.asc.gpg /etc/apt/trusted.gpg.d/spark-store.gpg
|
||||
|
||||
# Run apt update to avoid users being fucked up by the non-exist dependency problem
|
||||
# Now abandoned as aptss now run ssupdate everytime
|
||||
#aptss ssupdate
|
||||
|
||||
# Start upgrade detect service
|
||||
systemctl enable spark-update-notifier
|
||||
systemctl start spark-update-notifier
|
||||
|
||||
# Update certain caches
|
||||
update-icon-caches /usr/share/icons/hicolor || true
|
||||
update-desktop-database /usr/share/applications || true
|
||||
xdg-mime default spark-store.desktop x-scheme-handler/spk
|
||||
update-mime-database /usr/share/mime || true
|
||||
|
||||
# Send email for statistics
|
||||
#/tmp/spark-store-install/feedback.sh
|
||||
|
||||
# Remove temp dir
|
||||
rm -rf /tmp/spark-store-install
|
||||
;;
|
||||
|
||||
triggered)
|
||||
# Quit if deepin-app-store-tool existed
|
||||
if [ -x "/usr/bin/deepin-app-store-tool" ] ; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Trigger for UOS debs installation
|
||||
echo '--------检测到Uniontech标准软件包,运行补丁以修正安装--------'
|
||||
if [ -x "/usr/local/bin/spark-dstore-patch" ] ; then
|
||||
/usr/local/bin/spark-dstore-patch
|
||||
echo '-----------spark-dstore-patch补丁工具已运行完毕-----------'
|
||||
else
|
||||
echo '------------spark-dstore-patch补丁工具运行失败------------'
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
6
debian/spark-store.postrm
vendored
Normal file
6
debian/spark-store.postrm
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Update certain caches
|
||||
update-icon-caches /usr/share/icons/hicolor || true
|
||||
update-desktop-database /usr/share/applications || true
|
||||
update-mime-database /usr/share/mime || true
|
||||
28
debian/spark-store.preinst
vendored
Executable file
28
debian/spark-store.preinst
vendored
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
#检测网络链接畅通
|
||||
function network-check()
|
||||
{
|
||||
#超时时间
|
||||
local timeout=15
|
||||
|
||||
#目标网站
|
||||
local target=www.baidu.com
|
||||
|
||||
#获取响应状态码
|
||||
local ret_code=`curl -I -s --connect-timeout ${timeout} ${target} -w %{http_code} | tail -n1`
|
||||
|
||||
if [ "x$ret_code" = "x200" ]; then
|
||||
echo "Network Checked successful ! Continue..."
|
||||
echo "网络通畅,继续安装"
|
||||
else
|
||||
#网络不畅通
|
||||
echo "Network failed ! Cancel the installation"
|
||||
echo "网络不畅,终止安装"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
|
||||
#network-check
|
||||
echo "不再检测网络"
|
||||
52
debian/spark-store.prerm
vendored
Executable file
52
debian/spark-store.prerm
vendored
Executable file
@@ -0,0 +1,52 @@
|
||||
#!/bin/bash
|
||||
function notify-send()
|
||||
{
|
||||
#Detect the user using such display
|
||||
local user=$(who | awk '{print $1}' | head -n 1)
|
||||
|
||||
#Detect the id of the user
|
||||
local uid=$(id -u $user)
|
||||
|
||||
sudo -u $user DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$uid/bus notify-send "$@"
|
||||
}
|
||||
|
||||
if [ "$1" = "remove" ] || [ "$1" = "purge" ] ; then
|
||||
# Remove residual symbol links
|
||||
rm -f /usr/local/bin/spark-store
|
||||
rm -f /usr/local/bin/ssinstall
|
||||
rm -f /usr/local/bin/ssaudit
|
||||
rm -f /usr/local/bin/spark-dstore-patch
|
||||
rm -f /usr/local/bin/ss-apt-fast
|
||||
rm -f /usr/bin/aptss
|
||||
|
||||
rm -rf /etc/aptss/
|
||||
rm -rf /var/lib/aptss/
|
||||
|
||||
# Remove Sender module
|
||||
rm -f /opt/durapps/spark-store/bin/ss-feedback/sender-d
|
||||
|
||||
# Remove residual symbol links to stop upgrade detect
|
||||
rm -f /etc/xdg/autostart/spark-update-notifier.desktop
|
||||
|
||||
# Shutdown services
|
||||
systemctl stop spark-update-notifier
|
||||
# Stop update detect service
|
||||
systemctl disable spark-update-notifier
|
||||
|
||||
# Clean the auto install polkit file if exist
|
||||
rm -f /usr/share/polkit-1/actions/store.spark-app.ssinstall.policy
|
||||
|
||||
# Remove gpg key file
|
||||
rm -f /etc/apt/trusted.gpg.d/spark-store.gpg
|
||||
apt-key del '9D9A A859 F750 24B1 A1EC E16E 0E41 D354 A29A 440C'
|
||||
else
|
||||
echo "非卸载操作,不进行配置清理"
|
||||
|
||||
if [ ! -z "`pidof spark-store`" ];then
|
||||
echo "关闭已有 spark-store.."
|
||||
notify-send "正在升级星火商店" "请在升级结束后重启星火商店" -i spark-store
|
||||
killall spark-store
|
||||
else
|
||||
echo "继续安装 spark-store.."
|
||||
fi
|
||||
fi
|
||||
1
debian/spark-store.triggers
vendored
Normal file
1
debian/spark-store.triggers
vendored
Normal file
@@ -0,0 +1 @@
|
||||
interest-noawait /opt/apps
|
||||
@@ -1,52 +0,0 @@
|
||||
# 项目结构和命名规范
|
||||
|
||||
## 文件夹结构
|
||||
|
||||
### cmake
|
||||
|
||||
主要用于 CMake 配置时需要用到的 CMake 模块脚本。
|
||||
|
||||
### gui
|
||||
|
||||
主要用于显示界面的 C++ 代码文件(即包含 Qt Widgets 代码),无论包含多少与其他组件的联系,都在这个目录内。
|
||||
这包括 SpkUi 的自定义界面组件、商店主界面自身的 Page 类等等。
|
||||
|
||||
### inc
|
||||
|
||||
项目中所有以 `#include "xxx.h"` 方式包含到代码中的标头文件,全部放入此目录。
|
||||
标头文件并不强求目录结构明确,文件用途或来源特殊的除外。
|
||||
|
||||
### src
|
||||
|
||||
商店主体逻辑。包含基础的 `SpkStore` 类、`main.cpp` 等核心逻辑。
|
||||
新加入的逻辑如单个功能多于一个cpp文件,则必须分装到一个目录内。
|
||||
|
||||
### plugin
|
||||
|
||||
适配 Deepin 以及其他平台的平台相关插件。
|
||||
|
||||
## 命名规范
|
||||
|
||||
### 通用规范
|
||||
|
||||
类名、成员、方法名一律采用大驼峰形式。例如,`SpkTitleBar::SetTitle` 方法。
|
||||
C++ 规范要求的和第三方库有较大差异的除外。例如,`SpkUiMessage::_notify`成员。
|
||||
临时变量采用小驼峰形式或全小写。
|
||||
|
||||
名称要对功能要有基础的描述,例如,`SpkUi::SpkCategorySelector` 类。抽象核心逻辑除外。
|
||||
|
||||
### 类名
|
||||
|
||||
如非第三方代码,一般以 `Spk` 前缀标明。
|
||||
实现 UI 的类都应归于 `SpkUi` 命名空间。
|
||||
|
||||
## 类定义
|
||||
|
||||
### 一般规则
|
||||
|
||||
Qt 类的 `Q_OBJECT` 应置于类定义最顶端。
|
||||
`public` ,`protected` 和 `private` 等标签中只应该包含一类成员,
|
||||
如单个 `public` 标签内只能包含方法,或成员。
|
||||
信号、槽等不得与普通方法混合。
|
||||
|
||||
<!--TODO-->
|
||||
@@ -1,6 +0,0 @@
|
||||
|
||||
# 翻译
|
||||
|
||||
由于CMake和Qt的稀烂集成,我们不能使用CMake自动lupdate更新翻译。
|
||||
|
||||
如果需要更新翻译,请使用`make run_lupdate`目标进行。qm文件的编译无需其他操作,只需build即可。
|
||||
@@ -1,314 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
#include "page/spkpageappdetails.h"
|
||||
#include "spkutils.h"
|
||||
#include "spkappitem.h"
|
||||
|
||||
namespace SpkUi
|
||||
{
|
||||
constexpr QSize SpkPageAppDetails::IconSize;
|
||||
|
||||
void SpkPageAppDetails::LoadAppResources(QString aPkgName, QString aIcon, QStringList aScreenshots,
|
||||
QStringList aTags)
|
||||
{
|
||||
QPixmap pic;
|
||||
|
||||
// Load icon
|
||||
auto res = RES->RequestResource(0, aPkgName, SpkResource::ResourceType::AppIcon, aIcon);
|
||||
if(res.status == SpkResource::ResourceStatus::Ready)
|
||||
{
|
||||
if(pic.loadFromData(res.data))
|
||||
mAppIcon->setPixmap(pic.scaled(IconSize,
|
||||
Qt::IgnoreAspectRatio,
|
||||
Qt::SmoothTransformation));
|
||||
else
|
||||
{
|
||||
mAppIcon->setPixmap(mBrokenImg);
|
||||
RES->PurgeCachedResource(aPkgName, SpkResource::ResourceType::AppIcon, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Load screenshots. Screenshots have id starting with 1.
|
||||
if(aScreenshots.isEmpty())
|
||||
return;
|
||||
else
|
||||
{
|
||||
auto count = aScreenshots.size();
|
||||
mImgViewer->SetImageTotal(count);
|
||||
if(count > mScreenshotPreviews.size())
|
||||
{
|
||||
auto from = mScreenshotPreviews.size(), to = count - mScreenshotPreviews.size();
|
||||
for(int i = 0; i <= to; i++)
|
||||
{
|
||||
auto wid = new SpkClickLabel;
|
||||
wid->setProperty("shotId", from + i + 1);
|
||||
wid->setFixedHeight(200);
|
||||
wid->setCursor(Qt::PointingHandCursor);
|
||||
connect(wid, &SpkClickLabel::Pressed, this, &SpkPageAppDetails::ImageClicked);
|
||||
mScreenshotPreviews.append(wid);
|
||||
mScreenshotLay->addWidget(wid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int shotId = 0;
|
||||
for(auto &i : aScreenshots)
|
||||
{
|
||||
shotId++;
|
||||
res = RES->RequestResource(shotId, aPkgName, SpkResource::ResourceType::AppScreenshot, i,
|
||||
shotId);
|
||||
auto preview = mScreenshotPreviews[shotId - 1];
|
||||
preview->setVisible(true);
|
||||
if(res.status == SpkResource::ResourceStatus::Ready)
|
||||
{
|
||||
if(pic.loadFromData(res.data))
|
||||
{
|
||||
mAppImages[shotId] = pic;
|
||||
mImgViewer->SetPixmap(shotId, &mAppImages[shotId]);
|
||||
preview->setPixmap(pic.scaledToHeight(200, Qt::SmoothTransformation));
|
||||
}
|
||||
else
|
||||
{
|
||||
mAppImages[shotId] = mBrokenImg;
|
||||
RES->PurgeCachedResource(aPkgName, SpkResource::ResourceType::AppScreenshot, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
preview->setPixmap(mIconLoading);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: tags
|
||||
}
|
||||
|
||||
void SpkPageAppDetails::SetWebsiteLink(QString url)
|
||||
{
|
||||
mWebsite->setText(QString("<a href=\"%1\">%2</a>").arg(url, tr("Website link")));
|
||||
}
|
||||
|
||||
void SpkPageAppDetails::SetPackagePath(QString url)
|
||||
{
|
||||
mPkgPath = url;
|
||||
}
|
||||
|
||||
SpkPageAppDetails::SpkPageAppDetails(QWidget *parent) : SpkPageBase(parent),
|
||||
mBrokenImg(QIcon(":/icons/broken-icon.svg").pixmap(SpkAppItem::IconSize_)),
|
||||
mIconLoading(QIcon(":/icons/loading-icon.svg").pixmap(SpkAppItem::IconSize_))
|
||||
{
|
||||
mMainArea = new QScrollArea;
|
||||
mMainArea->setWidgetResizable(true);
|
||||
mMainArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
|
||||
mMainLay = new QVBoxLayout(this);
|
||||
mMainLay->addWidget(mMainArea);
|
||||
|
||||
mBottomBar = new QWidget;
|
||||
mMainLay->addWidget(mBottomBar);
|
||||
|
||||
mDetailsLay = new QVBoxLayout(mMainArea);
|
||||
mDetailsLay->setSizeConstraint(QLayout::SetMinAndMaxSize);
|
||||
|
||||
mAppIcon = new QLabel;
|
||||
|
||||
mAppTitle = new QLabel;
|
||||
mAppTitle->setObjectName("styDetTitle");
|
||||
mAppTitle->setWordWrap(true);
|
||||
|
||||
mAppDescription = new QLabel;
|
||||
mAppDescription->setObjectName("styDetDesc");
|
||||
mAppDescription->setWordWrap(true);
|
||||
mAppShortDesc = new QLabel;
|
||||
mAppShortDesc->setObjectName("styDetDesc");
|
||||
mAppShortDesc->setWordWrap(true);
|
||||
// NOTE: Seems Qt have trouble dealing with wrapped text here. Removing the following operations
|
||||
// to mAppShortDesc will result in broken layout. Very possible that it's a Qt bug.
|
||||
mAppShortDesc->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
|
||||
mAppShortDesc->setMinimumWidth(100);
|
||||
mVersion = new QLabel;
|
||||
mVersion->setWordWrap(true);
|
||||
mWebsite = new QLabel;
|
||||
mPkgName = new QLabel;
|
||||
mPkgName->setObjectName("styDetPkg");
|
||||
mPkgName->setWordWrap(true);
|
||||
|
||||
mTitleLay = new QVBoxLayout;
|
||||
mTitleLay->setAlignment(Qt::AlignTop);
|
||||
mTitleLay->addWidget(mAppTitle);
|
||||
mTitleLay->addWidget(mVersion);
|
||||
mTitleLay->addWidget(mAppShortDesc);
|
||||
mTitleLay->addWidget(mPkgName);
|
||||
mTitleLay->addWidget(mWebsite);
|
||||
mTitleLay->setSpacing(0);
|
||||
|
||||
mIconTitleLay = new QHBoxLayout;
|
||||
mIconTitleLay->setAlignment(Qt::AlignLeft);
|
||||
mIconTitleLay->addWidget(mAppIcon);
|
||||
mIconTitleLay->addSpacing(15);
|
||||
mIconTitleLay->addLayout(mTitleLay);
|
||||
|
||||
mIconTitleWidget = new QWidget;
|
||||
mIconTitleWidget->setLayout(mIconTitleLay);
|
||||
|
||||
mAuthor = new SpkDetailEntry;
|
||||
mAuthor->SetTitle(tr("Author"));
|
||||
mContributor = new SpkDetailEntry;
|
||||
mContributor->SetTitle(tr("Contributor"));
|
||||
// mSite = new SpkDetailEntry;
|
||||
// mSite->SetTitle(tr("Website"));
|
||||
mArch = new SpkDetailEntry;
|
||||
mArch->SetTitle(tr("Architecture"));
|
||||
mSize = new SpkDetailEntry;
|
||||
mSize->SetTitle(tr("Size"));
|
||||
|
||||
mDetailLay = new SpkStretchLayout;
|
||||
mDetailLay->setSpacing(12);
|
||||
mDetailLay->addWidget(mAuthor);
|
||||
mDetailLay->addWidget(mContributor);
|
||||
mDetailLay->addWidget(mSize);
|
||||
mDetailLay->addWidget(mArch);
|
||||
// mDetailLay->addWidget(mSite);
|
||||
|
||||
// mDetailWidget = new QWidget;
|
||||
// mDetailWidget->setLayout(mDetailLay);
|
||||
// mDetailWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
|
||||
|
||||
mDetailsLay->setAlignment(Qt::AlignTop);
|
||||
mDetailsLay->addWidget(mIconTitleWidget);
|
||||
mDetailsLay->addLayout(mDetailLay);
|
||||
mDetailsLay->addWidget(mAppDescription);
|
||||
// mMainLay->addStretch();
|
||||
|
||||
mScreenshotLay = new QHBoxLayout;
|
||||
mScreenshotArea = new QScrollArea;
|
||||
mWid4ShotArea = new QWidget;
|
||||
mWid4ShotArea->setLayout(mScreenshotLay);
|
||||
mScreenshotArea->setWidget(mWid4ShotArea);
|
||||
mScreenshotArea->setWidgetResizable(true);
|
||||
mScreenshotArea->setFixedHeight(230);
|
||||
mScreenshotArea->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
|
||||
|
||||
mDetailsLay->addWidget(mScreenshotArea);
|
||||
|
||||
mWid4MainArea = new QWidget;
|
||||
mWid4MainArea->setLayout(mDetailsLay);
|
||||
|
||||
mMainArea->setWidget(mWid4MainArea);
|
||||
|
||||
mWebsite->setTextFormat(Qt::RichText);
|
||||
mWebsite->setOpenExternalLinks(true);
|
||||
|
||||
// Bottom bar buttons
|
||||
mBottomBarLay = new QHBoxLayout;
|
||||
mBottomBar->setLayout(mBottomBarLay);
|
||||
|
||||
mBtnDownload = new QPushButton;
|
||||
mBtnDownload->setText(tr("Download"));
|
||||
|
||||
// mBtnInstall = new QPushButton;
|
||||
// mBtnInstall->setText(tr("Install"));
|
||||
|
||||
mBtnUninstall = new QPushButton;
|
||||
mBtnUninstall->setText(tr("Uninstall"));
|
||||
|
||||
mBtnRequestUpdate = new QPushButton;
|
||||
mBtnRequestUpdate->setText(tr("Request Update"));
|
||||
|
||||
mBtnReport = new QPushButton;
|
||||
mBtnReport->setText(tr("Report"));
|
||||
|
||||
mBottomBarLay->addStretch();
|
||||
mBottomBarLay->addWidget(mBtnDownload);
|
||||
// mBottomBarLay->addWidget(mBtnInstall);
|
||||
mBottomBarLay->addWidget(mBtnUninstall);
|
||||
mBottomBarLay->addWidget(mBtnRequestUpdate);
|
||||
mBottomBarLay->addWidget(mBtnReport);
|
||||
|
||||
mImgViewer = new SpkImgViewer;
|
||||
mImgViewer->setVisible(false);
|
||||
|
||||
connect(mBtnDownload, &QPushButton::clicked,
|
||||
[=](){ emit RequestDownload(mAppTitle->text(), mPkgName->text(),
|
||||
"/store/reading/youdao-dict/youdao-dict_6.0.0-0~ubuntu_amd64.deb");
|
||||
});
|
||||
}
|
||||
|
||||
SpkPageAppDetails::~SpkPageAppDetails()
|
||||
{
|
||||
delete mImgViewer;
|
||||
}
|
||||
|
||||
void SpkPageAppDetails::ResourceAcquisitionFinished(int id, ResourceResult result)
|
||||
{
|
||||
QPixmap img;
|
||||
// qDebug() << "PageAppDetails: Resource" << id << "acquired";
|
||||
if(!id)
|
||||
{
|
||||
// id == 0, icon
|
||||
if(result.status == SpkResource::ResourceStatus::Ready)
|
||||
{
|
||||
if(img.loadFromData(result.data))
|
||||
mAppIcon->setPixmap(img.scaled(SpkAppItem::IconSize_,
|
||||
Qt::IgnoreAspectRatio,
|
||||
Qt::SmoothTransformation));
|
||||
else
|
||||
mAppIcon->setPixmap(mBrokenImg);
|
||||
}
|
||||
else if(result.status == SpkResource::ResourceStatus::Failed)
|
||||
{
|
||||
mAppIcon->setPixmap(mBrokenImg);
|
||||
RES->PurgeCachedResource(mPkgName->text(), SpkResource::ResourceType::AppIcon, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto preview = mScreenshotPreviews[id - 1];
|
||||
preview->setVisible(true);
|
||||
if(result.status == SpkResource::ResourceStatus::Ready)
|
||||
{
|
||||
if(img.loadFromData(result.data))
|
||||
{
|
||||
mAppImages[id] = img;
|
||||
mImgViewer->SetPixmap(id, &mAppImages[id]);
|
||||
mScreenshotPreviews[id - 1]->setPixmap(img.scaledToHeight(200, Qt::SmoothTransformation));
|
||||
}
|
||||
else
|
||||
{
|
||||
mImgViewer->SetPixmap(id, &mBrokenImg);
|
||||
mScreenshotPreviews[id - 1]->setPixmap(mBrokenImg);
|
||||
}
|
||||
}
|
||||
else if(result.status == SpkResource::ResourceStatus::Failed)
|
||||
{
|
||||
mImgViewer->SetPixmap(id, &mBrokenImg);
|
||||
mScreenshotPreviews[id - 1]->setPixmap(mBrokenImg);
|
||||
RES->PurgeCachedResource(mPkgName->text(), SpkResource::ResourceType::AppIcon, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpkPageAppDetails::Activated()
|
||||
{
|
||||
RES->Acquire(this, false);
|
||||
for(auto &i : mScreenshotPreviews)
|
||||
i->setVisible(false);
|
||||
mImgViewer->Clear();
|
||||
}
|
||||
|
||||
void SpkPageAppDetails::ImageClicked()
|
||||
{
|
||||
mImgViewer->ShowWithImage(sender()->property("shotId").toInt());
|
||||
}
|
||||
|
||||
SpkDetailEntry::SpkDetailEntry(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
setLayout(&mLay);
|
||||
mLay.addWidget(&mTitle);
|
||||
mLay.addWidget(&mField);
|
||||
mTitle.setAlignment(Qt::AlignLeft);
|
||||
mField.setAlignment(Qt::AlignRight);
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
setMinimumWidth(300);
|
||||
setAutoFillBackground(true);
|
||||
}
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
|
||||
#include "page/spkpageapplist.h"
|
||||
#include "spkutils.h"
|
||||
#include "spkuimsg.h"
|
||||
|
||||
namespace SpkUi
|
||||
{
|
||||
SpkPageAppList::SpkPageAppList(QWidget *parent) : SpkPageBase(parent)
|
||||
{
|
||||
mLoadingIcon = new QPixmap(QIcon(":/icons/loading-icon.svg").pixmap(SpkAppItem::IconSize_));
|
||||
mBrokenIcon = new QPixmap(QIcon(":/icons/broken-icon.svg").pixmap(SpkAppItem::IconSize_));
|
||||
|
||||
mAppsWidget = new QWidget;
|
||||
mAppsArea = new QScrollArea(this);
|
||||
mMainLay = new QVBoxLayout(this);
|
||||
mItemLay = new SpkStretchLayout(mAppsWidget);
|
||||
|
||||
mPageSwitchWidget = new QWidget;
|
||||
mPageSwitchLay = new QHBoxLayout(mPageSwitchWidget);
|
||||
mBtnPgUp = new QPushButton;
|
||||
mBtnPgDown = new QPushButton;
|
||||
mBtnGotoPage = new QPushButton;
|
||||
mPageInput = new QLineEdit;
|
||||
mPageValidator = new QIntValidator(mPageInput);
|
||||
mPageIndicator = new QLabel;
|
||||
|
||||
mPageValidator->setRange(1, 99);
|
||||
mPageInput->setFixedWidth(50);
|
||||
mPageInput->setValidator(mPageValidator);
|
||||
mBtnGotoPage->setText(tr("Goto"));
|
||||
mBtnPgUp->setText(tr("Previous"));
|
||||
mBtnPgDown->setText(tr("Next"));
|
||||
mBtnGotoPage->setFocusPolicy(Qt::NoFocus);
|
||||
mBtnPgDown->setFocusPolicy(Qt::NoFocus);
|
||||
mBtnPgUp->setFocusPolicy(Qt::NoFocus);
|
||||
|
||||
mPageSwitchLay->addWidget(mPageIndicator);
|
||||
mPageSwitchLay->addStretch();
|
||||
mPageSwitchLay->addWidget(mPageInput);
|
||||
mPageSwitchLay->addWidget(mBtnGotoPage);
|
||||
mPageSwitchLay->addWidget(mBtnPgUp);
|
||||
mPageSwitchLay->addWidget(mBtnPgDown);
|
||||
|
||||
mAppsArea->setWidget(mAppsWidget);
|
||||
mAppsArea->setWidgetResizable(true);
|
||||
|
||||
mMainLay->addWidget(mAppsArea);
|
||||
mMainLay->addWidget(mPageSwitchWidget);
|
||||
setLayout(mMainLay);
|
||||
|
||||
connect(mBtnPgUp, &QPushButton::clicked, this, &SpkPageAppList::PageUp);
|
||||
connect(mBtnPgDown, &QPushButton::clicked, this, &SpkPageAppList::PageDown);
|
||||
connect(mBtnGotoPage, &QPushButton::clicked, this, &SpkPageAppList::GotoPage);
|
||||
}
|
||||
|
||||
void SpkPageAppList::AddApplicationEntry(QString name, QString pkgName, QString description,
|
||||
QString iconUrl, int appId)
|
||||
{
|
||||
auto item = new SpkAppItem(appId, this);
|
||||
auto id = mAppItemList.size();
|
||||
|
||||
connect(item, &SpkAppItem::clicked, this, &SpkPageAppList::ApplicationClicked);
|
||||
item->SetTitle(name);
|
||||
item->SetDescription(description);
|
||||
item->setProperty("pkg_name", pkgName);
|
||||
|
||||
auto iconRes = RES->RequestResource(id, pkgName, SpkResource::ResourceType::AppIcon,
|
||||
iconUrl, 0);
|
||||
QPixmap icon;
|
||||
if(iconRes.status == SpkResource::ResourceStatus::Ready)
|
||||
{
|
||||
if(icon.loadFromData(iconRes.data))
|
||||
item->SetIcon(icon.scaled(SpkAppItem::IconSize_,
|
||||
Qt::IgnoreAspectRatio,
|
||||
Qt::SmoothTransformation));
|
||||
else
|
||||
{
|
||||
item->SetIcon(*mBrokenIcon);
|
||||
RES->PurgeCachedResource(pkgName, SpkResource::ResourceType::AppIcon, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
item->SetIcon(*mLoadingIcon);
|
||||
|
||||
mAppItemList.append(item);
|
||||
mItemLay->addWidget(item);
|
||||
}
|
||||
|
||||
void SpkPageAppList::ClearAll()
|
||||
{
|
||||
QWidget *itm;
|
||||
QLayoutItem *layitm;
|
||||
while((layitm = mItemLay->takeAt(0)))
|
||||
{
|
||||
itm = layitm->widget();
|
||||
itm->hide();
|
||||
itm->deleteLater();
|
||||
}
|
||||
mAppItemList.clear();
|
||||
mAppsArea->verticalScrollBar()->setValue(0);
|
||||
}
|
||||
|
||||
void SpkPageAppList::ResourceAcquisitionFinished(int id, ResourceResult result)
|
||||
{
|
||||
QPixmap icon;
|
||||
// qDebug() << "PageAppList: Resource" << id << "acquired";
|
||||
auto item = mAppItemList[id];
|
||||
if(result.status == SpkResource::ResourceStatus::Ready)
|
||||
{
|
||||
if(icon.loadFromData(result.data))
|
||||
item->SetIcon(icon.scaled(SpkAppItem::IconSize_,
|
||||
Qt::IgnoreAspectRatio,
|
||||
Qt::SmoothTransformation));
|
||||
else
|
||||
item->SetIcon(*mBrokenIcon);
|
||||
}
|
||||
else if(result.status == SpkResource::ResourceStatus::Failed)
|
||||
{
|
||||
item->SetIcon(*mBrokenIcon);
|
||||
RES->PurgeCachedResource(item->property("pkg_name").toString(),
|
||||
SpkResource::ResourceType::AppIcon, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void SpkPageAppList::SetPageStatus(int total, int current, int itemCount, QString &keyword)
|
||||
{
|
||||
mCurrentPage = current;
|
||||
mKeyword = keyword;
|
||||
mPageIndicator->setText(tr("Page %1 / %2, %3 apps in total")
|
||||
.arg(current).arg(total).arg(itemCount));
|
||||
mBtnPgUp->setDisabled(current == 1);
|
||||
mBtnPgDown->setDisabled(total == current || total == 1);
|
||||
mBtnGotoPage->setDisabled(total == 1);
|
||||
mPageValidator->setTop(total);
|
||||
}
|
||||
|
||||
void SpkPageAppList::DisablePageSwitchers()
|
||||
{
|
||||
mBtnPgDown->setDisabled(true);
|
||||
mBtnPgUp->setDisabled(true);
|
||||
mBtnGotoPage->setDisabled(true);
|
||||
}
|
||||
|
||||
void SpkPageAppList::PageUp()
|
||||
{
|
||||
DisablePageSwitchers();
|
||||
if(mKeyword.isEmpty())
|
||||
emit SwitchListPage(mCategoryId, mCurrentPage - 1);
|
||||
else
|
||||
emit SwitchSearchPage(mKeyword, mCurrentPage - 1);
|
||||
}
|
||||
|
||||
void SpkPageAppList::PageDown()
|
||||
{
|
||||
DisablePageSwitchers();
|
||||
if(mKeyword.isEmpty())
|
||||
emit SwitchListPage(mCategoryId, mCurrentPage + 1);
|
||||
else
|
||||
emit SwitchSearchPage(mKeyword, mCurrentPage + 1);
|
||||
}
|
||||
|
||||
void SpkPageAppList::GotoPage()
|
||||
{
|
||||
if(mPageInput->text().isEmpty())
|
||||
return SpkUiMessage::SendStoreNotification(tr("Please enter page number to go to!"));
|
||||
int page = mPageInput->text().toInt();
|
||||
if(page > mPageValidator->top())
|
||||
return SpkUiMessage::SendStoreNotification(tr("Page %1 is not a valid page number!")
|
||||
.arg(page));
|
||||
DisablePageSwitchers();
|
||||
if(mKeyword.isEmpty())
|
||||
emit SwitchListPage(mCategoryId, page);
|
||||
else
|
||||
emit SwitchSearchPage(mKeyword, page);
|
||||
}
|
||||
|
||||
void SpkPageAppList::Activated()
|
||||
{
|
||||
RES->Acquire(this, false);
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
|
||||
#include "page/spkpagebase.h"
|
||||
|
||||
/*
|
||||
* Documentation on
|
||||
* How to Add a New Page to Main Window Side Bar
|
||||
*
|
||||
* 1. Derive your page widget class from SpkPageBase (reference implementation
|
||||
* in SpkPageSettings) and add them to CMakeLists
|
||||
*
|
||||
* 2. Add the ID for the page in enum SpkUi::SpkStackedPages (in spkmainwindow.h)
|
||||
* and add it as a resource context if needed
|
||||
*
|
||||
* 3. Include the page's header file in spkmainwindow.h and add a pointer to it in
|
||||
* SpkUi::SpkMainWidget
|
||||
*
|
||||
* 4. Add a tree item or icon button for the corresponding page inside
|
||||
* SpkUi::SpkMainWidget, and initialize it in SpkUi::SpkMainWidget::SpkMainWidget.
|
||||
* Take references of existing entries, and write similar code close to each other
|
||||
* to make the source look nice. Don't forget to add the item to the UI.
|
||||
*
|
||||
* 5. Make the linkage between the page and the sidebar item at the end of
|
||||
* SpkUi::SpkMainWidget::SpkMainWidget().
|
||||
*
|
||||
*/
|
||||
|
||||
SpkPageBase::SpkPageBase(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SpkPageBase::ResourceAcquisitionFinished(int id, ResourceResult result)
|
||||
{
|
||||
Q_UNUSED(id);
|
||||
Q_UNUSED(result);
|
||||
}
|
||||
|
||||
void SpkPageBase::Activated()
|
||||
{
|
||||
; // Do nothing
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
|
||||
|
||||
#include "page/spkpagedownloads.h"
|
||||
#include "pkgs/spkpkgmgrbase.h"
|
||||
#include "spkuimsg.h"
|
||||
#include "spkutils.h"
|
||||
|
||||
SpkUi::SpkPageDownloads::SpkPageDownloads(QWidget *parent) :
|
||||
SpkPageBase(parent)
|
||||
{
|
||||
mMainLay = new QVBoxLayout(this);
|
||||
mLayEntries = new QVBoxLayout;
|
||||
mScrollWidget = new QWidget;
|
||||
mScrollArea = new QScrollArea(this);
|
||||
|
||||
mLayEntries->setAlignment(Qt::AlignTop);
|
||||
mScrollWidget->setLayout(mLayEntries);
|
||||
mScrollArea->setWidget(mScrollWidget);
|
||||
mScrollArea->setWidgetResizable(true);
|
||||
mMainLay->addWidget(mScrollArea);
|
||||
setLayout(mMainLay);
|
||||
|
||||
mDownloadMgr = new SpkDownloadMgr(this);
|
||||
connect(mDownloadMgr, &SpkDownloadMgr::DownloadProgressed,
|
||||
this, &SpkPageDownloads::DownloadProgress);
|
||||
|
||||
mNextDownloadId = 0;
|
||||
mCurrentStatus = Idle;
|
||||
|
||||
connect(mDownloadMgr, &SpkDownloadMgr::DownloadStopped,
|
||||
this, &SpkPageDownloads::DownloadStopped, Qt::QueuedConnection);
|
||||
connect(PKG, &SpkPkgMgrBase::ReportInstallResult,
|
||||
this, &SpkPageDownloads::InstallationEnded);
|
||||
}
|
||||
|
||||
SpkUi::SpkPageDownloads::~SpkPageDownloads()
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void SpkUi::SpkPageDownloads::DownloadProgress(qint64 downloadedBytes, qint64 totalBytes, int id)
|
||||
{
|
||||
if(!totalBytes)
|
||||
return;
|
||||
|
||||
if(mCurrentStatus == Waiting && totalBytes)
|
||||
{
|
||||
mCurrentStatus = Downloading;
|
||||
mEntries[id]->SetTotalBytes(totalBytes);
|
||||
mEntries[id]->SetStatus(SpkDownloadEntry::Downloading);
|
||||
}
|
||||
mEntries[id]->Progress(downloadedBytes);
|
||||
}
|
||||
|
||||
void SpkUi::SpkPageDownloads::AddDownloadTask(QString name, QString pkgName, QString path)
|
||||
{
|
||||
// Add a new download entry into the UI
|
||||
auto entry = new SpkDownloadEntry;
|
||||
auto iconData = RES->CacheLookup(pkgName, SpkResource::ResourceType::AppIcon, 0);
|
||||
auto id = mNextDownloadId;
|
||||
QPixmap icon;
|
||||
if(iconData.status != SpkResource::ResourceStatus::Ready || !icon.loadFromData(iconData.data))
|
||||
icon.load(":/icons/broken-icon.svg");
|
||||
entry->SetBasicInfo(name, icon, mDownloadMgr->GetDestFilePath(path));
|
||||
entry->SetStatus(SpkDownloadEntry::Waiting);
|
||||
entry->setProperty("entryId", id);
|
||||
entry->setProperty("path", path);
|
||||
|
||||
mNextDownloadId++;
|
||||
|
||||
mEntries[id] = entry;
|
||||
mLayEntries->addWidget(entry);
|
||||
|
||||
connect(entry, &SpkDownloadEntry::Action,
|
||||
this, &SpkPageDownloads::EntryAction);
|
||||
|
||||
NewDownloadTask(id, path);
|
||||
}
|
||||
|
||||
void SpkUi::SpkPageDownloads::DownloadStopped(SpkDownloadMgr::TaskResult status, int id)
|
||||
{
|
||||
switch(status)
|
||||
{
|
||||
case SpkDownloadMgr::Success:
|
||||
mEntries[id]->SetStatus(SpkDownloadEntry::ToBeInstalled);
|
||||
break;
|
||||
|
||||
case SpkDownloadMgr::FailCannotCreateFile:
|
||||
mEntries[id]->SetStatus(SpkDownloadEntry::DownloadFailed,
|
||||
tr("Cannot create download file. Download failed."));
|
||||
break;
|
||||
|
||||
case SpkDownloadMgr::FailNoVaibleServer:
|
||||
mEntries[id]->SetStatus(SpkDownloadEntry::DownloadFailed,
|
||||
tr("Connection unstable or server failure. Download failed."));
|
||||
break;
|
||||
|
||||
case SpkDownloadMgr::FailCancel:
|
||||
mEntries[id]->SetStatus(SpkDownloadEntry::DownloadFailed,
|
||||
tr("This download was cancelled."));
|
||||
break;
|
||||
|
||||
case SpkDownloadMgr::Fail:
|
||||
mEntries[id]->SetStatus(SpkDownloadEntry::DownloadFailed,
|
||||
tr("Unknown error. Download failed."));
|
||||
break;
|
||||
}
|
||||
|
||||
if(status == SpkDownloadMgr::Success)
|
||||
SpkUiMessage::SendDesktopNotification(
|
||||
tr("App \"%1\" downloaded, and ready to install.").arg(mEntries[id]->GetTaskName()));
|
||||
else if(status != SpkDownloadMgr::FailCancel)
|
||||
SpkUiMessage::SendDesktopNotification(
|
||||
tr("Error occurred downloading \"%1\".").arg(mEntries[id]->GetTaskName()));
|
||||
|
||||
|
||||
// Continue next download task
|
||||
if(!mWaitingDownloads.isEmpty())
|
||||
{
|
||||
auto nextTask = mWaitingDownloads.dequeue();
|
||||
auto nextEntry = mEntries[nextTask.first];
|
||||
nextEntry->SetStatus(SpkDownloadEntry::Starting);
|
||||
mDownloadMgr->StartNewDownload(nextTask.second, nextTask.first);
|
||||
mCurrentStatus = Waiting;
|
||||
}
|
||||
else
|
||||
{
|
||||
mCurrentStatus = Idle;
|
||||
}
|
||||
}
|
||||
|
||||
void SpkUi::SpkPageDownloads::EntryAction(SpkDownloadEntry::EntryAction act)
|
||||
{
|
||||
SpkDownloadEntry *entry = static_cast<SpkDownloadEntry*>(sender());
|
||||
auto id = entry->property("entryId").toInt();
|
||||
switch(act)
|
||||
{
|
||||
case SpkDownloadEntry::AbortDownload:
|
||||
mDownloadMgr->CancelCurrentDownload(); // Only one task at a time so simply abort download
|
||||
break;
|
||||
|
||||
case SpkDownloadEntry::RetryDownload:
|
||||
mLayEntries->removeWidget(entry); // Move to list tail
|
||||
mLayEntries->addWidget(entry);
|
||||
NewDownloadTask(id, entry->property("path").toString());
|
||||
entry->SetStatus(SpkDownloadEntry::Waiting);
|
||||
break;
|
||||
|
||||
case SpkDownloadEntry::StartInstall:
|
||||
switch(PKG->ExecuteInstallation(entry->GetFilePath(), id))
|
||||
{
|
||||
case SpkPkgMgrBase::Succeeded:
|
||||
entry->SetStatus(SpkDownloadEntry::Installing);
|
||||
break;
|
||||
|
||||
case SpkPkgMgrBase::Failed:
|
||||
entry->SetStatus(SpkDownloadEntry::InstallFailed,
|
||||
tr("Failed to start installation."));
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SpkDownloadEntry::RemoveEntry:
|
||||
mLayEntries->removeWidget(entry);
|
||||
mEntries.remove(id);
|
||||
for(auto i = mWaitingDownloads.begin(); i != mWaitingDownloads.end(); i++)
|
||||
{
|
||||
if(i->first == id)
|
||||
{
|
||||
mWaitingDownloads.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
entry->setVisible(false);
|
||||
entry->deleteLater();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SpkUi::SpkPageDownloads::InstallationEnded(int id,
|
||||
SpkPkgMgrBase::PkgInstallResult result,
|
||||
int exitCode)
|
||||
{
|
||||
if(result == SpkPkgMgrBase::Succeeded)
|
||||
{
|
||||
mEntries[id]->SetStatus(SpkDownloadEntry::Installed);
|
||||
}
|
||||
else
|
||||
{
|
||||
mEntries[id]->SetStatus(SpkDownloadEntry::InstallFailed,
|
||||
tr("Install failed, exit code: %1.").arg(exitCode));
|
||||
}
|
||||
}
|
||||
|
||||
void SpkUi::SpkPageDownloads::NewDownloadTask(int id, QString downloadPath)
|
||||
{
|
||||
if(mCurrentStatus != Idle)
|
||||
mWaitingDownloads.enqueue({ id, downloadPath }); // Queue download task for future
|
||||
else
|
||||
{
|
||||
auto nextEntry = mEntries[id];
|
||||
nextEntry->SetStatus(SpkDownloadEntry::Starting);
|
||||
mCurrentStatus = Waiting;
|
||||
if(!mDownloadMgr->StartNewDownload(downloadPath, id)) // Initiate a download task when idle
|
||||
{
|
||||
// If fails to start then try next one. Emitting this signal causes
|
||||
// SpkPageDownloads::DownloadStopped to be activated and thus tries next item in queue
|
||||
emit mDownloadMgr->DownloadStopped(SpkDownloadMgr::FailNoVaibleServer, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
|
||||
#include <QDesktopServices>
|
||||
|
||||
#include "page/spkpagehome.h"
|
||||
#include "spkabout.h"
|
||||
#include "gitver.h"
|
||||
|
||||
SpkUi::SpkPageHome::SpkPageHome(QWidget *parent) :
|
||||
SpkPageBase(parent)
|
||||
{
|
||||
ui = new Ui::SpkHomepage;
|
||||
ui->setupUi(this);
|
||||
|
||||
SetupUi();
|
||||
}
|
||||
|
||||
void SpkUi::SpkPageHome::LinkActivated(QString s)
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl(s));
|
||||
}
|
||||
|
||||
void SpkUi::SpkPageHome::SetupUi()
|
||||
{
|
||||
ui->lblIcon->setPixmap(QIcon(":/icons/spark-store.svg").pixmap(QSize(128, 128)));
|
||||
|
||||
ui->hlayTitle->setAlignment(Qt::AlignHCenter);
|
||||
|
||||
ui->lblVersion->setText(ui->lblVersion->text().arg(GitVer::DescribeTags()));
|
||||
|
||||
ui->lblNewAnnouncement->setVisible(false);
|
||||
|
||||
// Click event will propagate to the main window and cause the window to move when
|
||||
// mouse enters the zoom & move detection area. Disable mouse event propagation.
|
||||
ui->lblAuthor->setAttribute(Qt::WA_NoMousePropagation, true);
|
||||
|
||||
ui->widReloadCategory->setVisible(false);
|
||||
ui->widReloadCategory->setAttribute(Qt::WA_StyledBackground);
|
||||
ui->lblCategoryErrIcon->setPixmap(QIcon::fromTheme("dialog-error").pixmap(QSize(32, 32)));
|
||||
|
||||
connect(ui->lblAuthor, &QLabel::linkActivated,
|
||||
this, &SpkPageHome::LinkActivated);
|
||||
connect(ui->btnSubmit, &QPushButton::clicked,
|
||||
[&](){ LinkActivated("https://upload.deepinos.org"); });
|
||||
connect(ui->btnFeedback, &QPushButton::clicked,
|
||||
[&](){ LinkActivated("https://www.deepinos.org/t/spark-feedback"); });
|
||||
connect(ui->btnDonation, &QPushButton::clicked,
|
||||
[&](){ LinkActivated("https://spark.deepinos.org.cn/"); });
|
||||
connect(ui->btnAbout, &QPushButton::clicked,
|
||||
[&](){ SpkAbout::Show(); });
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
|
||||
#include <QtConcurrent/QtConcurrentRun>
|
||||
#include <QMutexLocker>
|
||||
#include <QFutureWatcher>
|
||||
#include "spkutils.h"
|
||||
#include "page/spkpagesettings.h"
|
||||
#include "spkmsgbox.h"
|
||||
|
||||
namespace SpkUi
|
||||
{
|
||||
SpkPageSettings::SpkPageSettings(QWidget *parent) :
|
||||
SpkPageBase(parent)
|
||||
{
|
||||
mMainArea = new QScrollArea();
|
||||
mMainLay = new QVBoxLayout(this);
|
||||
mSettingsWidget = new QWidget(this);
|
||||
ui = new Ui::SpkUiSettings;
|
||||
|
||||
ui->setupUi(mSettingsWidget);
|
||||
|
||||
mMainLay->addWidget(mMainArea);
|
||||
|
||||
mMainArea->setWidget(mSettingsWidget);
|
||||
mMainArea->setWidgetResizable(true);
|
||||
|
||||
CFG->BindField("url/repo", &this->mRepoListUrl,
|
||||
"https://d.store.deepinos.org.cn/store/server.list");
|
||||
|
||||
mBytesDownloads = mBytesResource = -1;
|
||||
|
||||
connect(&mFwResourceClean, &QFutureWatcher<void>::finished,
|
||||
this, &SpkPageSettings::CleanedResource);
|
||||
connect(&mFwResourceCount, &QFutureWatcher<void>::finished,
|
||||
this, &SpkPageSettings::CountFinishResource);
|
||||
connect(&mFwDownloadClean, &QFutureWatcher<void>::finished,
|
||||
this, &SpkPageSettings::CleanedDownload);
|
||||
connect(&mFwDownloadCount, &QFutureWatcher<void>::finished,
|
||||
this, &SpkPageSettings::CountFinishDownload);
|
||||
connect(ui->btnViewDownloadedContent, &QPushButton::clicked,
|
||||
this, &SpkPageSettings::on_btnViewDownloadedContent_clicked);
|
||||
connect(ui->btnViewResourceCache, &QPushButton::clicked,
|
||||
this, &SpkPageSettings::on_btnViewResourceCache_clicked);
|
||||
connect(ui->btnCleanDownloadedContent, &QPushButton::clicked,
|
||||
this, &SpkPageSettings::on_btnCleanDownloadedContent_clicked);
|
||||
connect(ui->btnCleanResourceCache, &QPushButton::clicked,
|
||||
this, &SpkPageSettings::on_btnCleanResourceCache_clicked);
|
||||
|
||||
SetupUi();
|
||||
}
|
||||
|
||||
SpkPageSettings::~SpkPageSettings()
|
||||
{
|
||||
delete mSettingsWidget;
|
||||
}
|
||||
|
||||
void SpkPageSettings::SetupUi()
|
||||
{
|
||||
ui->lblSettingsTitle->setObjectName("styConfTitle");
|
||||
ui->lblCleanup->setObjectName("styConfTitle");
|
||||
ui->lblAdvanced->setObjectName("styConfTitle");
|
||||
|
||||
connect(ui->btnSave, &QPushButton::clicked,
|
||||
this, &SpkPageSettings::SaveConfiguration);
|
||||
}
|
||||
|
||||
void SpkPageSettings::ReadConfiguration()
|
||||
{
|
||||
ui->spnConcurrentResDownloads->setValue(CFG->ReadField("resource/concurrent", 5).toInt());
|
||||
ui->edtApiUrl->setText(CFG->ReadField("url/api", "").toString());
|
||||
ui->edtResourceUrl->setText(CFG->ReadField("url/res", "").toString());
|
||||
ui->edtResourceCachePath->setText(CFG->ReadField("dirs/cache", "").toString());
|
||||
ui->edtDownloadPath->setText(CFG->ReadField("dirs/download", "").toString());
|
||||
ui->edtDownloadServers->setPlainText(CFG->ReadField("download/servers", "").toString());
|
||||
ui->edtQssPath->setText(CFG->ReadField("internal/qss_path", "").toString());
|
||||
ui->edtRepoListUrl->setText(CFG->ReadField("url/repo", "").toString());
|
||||
ui->cmbLightDarkTheme->setCurrentIndex(CFG->ReadField("ui/theme", 0).toInt());
|
||||
}
|
||||
|
||||
void SpkPageSettings::SaveConfiguration()
|
||||
{
|
||||
CFG->SetSettings("resource/concurrent", ui->spnConcurrentResDownloads->value());
|
||||
CFG->SetField("url/api", ui->edtApiUrl->text());
|
||||
CFG->SetField("url/res", ui->edtResourceUrl->text());
|
||||
CFG->SetSettings("dirs/cache", ui->edtResourceCachePath->text());
|
||||
CFG->SetField("dirs/download", ui->edtDownloadPath->text());
|
||||
CFG->SetSettings("internal/qss_path", ui->edtQssPath->text());
|
||||
CFG->SetField("url/repo", ui->edtRepoListUrl->text());
|
||||
if(!CFG->SetField("download/servers", ui->edtDownloadServers->toPlainText()))
|
||||
SpkMsgBox::StaticExec(tr("Cannot change distribution servers.\n"
|
||||
"There's probably still downloads going on."),
|
||||
tr("Cannot set distribution server"),
|
||||
QMessageBox::Warning);
|
||||
|
||||
if(!CFG->SetField("ui/theme", ui->cmbLightDarkTheme->currentIndex()))
|
||||
SpkMsgBox::StaticExec(tr("Auto mode can only be used when DDE plugin is loaded.\n"
|
||||
"Option change is not applied."),
|
||||
tr("Cannot set theme mode"),
|
||||
QMessageBox::Warning);
|
||||
}
|
||||
|
||||
void SpkPageSettings::CountCleaning()
|
||||
{
|
||||
ui->lblSizeDownloadedContent->setText(tr("Counting..."));
|
||||
ui->lblSizeResourceCache->setText(tr("Counting..."));
|
||||
auto futureDownload = QtConcurrent::run([&]()
|
||||
{
|
||||
QDirIterator itr(ui->edtDownloadPath->text().replace('*', QDir::homePath()),
|
||||
QDirIterator::Subdirectories);
|
||||
if(mMutDownload.tryLock(0))
|
||||
{
|
||||
int64_t size = 0;
|
||||
while(itr.hasNext())
|
||||
{
|
||||
QFile f(itr.next());
|
||||
size += f.size();
|
||||
}
|
||||
mBytesDownloads = size;
|
||||
mMutDownload.unlock();
|
||||
}
|
||||
});
|
||||
auto futureResource = QtConcurrent::run([&]()
|
||||
{
|
||||
QDirIterator itr(ui->edtResourceCachePath->text().replace('*', QDir::homePath()),
|
||||
QDirIterator::Subdirectories);
|
||||
if(mMutResource.tryLock((0)))
|
||||
{
|
||||
int64_t size = 0;
|
||||
while(itr.hasNext())
|
||||
{
|
||||
QFile f(itr.next());
|
||||
size += f.size();
|
||||
}
|
||||
mBytesResource = size;
|
||||
mMutResource.unlock();
|
||||
}
|
||||
});
|
||||
mFwDownloadCount.setFuture(futureDownload);
|
||||
mFwResourceCount.setFuture(futureResource);
|
||||
}
|
||||
|
||||
void SpkPageSettings::CleanedResource()
|
||||
{
|
||||
ui->lblSizeResourceCache->setText(tr("Cleaned"));
|
||||
}
|
||||
|
||||
void SpkPageSettings::CleanedDownload()
|
||||
{
|
||||
ui->lblSizeDownloadedContent->setText(tr("Cleaned"));
|
||||
}
|
||||
|
||||
void SpkPageSettings::Activated()
|
||||
{
|
||||
ReadConfiguration();
|
||||
CountCleaning();
|
||||
}
|
||||
|
||||
void SpkPageSettings::CountFinishResource()
|
||||
{
|
||||
if(mBytesResource >= 0)
|
||||
ui->lblSizeResourceCache->setText(SpkUtils::BytesToSize(mBytesResource));
|
||||
}
|
||||
|
||||
void SpkPageSettings::CountFinishDownload()
|
||||
{
|
||||
if(mBytesDownloads >= 0)
|
||||
ui->lblSizeDownloadedContent->setText(SpkUtils::BytesToSize(mBytesDownloads));
|
||||
}
|
||||
|
||||
void SpkPageSettings::on_btnViewResourceCache_clicked()
|
||||
{
|
||||
QDesktopServices::openUrl(ui->edtResourceCachePath->text().replace('*', QDir::homePath()));
|
||||
}
|
||||
|
||||
void SpkPageSettings::on_btnViewDownloadedContent_clicked()
|
||||
{
|
||||
QDesktopServices::openUrl(ui->edtDownloadPath->text().replace('*', QDir::homePath()));
|
||||
}
|
||||
|
||||
|
||||
void SpkPageSettings::on_btnCleanResourceCache_clicked()
|
||||
{
|
||||
ui->lblSizeResourceCache->setText(tr("Cleaning..."));
|
||||
auto future = QtConcurrent::run([&]()
|
||||
{
|
||||
QDirIterator itr(ui->edtResourceCachePath->text().replace('*', QDir::homePath()),
|
||||
QDirIterator::Subdirectories);
|
||||
if(mMutDownload.tryLock(0))
|
||||
{
|
||||
int64_t size = 0;
|
||||
while(itr.hasNext())
|
||||
{
|
||||
QFile f(itr.next());
|
||||
f.remove();
|
||||
}
|
||||
mBytesDownloads = size;
|
||||
mMutDownload.unlock();
|
||||
}
|
||||
});
|
||||
mFwResourceClean.setFuture(future);
|
||||
}
|
||||
|
||||
|
||||
void SpkPageSettings::on_btnCleanDownloadedContent_clicked()
|
||||
{
|
||||
ui->lblSizeDownloadedContent->setText(tr("Cleaning..."));
|
||||
auto futureDownload = QtConcurrent::run([&]()
|
||||
{
|
||||
QDirIterator itr(ui->edtDownloadPath->text().replace('*', QDir::homePath()),
|
||||
QDirIterator::Subdirectories);
|
||||
if(mMutDownload.tryLock(0))
|
||||
{
|
||||
int64_t size = 0;
|
||||
while(itr.hasNext())
|
||||
{
|
||||
QFile f(itr.next());
|
||||
f.remove();
|
||||
}
|
||||
mBytesDownloads = size;
|
||||
mMutDownload.unlock();
|
||||
}
|
||||
});
|
||||
mFwDownloadClean.setFuture(futureDownload);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
|
||||
#include <QApplication>
|
||||
#include "spkabout.h"
|
||||
#include "inc/page/spkpageuitest.h"
|
||||
#include "spkpopup.h"
|
||||
#include "spkui_general.h"
|
||||
#include "pkgs/spkpkgmgrbase.h"
|
||||
|
||||
SpkUi::SpkPageUiTest::SpkPageUiTest(QWidget *parent) : QSplitter(parent)
|
||||
{
|
||||
setObjectName("spk_pg_qsstest");
|
||||
|
||||
TextStylesheet = new QTextEdit(this);
|
||||
TextStylesheet->setObjectName("spk_pg_qsstest_qsstext");
|
||||
TextStylesheet->setPlainText(SpkUi::CurrentStylesheet);
|
||||
|
||||
BtnApply = new QPushButton(this);
|
||||
BtnApply->setObjectName("spk_pg_qsstest_btnapply");
|
||||
BtnApply->setText("Apply");
|
||||
connect(BtnApply, &QPushButton::pressed, this, &SpkPageUiTest::SetStylesheet);
|
||||
|
||||
BtnFetch = new QPushButton(this);
|
||||
BtnFetch->setObjectName("spk_pg_qsstest_btnfetch");
|
||||
BtnFetch->setText("Fetch Stylesheet");
|
||||
connect(BtnFetch, &QPushButton::pressed, this, &SpkPageUiTest::FetchStylesheet);
|
||||
|
||||
HLayInputBtns = new QHBoxLayout;
|
||||
HLayInputBtns->setObjectName("spk_pg_qsstest_hlay_inputbtns");
|
||||
HLayInputBtns->addWidget(BtnFetch);
|
||||
HLayInputBtns->addWidget(BtnApply);
|
||||
|
||||
Btn = new QPushButton(this);
|
||||
Btn->setObjectName("spk_pg_qsstest_button");
|
||||
Btn->setText("TestButton");
|
||||
|
||||
Chk = new QCheckBox(this);
|
||||
Chk->setObjectName("spk_pg_qsstest_checkbox");
|
||||
Chk->setText("CheckBox");
|
||||
|
||||
Rad = new QRadioButton(this);
|
||||
Rad->setObjectName("spk_pg_qsstest_radiobtn");
|
||||
Rad->setText("RadioButton");
|
||||
|
||||
Loading = new SpkLoading(this);
|
||||
Loading->setObjectName("spk_pg_qsstest_loading");
|
||||
Loading->start();
|
||||
|
||||
Prog = new QProgressBar(this);
|
||||
Prog->setObjectName("spk_pg_qsstest_prog");
|
||||
Prog->setValue(65);
|
||||
Prog->setRange(0, 100);
|
||||
|
||||
AppItem = new SpkAppItem(0, this);
|
||||
AppItem->setObjectName("spk_pg_qsstest_appitem");
|
||||
AppItem->SetTitle("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
|
||||
AppItem->SetDescription("Nam vehicula lacus vitae leo fermentum efficitur. "
|
||||
"Phasellus finibus risus id aliquam pulvinar.");
|
||||
AppItem->SetIcon(QIcon::fromTheme("dialog-information").pixmap(72, 72));
|
||||
|
||||
Detail1 = new SpkDetailEntry; Detail1->SetTitle("Foo"); Detail1->SetValue("1");
|
||||
Detail2 = new SpkDetailEntry; Detail2->SetTitle("Foo"); Detail2->SetValue("1");
|
||||
Detail3 = new SpkDetailEntry; Detail3->SetTitle("Foo"); Detail3->SetValue("1");
|
||||
|
||||
DetailsLay = new SpkStretchLayout;
|
||||
DetailsLay->addWidget(Detail1);
|
||||
DetailsLay->addWidget(Detail2);
|
||||
DetailsLay->addWidget(Detail3);
|
||||
|
||||
DetailsWidget = new QWidget;
|
||||
DetailsWidget->setLayout(DetailsLay);
|
||||
|
||||
PopupText = new QLineEdit(this);
|
||||
PopupText->setObjectName("spk_pg_qsstest_poptext");
|
||||
PopupText->setText("Hello, world");
|
||||
|
||||
ShowPopup = new QPushButton(this);
|
||||
ShowPopup->setText("Show Popup");
|
||||
connect(ShowPopup, &QPushButton::clicked, this, &SpkPageUiTest::ShowPopupSlot);
|
||||
|
||||
ShowAbout = new QPushButton(this);
|
||||
ShowAbout->setText("Show About Dialog");
|
||||
connect(ShowAbout, &QPushButton::clicked, [](){ SpkAbout::Show(); });
|
||||
|
||||
ShowPkgmgr = new QPushButton(this);
|
||||
ShowPkgmgr->setText("Show Install Menu");
|
||||
connect(ShowPkgmgr, &QPushButton::clicked, [=](){ SpkPkgMgrBase::Instance()->ExecuteInstallation(PopupText->text(), 0); });
|
||||
|
||||
SlideV = new QSlider(this);
|
||||
SlideV->setObjectName("spk_pg_qsstest_slider_v");
|
||||
SlideV->setOrientation(Qt::Vertical);
|
||||
SlideV->setMaximum(1000);
|
||||
SlideV->setMinimum(0);
|
||||
|
||||
SlideH = new QSlider(this);
|
||||
SlideH->setObjectName("spk_pg_qsstest_slider_h");
|
||||
SlideH->setOrientation(Qt::Horizontal);
|
||||
SlideH->setMaximum(1000);
|
||||
SlideH->setMinimum(0);
|
||||
|
||||
IconBtn = new SpkIconButton(this);
|
||||
IconBtn->setObjectName("spk_pg_qsstest_iconbtn");
|
||||
IconBtn->SetIcon(QIcon(":/icons/settings.svg"), QSize{ 16, 16 });
|
||||
|
||||
VLayTestWidgets = new QVBoxLayout;
|
||||
VLayTestWidgets->setObjectName("spk_pg_qsstest_vlay_btn");
|
||||
VLayTestWidgets->addWidget(Btn);
|
||||
VLayTestWidgets->addWidget(Chk);
|
||||
VLayTestWidgets->addWidget(Rad);
|
||||
VLayTestWidgets->addWidget(IconBtn);
|
||||
VLayTestWidgets->addWidget(Loading);
|
||||
VLayTestWidgets->addWidget(PopupText);
|
||||
VLayTestWidgets->addWidget(ShowPopup);
|
||||
VLayTestWidgets->addWidget(ShowAbout);
|
||||
VLayTestWidgets->addWidget(ShowPkgmgr);
|
||||
VLayTestWidgets->addWidget(AppItem);
|
||||
VLayTestWidgets->addWidget(DetailsWidget);
|
||||
|
||||
Group = new QGroupBox(this);
|
||||
Group->setObjectName("spk_pg_qsstest_groupbox");
|
||||
Group->setTitle("GroupBox");
|
||||
Group->setLayout(VLayTestWidgets);
|
||||
|
||||
VLayInput = new QVBoxLayout;
|
||||
VLayInput->setObjectName("spk_pg_qsstest_inputlay");
|
||||
VLayInput->addWidget(TextStylesheet);
|
||||
VLayInput->addLayout(HLayInputBtns);
|
||||
|
||||
VLayWidgets = new QVBoxLayout;
|
||||
VLayWidgets->setObjectName("spk_pg_qsstest_widgetlay");
|
||||
VLayWidgets->addWidget(Group);
|
||||
VLayWidgets->addWidget(SlideH);
|
||||
VLayWidgets->addWidget(Prog);
|
||||
|
||||
HLay4Slider = new QHBoxLayout;
|
||||
HLay4Slider->setObjectName("spk_pg_qsstest_hlay_for_slider");
|
||||
HLay4Slider->addLayout(VLayWidgets);
|
||||
HLay4Slider->addWidget(SlideV);
|
||||
|
||||
WidL = new QWidget(this);
|
||||
WidL->setObjectName("spk_pg_qsstest_widleft");
|
||||
WidL->setLayout(HLay4Slider);
|
||||
WidL->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
|
||||
|
||||
WidR = new QWidget(this);
|
||||
WidR->setObjectName("spk_pg_qsstest_widright");
|
||||
WidR->setLayout(VLayInput);
|
||||
|
||||
addWidget(WidL);
|
||||
addWidget(WidR);
|
||||
}
|
||||
|
||||
void SpkUi::SpkPageUiTest::SetStylesheet()
|
||||
{
|
||||
qApp->setStyleSheet(TextStylesheet->toPlainText());
|
||||
}
|
||||
|
||||
void SpkUi::SpkPageUiTest::FetchStylesheet()
|
||||
{
|
||||
TextStylesheet->setPlainText(SpkUi::CurrentStylesheet);
|
||||
}
|
||||
|
||||
void SpkUi::SpkPageUiTest::ShowPopupSlot()
|
||||
{
|
||||
SpkUi::Popup->Show(PopupText->text());
|
||||
}
|
||||
@@ -1,361 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SpkHomepage</class>
|
||||
<widget class="QWidget" name="SpkHomepage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>648</width>
|
||||
<height>554</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="hlayTitle">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblIcon">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>{spark-store-icon}</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblTitle">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>40</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Spark Store</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblAuthor">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>Brought to you by <a href="https://spark-app.store"><span style=" text-decoration: underline; color:#007af4;">Spark Project</span></a>, an open source software project.</p></body></html></string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>50</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="vlayBtns">
|
||||
<item row="1" column="1">
|
||||
<widget class="SpkNotifyDot" name="lblNewAnnouncement">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lblAboutProject">
|
||||
<property name="text">
|
||||
<string>About this project...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QPushButton" name="btnFeedback">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Feedback</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QPushButton" name="btnDonation">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Donation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QPushButton" name="btnAnnouncements">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Announcements</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QPushButton" name="btnSubmit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Submit Software</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widReloadCategory" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblCategoryErrIcon">
|
||||
<property name="text">
|
||||
<string>{error-icon}</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblCategoryErr">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Category failed to load. Click the button to retry.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnReloadCategory">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reload</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblVersion">
|
||||
<property name="text">
|
||||
<string>Version %1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnAbout">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>About</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>SpkNotifyDot</class>
|
||||
<extends>QLabel</extends>
|
||||
<header>spknotifydot.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -1,472 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SpkUiSettings</class>
|
||||
<widget class="QWidget" name="SpkUiSettings">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>581</width>
|
||||
<height>896</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="layTitle">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblSettingsTitle">
|
||||
<property name="text">
|
||||
<string>Spark Store Settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnSave">
|
||||
<property name="text">
|
||||
<string>Apply</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="lineTitle">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblRestartHint">
|
||||
<property name="text">
|
||||
<string>Configuration entries marked "*" will only take effect after restarting Spark Store.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="laySettings">
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="lblApiUrl">
|
||||
<property name="text">
|
||||
<string>Store API URL</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="lblResourceUrl">
|
||||
<property name="text">
|
||||
<string>Store resource URL</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="edtDownloadPath">
|
||||
<property name="spkcfg_key" stdset="0">
|
||||
<string notr="true">dirs/download</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="lblResourceCachePath">
|
||||
<property name="text">
|
||||
<string>Resource cache path*</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="lblAptRepo">
|
||||
<property name="text">
|
||||
<string>APT Repository</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QLineEdit" name="edtResourceUrl">
|
||||
<property name="spkcfg_key" stdset="0">
|
||||
<string>url/res</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="layAptRepo">
|
||||
<property name="spacing">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cmbAptRepo">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="spkcfg_key" stdset="0">
|
||||
<string notr="true">pkgmgr/apt_repo</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnFetchAptRepo">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Fetch all</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnApplyAptRepo">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Apply</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lblLightDarkTheme">
|
||||
<property name="text">
|
||||
<string>Light/dark theme</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLineEdit" name="edtResourceCachePath">
|
||||
<property name="spkcfg_key" stdset="0">
|
||||
<string>dirs/cache</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QPlainTextEdit" name="edtDownloadServers">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>80</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>150</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="baseSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="spkcfg_key" stdset="0">
|
||||
<string notr="true">download/servers</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="cmbLightDarkTheme">
|
||||
<property name="currentIndex">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="frame">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="spkcfg_key" stdset="0">
|
||||
<string notr="true">gui/theme</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Auto (DDE only)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Always Light</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Always Dark</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Manual</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="lblDownloadPath">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="toolTipDuration">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Download path*</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="lblDownloadServers">
|
||||
<property name="toolTip">
|
||||
<string>Server addresses are separated with two semicolons (;;).</string>
|
||||
</property>
|
||||
<property name="toolTipDuration">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Download servers</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QLineEdit" name="edtApiUrl">
|
||||
<property name="spkcfg_key" stdset="0">
|
||||
<string>url/api</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="lblRepoListUrl">
|
||||
<property name="text">
|
||||
<string>APT Repository Source</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QLineEdit" name="edtRepoListUrl"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblHomeNotice">
|
||||
<property name="text">
|
||||
<string>Note: character "*" in paths are replaced with the current user's home path.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblCleanup">
|
||||
<property name="text">
|
||||
<string>Cache and Downloads cleanup</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblCleanupDescription">
|
||||
<property name="text">
|
||||
<string>Spark Store caches resources such as app icons and screenshots locally. If you want to free up space, you can clear them here or delete them manually.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="layCleanup">
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="btnCleanDownloadedContent">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Clear</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="btnViewResourceCache">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>View</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="btnViewDownloadedContent">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>View</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="lblDownloadedContent">
|
||||
<property name="text">
|
||||
<string>Downloaded content</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lblResourceCache">
|
||||
<property name="text">
|
||||
<string>Resource cache</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QPushButton" name="btnCleanResourceCache">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Clear</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="lblSizeResourceCache">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="lblSizeDownloadedContent">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblAdvanced">
|
||||
<property name="text">
|
||||
<string>Advanced</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblAdvancedDescription">
|
||||
<property name="text">
|
||||
<string>Advanced settings are low-level configurations that can affect usability and are not meant to be modified by average users.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="layAdvanced">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lblConcurrentResDownloads">
|
||||
<property name="text">
|
||||
<string>Concurrent resource downloads*</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="spnConcurrentResDownloads">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="spkcfg_key" stdset="0">
|
||||
<string>resource/concurrent</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="lblQssPath">
|
||||
<property name="text">
|
||||
<string>Default Qt Style Sheet template*</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="edtQssPath">
|
||||
<property name="spkcfg_key" stdset="0">
|
||||
<string>internal/qss_path</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -1,133 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtCore module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** BSD License Usage
|
||||
** Alternatively, you may use this file under the terms of the BSD license
|
||||
** as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Slight modifications has been done to the code to make it fit into the project.
|
||||
*/
|
||||
|
||||
#include "qt/elidedlabel.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QSizePolicy>
|
||||
#include <QTextLayout>
|
||||
|
||||
//! [0]
|
||||
ElidedLabel::ElidedLabel(const QString &text, QWidget *parent)
|
||||
: QFrame(parent)
|
||||
, elided(false)
|
||||
, content(text)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
}
|
||||
//! [0]
|
||||
|
||||
//! [1]
|
||||
void ElidedLabel::setText(const QString &newText)
|
||||
{
|
||||
content = newText;
|
||||
update();
|
||||
}
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
void ElidedLabel::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
QFrame::paintEvent(event);
|
||||
|
||||
QPainter painter(this);
|
||||
QFontMetrics fontMetrics = painter.fontMetrics();
|
||||
|
||||
bool didElide = false;
|
||||
int lineSpacing = fontMetrics.lineSpacing();
|
||||
int y = 0;
|
||||
|
||||
QTextLayout textLayout(content, painter.font());
|
||||
textLayout.beginLayout();
|
||||
forever {
|
||||
QTextLine line = textLayout.createLine();
|
||||
|
||||
if (!line.isValid())
|
||||
break;
|
||||
|
||||
line.setLineWidth(width());
|
||||
int nextLineY = y + lineSpacing;
|
||||
|
||||
if (height() >= nextLineY + lineSpacing) {
|
||||
line.draw(&painter, QPoint(0, y));
|
||||
y = nextLineY;
|
||||
//! [2]
|
||||
//! [3]
|
||||
} else {
|
||||
QString lastLine = content.mid(line.textStart());
|
||||
QString elidedLastLine = fontMetrics.elidedText(lastLine, Qt::ElideRight, width());
|
||||
painter.drawText(QPoint(0, y + fontMetrics.ascent()), elidedLastLine);
|
||||
line = textLayout.createLine();
|
||||
didElide = line.isValid();
|
||||
break;
|
||||
}
|
||||
}
|
||||
textLayout.endLayout();
|
||||
//! [3]
|
||||
|
||||
//! [4]
|
||||
if (didElide != elided) {
|
||||
elided = didElide;
|
||||
emit elisionChanged(didElide);
|
||||
}
|
||||
}
|
||||
|
||||
ElidedLabel::ElidedLabel(QWidget *parent)
|
||||
: QFrame(parent)
|
||||
, elided(false)
|
||||
, content("")
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
}
|
||||
//! [4]
|
||||
@@ -1,73 +0,0 @@
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include "spkabout.h"
|
||||
#include "gitver.h"
|
||||
|
||||
SpkAbout::SpkAbout(QWidget *parent) : SpkDialog(parent)
|
||||
{
|
||||
setWindowModality(Qt::ApplicationModal);
|
||||
|
||||
// mDialogWidget->setMaximumWidth(600);
|
||||
mDialogWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
|
||||
setFixedSize(550, 450);
|
||||
SetResizable(false); // Do you like the dilemma of using self created widget?
|
||||
|
||||
mIconLay = new QHBoxLayout;
|
||||
|
||||
mSpkVersion = new QLabel;
|
||||
mSpkVersion->setText(tr("<h1>Spark Store</h1>"
|
||||
"<h3>Version <a href=\"https://www.spark-app.store\">%1</a></h3>"
|
||||
"<t>Built on %2 %3</t>")
|
||||
.arg(GitVer::DescribeTags(),
|
||||
__DATE__, __TIME__));
|
||||
connect(mSpkVersion, &QLabel::linkActivated,
|
||||
[](const QString &link){ QDesktopServices::openUrl(link); });
|
||||
|
||||
mSpkIcon = new QLabel;
|
||||
mSpkIcon->setPixmap(QIcon(":/icons/spark-store.svg").pixmap(QSize(128, 128)));
|
||||
|
||||
auto description = tr(
|
||||
"Spark Store was started when Chinese home-grown Linux operating systems "
|
||||
"had initially hit the market. Because the Linux desktop ecosystem is not "
|
||||
"good enough at the time being, volunteers built this small App Store in "
|
||||
"the hope that users can get useful applications faster.\n\n"
|
||||
"Right now we are not just a Chinese group. We are discovering our way into "
|
||||
"more Debian-based Linux OSes, and build a real community software repository "
|
||||
"for users around the world.");
|
||||
mDescriptionText = new QLabel;
|
||||
mDescriptionText->setObjectName("spk_about_desc");
|
||||
mDescriptionText->setWordWrap(true);
|
||||
mDescriptionText->setText(description);
|
||||
|
||||
mIconLay->addStretch(3);
|
||||
mIconLay->addWidget(mSpkIcon);
|
||||
mIconLay->addStretch(1);
|
||||
mIconLay->addWidget(mSpkVersion);
|
||||
mIconLay->addStretch(3);
|
||||
mIconLay->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
|
||||
|
||||
AddStretch();
|
||||
AddLayout(mIconLay);
|
||||
AddSpacing(18);
|
||||
AddWidget(mDescriptionText);
|
||||
AddStretch();
|
||||
SetMargin(18, 0, 18, 18);
|
||||
|
||||
GetTitleBar()->SetOperationButton(SpkTitleBar::OperationButton::Close);
|
||||
GetTitleBar()->SetTitle(tr("About Spark Store"));
|
||||
}
|
||||
|
||||
SpkAbout::~SpkAbout()
|
||||
{
|
||||
// delete mIconLay;
|
||||
// delete mDescriptionText;
|
||||
}
|
||||
|
||||
void SpkAbout::Show()
|
||||
{
|
||||
SpkAbout *b = new SpkAbout;
|
||||
|
||||
b->Exec();
|
||||
delete b;
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
|
||||
#include <QPainter>
|
||||
#include <QStyleOption>
|
||||
#include "spkappitem.h"
|
||||
#include "qt/elidedlabel.h"
|
||||
|
||||
const QSize SpkAppItem::IconSize_;
|
||||
|
||||
SpkAppItem::SpkAppItem(int appId, QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
mAppId = appId;
|
||||
|
||||
mMainLay = new QHBoxLayout(this);
|
||||
mLayText = new QVBoxLayout;
|
||||
|
||||
mIcon = new QLabel;
|
||||
mIcon->setFixedSize(IconSize, IconSize);
|
||||
mIcon->setAutoFillBackground(false);
|
||||
|
||||
// NOTE: Make mTitle ElidedTitle too?
|
||||
mTitle = new QLabel;
|
||||
mTitle->setWordWrap(false);
|
||||
mTitle->setObjectName("styAppItmTitle");
|
||||
mTitle->setAutoFillBackground(true);
|
||||
mDescription = new ElidedLabel;
|
||||
// mDescription->setWordWrap(true); // Commented out since ElidedLabel lacks of these methods
|
||||
mDescription->setObjectName("styAppItmDesc");
|
||||
mDescription->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
// mDescription->setAlignment(Qt::AlignTop | Qt::AlignLeft);
|
||||
// mDescription->setAutoFillBackground(true);
|
||||
mLayText->addWidget(mTitle);
|
||||
mLayText->addWidget(mDescription);
|
||||
mLayText->setAlignment(Qt::AlignTop);
|
||||
|
||||
mMainLay->setMargin(5);
|
||||
mMainLay->addWidget(mIcon);
|
||||
mMainLay->addLayout(mLayText);
|
||||
|
||||
setMinimumHeight(82);
|
||||
setMaximumHeight(82);
|
||||
setMinimumWidth(300);
|
||||
}
|
||||
|
||||
void SpkAppItem::paintEvent(QPaintEvent *e)
|
||||
{
|
||||
Q_UNUSED(e)
|
||||
QStyleOption opt;
|
||||
opt.init(this);
|
||||
QPainter p(this);
|
||||
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
|
||||
}
|
||||
|
||||
void SpkAppItem::mousePressEvent(QMouseEvent *e)
|
||||
{
|
||||
mPressCond = true;
|
||||
}
|
||||
|
||||
void SpkAppItem::mouseReleaseEvent(QMouseEvent *e)
|
||||
{
|
||||
if(mPressCond)
|
||||
emit clicked(mAppId);
|
||||
mPressCond = false;
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
|
||||
#include "spkmainwindow.h"
|
||||
|
||||
namespace SpkUi
|
||||
{
|
||||
SpkCategorySelector::SpkCategorySelector(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
mBtnLayout = new QVBoxLayout(this);
|
||||
mGroup = new QButtonGroup(this);
|
||||
}
|
||||
|
||||
void SpkCategorySelector::AddButton(QString aBtnText, int aCategoryId, QPixmap *aBtnIcon)
|
||||
{
|
||||
auto btn = new SpkCategoryButton(this);
|
||||
btn->SetText(aBtnText);
|
||||
if(aBtnIcon)
|
||||
btn->SetIcon(*aBtnIcon);
|
||||
mBtnList.append(btn);
|
||||
mGroup->addButton(btn, aCategoryId ? aCategoryId : -1);
|
||||
mBtnLayout->addWidget(btn);
|
||||
}
|
||||
|
||||
void SpkCategorySelector::DeleteAllButtons() // TODO: UNTESTED
|
||||
{
|
||||
foreach (auto i, mBtnList)
|
||||
{
|
||||
mBtnLayout->removeWidget(i);
|
||||
mGroup->removeButton(i);
|
||||
i->deleteLater();
|
||||
}
|
||||
mBtnList.clear();
|
||||
}
|
||||
|
||||
SpkCategoryButton::SpkCategoryButton(QWidget *parent) : QPushButton(parent)
|
||||
{
|
||||
mIcon = new QLabel(this);
|
||||
mIcon->setObjectName("spk_categorybtn_label");
|
||||
mText = new QLabel(this);
|
||||
mText->setObjectName("spk_categorybtn_text");
|
||||
mLayout = new QHBoxLayout;
|
||||
mLayout->setObjectName("spk_categorybtn_lay");
|
||||
mLayout->addSpacing(Spacing);
|
||||
mLayout->addWidget(mIcon);
|
||||
mLayout->addSpacing(Spacing);
|
||||
mLayout->addStretch();
|
||||
mLayout->addWidget(mText);
|
||||
mLayout->addStretch();
|
||||
mLayout->addSpacing(Spacing);
|
||||
setLayout(mLayout);
|
||||
}
|
||||
|
||||
void SpkCategoryButton::SetIcon(QPixmap aImage)
|
||||
{
|
||||
mIcon->setPixmap(aImage);
|
||||
}
|
||||
|
||||
void SpkCategoryButton::SetText(QString aText)
|
||||
{
|
||||
mText->setText(aText);
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
|
||||
#include "spkdialog.h"
|
||||
#include <QEventLoop>
|
||||
|
||||
SpkDialog::SpkDialog(QWidget *parent) : SpkWindow(parent)
|
||||
{
|
||||
mDialogWidget = new QWidget;
|
||||
mMainVLay = new QVBoxLayout;
|
||||
mWidgetsVLay = new QVBoxLayout();
|
||||
mBtnLay = new QHBoxLayout();
|
||||
mBtnGroup = new QButtonGroup(this);
|
||||
|
||||
mMainVLay->addLayout(mWidgetsVLay);
|
||||
mMainVLay->addLayout(mBtnLay);
|
||||
|
||||
mBtnLay->setAlignment(Qt::AlignCenter);
|
||||
|
||||
SetCentralWidget(mDialogWidget);
|
||||
|
||||
mDialogWidget->setLayout(mMainVLay);
|
||||
|
||||
// idClicked is not available on platforms we support, shouldn't change it
|
||||
connect(mBtnGroup, QOverload<int>::of(&QButtonGroup::buttonClicked),
|
||||
this, &SpkDialog::ButtonPressed);
|
||||
connect(this, &SpkWindow::Closed, this, &SpkDialog::ForceClose);
|
||||
}
|
||||
|
||||
SpkDialog::~SpkDialog()
|
||||
{
|
||||
auto itp = mParentsList.begin();
|
||||
for(auto itw = mWidgetsList.begin(); itw != mWidgetsList.end(); itw++)
|
||||
{
|
||||
(*itw)->setParent(*(itp++));// We shall never take the ownership of these widgets
|
||||
}
|
||||
delete mDialogWidget;
|
||||
}
|
||||
|
||||
void SpkDialog::AddButton(QString text, SpkUi::SpkButtonStyle style)
|
||||
{
|
||||
auto b = new QPushButton();
|
||||
b->setText(text);
|
||||
b->setMinimumWidth(100);
|
||||
b->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||
switch(style)
|
||||
{
|
||||
|
||||
case SpkUi::SpkButtonStyle::Recommend:
|
||||
b->setObjectName("sty_recommendbtn");
|
||||
break;
|
||||
case SpkUi::SpkButtonStyle::Warn:
|
||||
b->setObjectName("sty_warnbtn");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
mBtnLay->addWidget(b);
|
||||
mBtnGroup->addButton(b);
|
||||
}
|
||||
|
||||
void SpkDialog::AddWidget(QWidget *w)
|
||||
{
|
||||
// Adding a widget does not take the ownership.
|
||||
mWidgetsVLay->addWidget(w);
|
||||
mWidgetsList << w;
|
||||
mParentsList << w->parentWidget();
|
||||
}
|
||||
|
||||
void SpkDialog::AddLayout(QLayout *w)
|
||||
{
|
||||
mWidgetsVLay->addLayout(w);
|
||||
mWidgetsList << w;
|
||||
mParentsList << w->parentWidget();
|
||||
}
|
||||
|
||||
void SpkDialog::AddSpacing(int a)
|
||||
{
|
||||
mWidgetsVLay->addSpacing(a);
|
||||
}
|
||||
|
||||
void SpkDialog::AddStretch(int a)
|
||||
{
|
||||
mWidgetsVLay->addStretch(a);
|
||||
}
|
||||
|
||||
void SpkDialog::SetMargin(int a)
|
||||
{
|
||||
mWidgetsVLay->setMargin(a);
|
||||
}
|
||||
|
||||
int SpkDialog::Exec()
|
||||
{
|
||||
QEventLoop loop;
|
||||
connect(this, &SpkDialog::ExitEventLoop, &loop, &QEventLoop::exit);
|
||||
connect(this, &SpkDialog::CloseWindow, this, &QMainWindow::close);
|
||||
show();
|
||||
return loop.exec();
|
||||
}
|
||||
|
||||
void SpkDialog::ButtonPressed(int aBtnId)
|
||||
{
|
||||
disconnect(this, &SpkWindow::Closed, this, &SpkDialog::ForceClose);
|
||||
emit ExitEventLoop(-aBtnId - 2);
|
||||
emit CloseWindow();
|
||||
}
|
||||
|
||||
void SpkDialog::ForceClose()
|
||||
{
|
||||
disconnect(this, &SpkDialog::CloseWindow, this, &QMainWindow::close);
|
||||
emit ExitEventLoop(-1);
|
||||
}
|
||||
|
||||
void SpkDialog::SetMargin(int left, int top, int right, int bottom)
|
||||
{
|
||||
mWidgetsVLay->setContentsMargins(left, top, right, bottom);
|
||||
}
|
||||
@@ -1,201 +0,0 @@
|
||||
|
||||
#include "spkdownloadentry.h"
|
||||
#include "spklogging.h"
|
||||
#include "spkutils.h"
|
||||
#include <QDebug>
|
||||
|
||||
constexpr QSize SpkDownloadEntry::IconSize;
|
||||
|
||||
SpkDownloadEntry::SpkDownloadEntry(QWidget *parent)
|
||||
{
|
||||
mIcon = new QLabel;
|
||||
mAppName = new ElidedLabel;
|
||||
mMessage = new QLabel;
|
||||
mProgress = new QProgressBar;
|
||||
mLoading = new SpkLoading;
|
||||
mBtnDelete = new QPushButton;
|
||||
mBtnActions = new QPushButton;
|
||||
|
||||
mLayInfo = new QVBoxLayout;
|
||||
mLayMsgs = new QHBoxLayout;
|
||||
mLayMain = new QHBoxLayout;
|
||||
|
||||
mLoading->setVisible(false);
|
||||
mIcon->setFixedSize(IconSize);
|
||||
mProgress->setRange(0, 1000);
|
||||
|
||||
mLayMsgs->addWidget(mAppName);
|
||||
mLayMsgs->addStretch();
|
||||
mLayMsgs->addWidget(mMessage);
|
||||
|
||||
mLayInfo->addLayout(mLayMsgs);
|
||||
mLayInfo->addWidget(mProgress);
|
||||
mLayInfo->setAlignment(Qt::AlignVCenter);
|
||||
|
||||
mLayMain->addWidget(mIcon);
|
||||
mLayMain->addLayout(mLayInfo);
|
||||
mLayMain->addWidget(mLoading);
|
||||
mLayMain->addWidget(mBtnActions);
|
||||
mLayMain->addWidget(mBtnDelete);
|
||||
|
||||
setLayout(mLayMain);
|
||||
|
||||
connect(mBtnActions, &QPushButton::clicked, this, &SpkDownloadEntry::ActionButton);
|
||||
connect(mBtnDelete, &QPushButton::clicked, this, &SpkDownloadEntry::DeleteButton);
|
||||
|
||||
mStatus = Invalid;
|
||||
|
||||
mLastReportTime = QTime::currentTime();
|
||||
}
|
||||
|
||||
|
||||
SpkDownloadEntry::~SpkDownloadEntry()
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void SpkDownloadEntry::SetTotalBytes(qint64 total)
|
||||
{
|
||||
mTotalBytes = total;
|
||||
mReadableTotalSize = SpkUtils::BytesToSize(total);
|
||||
mLastReportTime = QTime::currentTime();
|
||||
}
|
||||
|
||||
void SpkDownloadEntry::SetBasicInfo(QString name, QPixmap icon, QString filePath)
|
||||
{
|
||||
mAppName->setText(name);
|
||||
mIcon->setPixmap(icon.scaled(IconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
||||
mFilePath = filePath;
|
||||
}
|
||||
|
||||
void SpkDownloadEntry::SetStatus(DownloadEntryStatus status, QString msg)
|
||||
{
|
||||
mStatus = status;
|
||||
switch(status)
|
||||
{
|
||||
case Waiting:
|
||||
mMessage->setText(tr("Waiting for download"));
|
||||
mProgress->setVisible(false);
|
||||
mBtnActions->setVisible(false);
|
||||
mBtnDelete->setVisible(true);
|
||||
mBtnDelete->setText(tr("Cancel"));
|
||||
break;
|
||||
|
||||
case Starting:
|
||||
mMessage->setText(tr("Starting download"));
|
||||
mBtnDelete->setVisible(false);
|
||||
break;
|
||||
|
||||
case Downloading:
|
||||
mMessage->setText(tr(""));
|
||||
mProgress->setVisible(true);
|
||||
mBtnActions->setVisible(false);
|
||||
mBtnDelete->setVisible(true);
|
||||
break;
|
||||
|
||||
case DownloadFailed:
|
||||
mMessage->setText(msg);
|
||||
mProgress->setVisible(false);
|
||||
mBtnActions->setVisible(true);
|
||||
mBtnActions->setText(tr("Retry"));
|
||||
|
||||
break;
|
||||
|
||||
case ToBeInstalled:
|
||||
mMessage->setText(tr("Download Finished"));
|
||||
mProgress->setVisible(false);
|
||||
mBtnActions->setVisible(true);
|
||||
mBtnDelete->setVisible(false);
|
||||
mBtnActions->setText(tr("Install"));
|
||||
break;
|
||||
|
||||
case Installing:
|
||||
mMessage->setText("");
|
||||
mProgress->setVisible(false);
|
||||
mBtnActions->setVisible(false);
|
||||
mBtnDelete->setVisible(false);
|
||||
mLoading->setVisible(true);
|
||||
mLoading->Begin();
|
||||
break;
|
||||
|
||||
case Installed:
|
||||
mMessage->setText(tr("Installed"));
|
||||
mLoading->End();
|
||||
mLoading->setVisible(false);
|
||||
mBtnDelete->setVisible(true);
|
||||
mBtnDelete->setText(tr("Delete"));
|
||||
break;
|
||||
|
||||
case InstallFailed:
|
||||
mMessage->setText(msg.isEmpty() ? tr("Install Failed") : msg);
|
||||
mLoading->End();
|
||||
mLoading->setVisible(false);
|
||||
mBtnActions->setVisible(true);
|
||||
mBtnActions->setText(tr("Install"));
|
||||
mBtnDelete->setVisible(true);
|
||||
mBtnDelete->setText(tr("Cancel"));
|
||||
break;
|
||||
|
||||
case Invalid:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SpkDownloadEntry::Progress(qint64 bytes)
|
||||
{
|
||||
auto now = QTime::currentTime();
|
||||
auto msecDiff = mLastReportTime.msecsTo(now);
|
||||
|
||||
if(msecDiff != 0)
|
||||
{
|
||||
auto bytesPerSec = (bytes - mDownloadedBytes) / (msecDiff / 1000.0);
|
||||
qDebug() << "Bytes" << bytes - mDownloadedBytes
|
||||
<< "MsDiff" << msecDiff / 1000.0
|
||||
<< "Bytes-Per-Seg" << bytesPerSec;
|
||||
auto speedSize = SpkUtils::BytesToSize(static_cast<size_t>(bytesPerSec));
|
||||
mMessage->setText(QString("%1/%2(%3/s)")
|
||||
.arg(SpkUtils::BytesToSize(bytes), mReadableTotalSize, speedSize));
|
||||
}
|
||||
mDownloadedBytes = bytes;
|
||||
mProgress->setValue(static_cast<int>(((double)bytes) / mTotalBytes * 1000));
|
||||
mLastReportTime = now;
|
||||
}
|
||||
|
||||
void SpkDownloadEntry::ActionButton()
|
||||
{
|
||||
switch(mStatus)
|
||||
{
|
||||
case DownloadFailed:
|
||||
emit Action(RetryDownload);
|
||||
break;
|
||||
|
||||
case ToBeInstalled:
|
||||
case InstallFailed:
|
||||
emit Action(StartInstall);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SpkDownloadEntry::DeleteButton()
|
||||
{
|
||||
switch(mStatus)
|
||||
{
|
||||
case Waiting:
|
||||
case DownloadFailed:
|
||||
case Installed:
|
||||
case InstallFailed:
|
||||
case ToBeInstalled:
|
||||
emit Action(RemoveEntry);
|
||||
break;
|
||||
|
||||
case Downloading:
|
||||
emit Action(AbortDownload);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
|
||||
#include <QMargins>
|
||||
#include <QPainter>
|
||||
#include <QVariant>
|
||||
#include <QDebug>
|
||||
#include "spkiconbutton.h"
|
||||
|
||||
SpkIconButton::SpkIconButton(QWidget *parent) :
|
||||
QPushButton(parent)
|
||||
{
|
||||
setFocusPolicy(Qt::NoFocus);
|
||||
}
|
||||
|
||||
void SpkIconButton::SetIcon(QIcon i, QSize s)
|
||||
{
|
||||
mPmapPaintedIcon = i.pixmap(s);
|
||||
|
||||
setFixedSize((mPmapSize = s.grownBy(QMargins(IconMargin, IconMargin, IconMargin, IconMargin))));
|
||||
}
|
||||
|
||||
void SpkIconButton::SetIcon(QPixmap m)
|
||||
{
|
||||
mPmapPaintedIcon = m;
|
||||
|
||||
setFixedSize((mPmapSize = m.size().grownBy(QMargins(IconMargin, IconMargin,
|
||||
IconMargin, IconMargin))));
|
||||
}
|
||||
|
||||
void SpkIconButton::SetIconSize(QSize s)
|
||||
{
|
||||
setFixedSize((mPmapSize = s.grownBy(QMargins(IconMargin, IconMargin, IconMargin, IconMargin))));
|
||||
}
|
||||
|
||||
void SpkIconButton::paintEvent(QPaintEvent *e)
|
||||
{
|
||||
QPushButton::paintEvent(e);
|
||||
|
||||
// Paint the icon mask
|
||||
QPainter p(this), p1(&mPmapPaintedIcon);
|
||||
QBrush b(Qt::SolidPattern);
|
||||
|
||||
p.drawPixmap(IconMargin, IconMargin, mPmapPaintedIcon);
|
||||
if(isDown() || isChecked())
|
||||
{
|
||||
b.setColor(SpkUi::ColorBtnMaskSelected);
|
||||
}
|
||||
else
|
||||
{
|
||||
b.setColor(SpkUi::ColorBtnMaskUnselected);
|
||||
}
|
||||
p1.setCompositionMode(QPainter::CompositionMode_SourceIn);
|
||||
p1.fillRect(0, 0, mPmapSize.width(), mPmapSize.height(), b);
|
||||
p1.end();
|
||||
p.drawPixmap(IconMargin, IconMargin, mPmapPaintedIcon);
|
||||
p.end();
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
|
||||
#include "spktitlebar.h"
|
||||
#include "spkimgviewer.h"
|
||||
#include "spkui_general.h"
|
||||
#include <QDebug>
|
||||
#include <QFocusEvent>
|
||||
#include <QGuiApplication>
|
||||
#include <QScreen>
|
||||
|
||||
SpkImgViewer::SpkImgViewer(QWidget *parent) :
|
||||
SpkWindow(parent),
|
||||
mIconLoading(QIcon(":/icons/loading-icon.svg").pixmap({ 72, 72 }))
|
||||
{
|
||||
mImgIndict = new QLabel;
|
||||
mImgIndict->setText("%1/%2");
|
||||
mBtnPrev = new QPushButton;
|
||||
mBtnPrev->setText("<");
|
||||
mBtnNext = new QPushButton;
|
||||
mBtnNext->setText(">");
|
||||
|
||||
auto titleBar = GetTitleBar();
|
||||
titleBar->SetUseIcon(false);
|
||||
titleBar->SetTitle(tr("Image Preview"));
|
||||
titleBar->SetOperationButton(SpkTitleBar::OperationButton::Close);
|
||||
|
||||
auto lay = titleBar->GetUserSpace();
|
||||
lay->setAlignment(Qt::AlignVCenter);
|
||||
lay->addStretch();
|
||||
lay->addWidget(mBtnPrev);
|
||||
lay->addWidget(mImgIndict);
|
||||
lay->addWidget(mBtnNext);
|
||||
lay->addStretch();
|
||||
|
||||
mImgArea = new QScrollArea;
|
||||
mImgArea->setWidgetResizable(true);
|
||||
mImgArea->setContentsMargins(10, 10, 10, 10);
|
||||
|
||||
mImgShow = new ImgView;
|
||||
|
||||
mImgArea->setWidget(mImgShow);
|
||||
|
||||
auto w = new QWidget;
|
||||
auto l = new QHBoxLayout;
|
||||
l->setContentsMargins(10, 10, 10, 10);
|
||||
l->addWidget(mImgArea);
|
||||
w->setLayout(l);
|
||||
SetCentralWidget(w);
|
||||
|
||||
connect(mBtnPrev, &QPushButton::clicked,
|
||||
[&](){ if(mCurrentImg > 0) { SwitchToImage(--mCurrentImg); } });
|
||||
connect(mBtnNext, &QPushButton::clicked,
|
||||
[&](){ if(mCurrentImg < mTotalImg) { SwitchToImage(++mCurrentImg); } });
|
||||
}
|
||||
|
||||
void SpkImgViewer::ShowWithImage(int idx)
|
||||
{
|
||||
SwitchToImage(idx);
|
||||
show();
|
||||
}
|
||||
|
||||
void SpkImgViewer::Clear()
|
||||
{
|
||||
mImgMap.clear();
|
||||
mImgShow->SetPixmap(nullptr);
|
||||
mCurrentImg = 1;
|
||||
}
|
||||
|
||||
void SpkImgViewer::SetPixmap(int idx, QPixmap *img)
|
||||
{
|
||||
mImgMap[idx] = img;
|
||||
if(mCurrentImg == idx)
|
||||
{
|
||||
mImgShow->SetPixmap(img);
|
||||
}
|
||||
ResizeToFitImageSize(img->size());
|
||||
}
|
||||
|
||||
void SpkImgViewer::SwitchToImage(int idx)
|
||||
{
|
||||
auto img = mImgMap.value(idx, nullptr);
|
||||
mCurrentImg = idx;
|
||||
mImgShow->SetPixmap(img ? img : &mIconLoading);
|
||||
if(img)
|
||||
ResizeToFitImageSize(img->size());
|
||||
if(idx == 1)
|
||||
{
|
||||
mBtnPrev->setEnabled(false);
|
||||
mBtnNext->setEnabled(true);
|
||||
}
|
||||
else if(idx == mTotalImg)
|
||||
{
|
||||
mBtnPrev->setEnabled(true);
|
||||
mBtnNext->setEnabled(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
mBtnPrev->setEnabled(true);
|
||||
mBtnNext->setEnabled(true);
|
||||
}
|
||||
mImgIndict->setText(QString("%1/%2").arg(mCurrentImg).arg(mTotalImg));
|
||||
}
|
||||
|
||||
bool SpkImgViewer::event(QEvent *e)
|
||||
{
|
||||
if(e->type() == QEvent::WindowDeactivate)
|
||||
close();
|
||||
return SpkWindow::event(e);
|
||||
}
|
||||
|
||||
void SpkImgViewer::ResizeToFitImageSize(QSize s)
|
||||
{
|
||||
auto targetSize = s;
|
||||
targetSize.rheight() += SpkTitleBar::Height;
|
||||
targetSize = s.grownBy(QMargins(10, 10, 10, 10));
|
||||
targetSize = targetSize.boundedTo(SpkUi::PrimaryScreenSize * 0.8);
|
||||
resize(targetSize);
|
||||
targetSize /= 2;
|
||||
auto targetPos = SpkUi::PrimaryScreenSize / 2 - targetSize;
|
||||
move(targetPos.width(), targetPos.height());
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
|
||||
#include <QPaintEvent>
|
||||
#include <QPainter>
|
||||
#include "spkloading.h"
|
||||
#include "spkui_general.h"
|
||||
|
||||
SpkLoading::SpkLoading(QWidget *parent) : QFrame(parent)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
mAnimTimer = new QTimeLine(400, this);
|
||||
mAnimTimer->setFrameRange(10, 30);
|
||||
mAnimTimer->setEasingCurve(QEasingCurve::InCubic);
|
||||
for(int i = 0; i < 5; i++)
|
||||
mSizeList.append(20);
|
||||
connect(mAnimTimer, &QTimeLine::frameChanged, this, &SpkLoading::timer);
|
||||
connect(mAnimTimer, &QTimeLine::finished, this, &SpkLoading::loop);
|
||||
}
|
||||
|
||||
void SpkLoading::paintEvent(QPaintEvent *e)
|
||||
{
|
||||
QPainter p(this);
|
||||
QPen pen(Qt::NoPen);
|
||||
QBrush b(SpkUi::CurrentColorSet[SpkUi::Qss::AccentColor], Qt::SolidPattern);
|
||||
p.setBrush(b);
|
||||
p.setPen(pen);
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
dx = width() / 2 - dh * 2;
|
||||
dy = height() / 2;
|
||||
|
||||
double r;
|
||||
for(int i = 0; i < 5; i++)
|
||||
{
|
||||
r = dh * mSizeList[i] / 80;
|
||||
p.drawEllipse({ dx, dy }, r, r);
|
||||
dx += dh;
|
||||
}
|
||||
e->accept();
|
||||
}
|
||||
|
||||
void SpkLoading::resizeEvent(QResizeEvent *e)
|
||||
{
|
||||
// Calculate size of drawing space
|
||||
if(mUserHeight != 0 && mUserHeight * 5 <= e->size().width())
|
||||
{
|
||||
dw = 5 * mUserHeight;
|
||||
dh = mUserHeight;
|
||||
return;
|
||||
}
|
||||
dh = e->size().height();
|
||||
if(width() < dh * 5)
|
||||
{
|
||||
dw = e->size().width();
|
||||
dh = dw / 5;
|
||||
}
|
||||
else
|
||||
dw = dh * 5;
|
||||
}
|
||||
|
||||
void SpkLoading::timer(int s)
|
||||
{
|
||||
for(int i = 4; i > 0; i--)
|
||||
mSizeList[i] = mSizeList[i - 1];
|
||||
mSizeList[0] = s;
|
||||
update();
|
||||
}
|
||||
|
||||
void SpkLoading::loop()
|
||||
{
|
||||
mAnimTimer->setDirection(mAnimTimer->direction() == QTimeLine::Forward ?
|
||||
QTimeLine::Backward : QTimeLine::Forward);
|
||||
mAnimTimer->start();
|
||||
}
|
||||
|
||||
void SpkLoading::reset()
|
||||
{
|
||||
for(int i = 0; i < 5; i++)
|
||||
mSizeList[i] = 20;
|
||||
update();
|
||||
}
|
||||
@@ -1,570 +0,0 @@
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QScreen>
|
||||
#include <QJsonArray>
|
||||
#include "spkmsgbox.h"
|
||||
#include "spkmainwindow.h"
|
||||
#include "spklogging.h"
|
||||
#include "spkutils.h"
|
||||
#include "spkuimsg.h"
|
||||
|
||||
SpkMainWindow::SpkMainWindow(QWidget *parent) : SpkWindow(parent)
|
||||
{
|
||||
ui = new SpkUi::SpkMainWidget(this);
|
||||
Initialize();
|
||||
|
||||
SetCentralWidget(ui);
|
||||
RefreshCategoryData();
|
||||
GetTitleBar()->SetTitle("");
|
||||
GetTitleBar()->SetUseIcon(true);
|
||||
GetTitleBar()->SetIcon(QIcon(":/icons/spark-store.svg").pixmap({ 40, 40 }));
|
||||
GetTitleBar()->setObjectName("spk_mw_titlebar");
|
||||
GetTitleBar()->setAttribute(Qt::WA_StyledBackground);
|
||||
|
||||
auto size = QGuiApplication::primaryScreen()->size() * 0.5;
|
||||
size = size.expandedTo(QSize(900, 600));
|
||||
resize(size);
|
||||
auto pos = QGuiApplication::primaryScreen()->size() * 0.5 - size * 0.5;
|
||||
move(pos.width(), pos.height());
|
||||
}
|
||||
|
||||
void SpkMainWindow::SwitchDayNightTheme()
|
||||
{
|
||||
if(SpkUi::CurrentStyle == SpkUi::Dark)
|
||||
SpkUi::SetGlobalStyle(SpkUi::Light, true);
|
||||
else
|
||||
SpkUi::SetGlobalStyle(SpkUi::Dark, true);
|
||||
ReloadThemedUiIcons();
|
||||
}
|
||||
|
||||
void SpkMainWindow::SwitchToPage(SpkUi::SpkStackedPages page)
|
||||
{
|
||||
if(mCurrentPage != page)
|
||||
{
|
||||
ui->Pager->setCurrentIndex(int(page));
|
||||
mCurrentPage = page;
|
||||
// If the page is a SpkPageBase (with a resource context), activate it for resource acquisition
|
||||
auto tryActivate = qobject_cast<SpkPageBase *>(ui->Pager->currentWidget());
|
||||
if(tryActivate)
|
||||
tryActivate->Activated();
|
||||
|
||||
ui->BtnBack->setVisible(page == SpkUi::SpkStackedPages::PgAppDetails);
|
||||
ui->BtnBack->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void SpkMainWindow::PopulateCategories(QJsonArray aCategoryData)
|
||||
{
|
||||
using SpkUi::SpkSidebarSelector;
|
||||
QTreeWidgetItem *catg;
|
||||
if(ui->CategoryParentItem->childCount()) // Clear all existing children if there is any
|
||||
foreach(auto &i, ui->CategoryParentItem->takeChildren())
|
||||
delete i;
|
||||
|
||||
foreach(auto i, aCategoryData)
|
||||
{
|
||||
if(i.isObject())
|
||||
{
|
||||
auto j = i.toObject();
|
||||
double typeId;
|
||||
QString typeName;
|
||||
if(j.contains("type_id") && j.value("type_id").isDouble())
|
||||
typeId = j.value("type_id").toDouble();
|
||||
else goto WRONG_CATEGORY;
|
||||
if(j.contains("type_name") && j.value("type_name").isString())
|
||||
typeName = j.value("type_name").toString();
|
||||
else goto WRONG_CATEGORY;
|
||||
catg = new QTreeWidgetItem(ui->CategoryParentItem, QStringList(typeName));
|
||||
catg->setData(0, SpkSidebarSelector::RoleItemIsCategory, true);
|
||||
catg->setData(0, SpkSidebarSelector::RoleItemCategoryPageId, typeId);
|
||||
continue;
|
||||
WRONG_CATEGORY:;
|
||||
}
|
||||
ui->CategoryParentItem->setExpanded(true);
|
||||
}
|
||||
}
|
||||
|
||||
void SpkMainWindow::RefreshCategoryData()
|
||||
{
|
||||
// Asynchronously call category API
|
||||
using namespace SpkUtils;
|
||||
VerifySingleRequest(mCategoryGetReply);
|
||||
mCategoryGetReply = STORE->SendApiRequest("type/get_type_list");
|
||||
DeleteReplyLater(mCategoryGetReply);
|
||||
connect(mCategoryGetReply, &QNetworkReply::finished, this, &SpkMainWindow::CategoryDataReceived);
|
||||
}
|
||||
|
||||
void SpkMainWindow::CategoryDataReceived()
|
||||
{
|
||||
QJsonValue retval;
|
||||
auto verify = SpkUtils::VerifyReplyJson(mCategoryGetReply, retval);
|
||||
if(verify || !retval.isArray())
|
||||
{
|
||||
sErr(tr("Failed to load categories! Type=%1 Code=%2").arg(retval.type()).arg(verify));
|
||||
sNotify(tr("Cannot load categories! Type: %1 Code: %2").arg(retval.type()).arg(verify));
|
||||
ui->PageHome->ui->widReloadCategory->setVisible(true);
|
||||
return;
|
||||
}
|
||||
ui->PageHome->ui->widReloadCategory->setVisible(false);
|
||||
PopulateCategories(retval.toArray());
|
||||
}
|
||||
|
||||
void SpkMainWindow::EnterCategoryList(int aCategoryId, int aPage)
|
||||
{
|
||||
// Asynchronously call category API
|
||||
using namespace SpkUtils;
|
||||
VerifySingleRequest(mCategoryAppListGetReply);
|
||||
QJsonObject reqData;
|
||||
QJsonDocument reqDoc;
|
||||
reqData.insert("type_id", QJsonValue(aCategoryId));
|
||||
reqData.insert("page", QJsonValue(aPage));
|
||||
reqDoc.setObject(reqData);
|
||||
mCategoryAppListGetReply = STORE->SendApiRequest("application/get_application_list", reqDoc);
|
||||
DeleteReplyLater(mCategoryAppListGetReply);
|
||||
connect(mCategoryAppListGetReply, &QNetworkReply::finished,
|
||||
this, &SpkMainWindow::CategoryListDataReceived);
|
||||
setCursor(Qt::BusyCursor);
|
||||
ui->PageAppList->SetCurrentCategory(aCategoryId); // AppList needs to remember current category
|
||||
}
|
||||
|
||||
void SpkMainWindow::CategoryListDataReceived()
|
||||
{
|
||||
QJsonValue retval;
|
||||
setCursor(Qt::ArrowCursor);
|
||||
int verify = SpkUtils::VerifyReplyJson(mCategoryAppListGetReply, retval);
|
||||
if(verify || !retval.isObject())
|
||||
{
|
||||
sErr(tr("Failed to load app list of category! Type=%1 Code=%2").arg(retval.type()).arg(verify));
|
||||
sNotify(tr("Failed to load app list of category! Type: %1 Code: %2").arg(retval.type()).arg(verify));
|
||||
return;
|
||||
}
|
||||
SwitchToPage(SpkUi::PgAppList);
|
||||
PopulateAppList(retval.toObject(), "");
|
||||
}
|
||||
|
||||
void SpkMainWindow::SearchKeyword(QString aKeyword, int aPage)
|
||||
{
|
||||
using namespace SpkUtils;
|
||||
VerifySingleRequest(mCategoryAppListGetReply);
|
||||
QJsonObject reqData;
|
||||
QJsonDocument reqDoc;
|
||||
reqData.insert("application_name", QJsonValue(aKeyword));
|
||||
reqData.insert("page", QJsonValue(aPage));
|
||||
reqDoc.setObject(reqData);
|
||||
mCategoryAppListGetReply = STORE->SendApiRequest("application/get_application_list", reqDoc);
|
||||
mCategoryAppListGetReply->setProperty("keyword", aKeyword);
|
||||
DeleteReplyLater(mCategoryAppListGetReply);
|
||||
connect(mCategoryAppListGetReply, &QNetworkReply::finished,
|
||||
this, &SpkMainWindow::SearchDataReceived);
|
||||
setCursor(Qt::BusyCursor);
|
||||
}
|
||||
|
||||
void SpkMainWindow::SearchDataReceived()
|
||||
{
|
||||
QJsonValue retval;
|
||||
setCursor(Qt::ArrowCursor);
|
||||
auto verify = SpkUtils::VerifyReplyJson(mCategoryAppListGetReply, retval);
|
||||
if(verify || !retval.isObject())
|
||||
{
|
||||
sErr(tr("Failed to search keyword! Type=%1 Code=%2").arg(retval.type()).arg(verify));
|
||||
sNotify(tr("Failed to search keyword! Type: %1 Code: %2").arg(retval.type()).arg(verify));
|
||||
return;
|
||||
}
|
||||
SwitchToPage(SpkUi::PgAppList);
|
||||
PopulateAppList(retval.toObject(), mCategoryAppListGetReply->property("keyword").toString());
|
||||
}
|
||||
|
||||
void SpkMainWindow::PopulateAppList(QJsonObject appData, QString &&keyword)
|
||||
{
|
||||
auto w = ui->PageAppList;
|
||||
w->ClearAll();
|
||||
static auto err =
|
||||
[](){
|
||||
sErr("Received invalid application list data!");
|
||||
SpkUiMessage::SendStoreNotification(tr("Received an invalid response. Please try again!"));
|
||||
return;
|
||||
};
|
||||
int pgCurrent, pgTotal, totalApps;
|
||||
|
||||
if(appData.contains("currentPage") && appData.value("currentPage").isDouble())
|
||||
pgCurrent = appData.value("currentPage").toInt();
|
||||
else return err();
|
||||
if(appData.contains("totalPages") && appData.value("totalPages").isDouble())
|
||||
pgTotal = appData.value("totalPages").toInt();
|
||||
else return err();
|
||||
if(appData.contains("count") && appData.value("count").isDouble())
|
||||
totalApps = appData.value("count").toInt();
|
||||
else return err();
|
||||
w->SetPageStatus(pgTotal, pgCurrent, totalApps, keyword);
|
||||
|
||||
if(!appData.contains("data") || !appData.value("data").isArray())
|
||||
return err();
|
||||
|
||||
auto apps = appData.value("data").toArray();
|
||||
|
||||
for(auto &&i : apps)
|
||||
{
|
||||
if(i.isObject())
|
||||
{
|
||||
auto j = i.toObject();
|
||||
QString pkgName, displayName, description, iconPath;
|
||||
int appid;
|
||||
if(j.contains("package") && j.value("package").isString())
|
||||
pkgName = j.value("package").toString();
|
||||
else continue;
|
||||
if(j.contains("application_name_zh") && j.value("application_name_zh").isString())
|
||||
displayName = j.value("application_name_zh").toString();
|
||||
else continue;
|
||||
if(j.contains("description") && j.value("description").isString())
|
||||
description = j.value("description").toString();
|
||||
else continue;
|
||||
if(j.contains("application_id") && j.value("application_id").isDouble())
|
||||
appid = j.value("application_id").toInt();
|
||||
else continue;
|
||||
if(j.contains("icons") && j.value("icons").isString())
|
||||
iconPath = j.value("icons").toString();
|
||||
else continue;
|
||||
|
||||
w->AddApplicationEntry(displayName, pkgName, description, iconPath, appid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpkMainWindow::EnterAppDetails(int aAppId)
|
||||
{
|
||||
using namespace SpkUtils;
|
||||
VerifySingleRequest(mAppDetailsGetReply);
|
||||
QJsonObject reqData;
|
||||
QJsonDocument reqDoc;
|
||||
reqData.insert("application_id", QJsonValue(aAppId));
|
||||
reqDoc.setObject(reqData);
|
||||
mAppDetailsGetReply = STORE->SendApiRequest("application/get_application_detail", reqDoc);
|
||||
DeleteReplyLater(mAppDetailsGetReply);
|
||||
connect(mAppDetailsGetReply, &QNetworkReply::finished,
|
||||
this, &SpkMainWindow::AppDetailsDataReceived);
|
||||
setCursor(Qt::BusyCursor);
|
||||
}
|
||||
|
||||
void SpkMainWindow::AppDetailsDataReceived()
|
||||
{
|
||||
QJsonValue retval;
|
||||
setCursor(Qt::ArrowCursor);
|
||||
auto verify = SpkUtils::VerifyReplyJson(mAppDetailsGetReply, retval);
|
||||
if(verify || !retval.isObject())
|
||||
{
|
||||
sErr(tr("Failed to open app details page! Type=%1 Code=%2").arg(retval.type()).arg(verify));
|
||||
sNotify(tr("Failed to open app details page! Type: %1 Code: %2").arg(retval.type()).arg(verify));
|
||||
return;
|
||||
}
|
||||
SwitchToPage(SpkUi::PgAppList);
|
||||
PopulateAppDetails(retval.toObject());
|
||||
}
|
||||
|
||||
void SpkMainWindow::PopulateAppDetails(QJsonObject appDetails)
|
||||
{
|
||||
QString pkgName, author, contributor, site, iconPath, arch, version, details, shortDesc, name,
|
||||
pkgPath;
|
||||
QStringList screenshots, tags;
|
||||
int packageSize;
|
||||
static auto err =
|
||||
[](){
|
||||
sErr("Received invalid application details!");
|
||||
SpkUiMessage::SendStoreNotification(tr("Received an invalid response. Please try again!"));
|
||||
return;
|
||||
};
|
||||
|
||||
if(appDetails.contains("package") && appDetails.value("package").isString())
|
||||
pkgName = appDetails.value("package").toString();
|
||||
else return err();
|
||||
if(appDetails.contains("application_name_zh") && appDetails.value("application_name_zh").isString())
|
||||
name = appDetails.value("application_name_zh").toString();
|
||||
else name = pkgName;
|
||||
if(appDetails.contains("version") && appDetails.value("version").isString())
|
||||
version = appDetails.value("version").toString();
|
||||
else return err();
|
||||
if(appDetails.contains("icons") && appDetails.value("icons").isString())
|
||||
iconPath= appDetails.value("icons").toString();
|
||||
if(appDetails.contains("author") && appDetails.value("author").isString())
|
||||
author = appDetails.value("author").toString();
|
||||
if(appDetails.contains("contributor") && appDetails.value("contributor").isString())
|
||||
contributor = appDetails.value("contributor").toString();
|
||||
if(appDetails.contains("website") && appDetails.value("website").isString())
|
||||
site = appDetails.value("website").toString();
|
||||
if(appDetails.contains("description") && appDetails.value("description").isString())
|
||||
shortDesc = appDetails.value("description").toString();
|
||||
if(appDetails.contains("more") && appDetails.value("more").isString())
|
||||
details = appDetails.value("more").toString();
|
||||
if(appDetails.contains("arch") && appDetails.value("arch").isString())
|
||||
arch = appDetails.value("arch").toString();
|
||||
if(appDetails.contains("size") && appDetails.value("size").isDouble())
|
||||
packageSize = appDetails.value("size").toInt();
|
||||
if(appDetails.contains("deb_url") && appDetails.value("deb_url").isString())
|
||||
pkgPath = appDetails.value("deb_url").toString();
|
||||
|
||||
QJsonArray imgs;
|
||||
if(appDetails.contains("img_urls") && appDetails.value("img_urls").isArray())
|
||||
imgs = appDetails.value("img_urls").toArray();
|
||||
if(!imgs.isEmpty())
|
||||
for(auto &&i : imgs)
|
||||
if(i.isString()) screenshots << i.toString();
|
||||
|
||||
QJsonArray tags_j;
|
||||
if(appDetails.contains("tags") && appDetails.value("tags").isArray())
|
||||
imgs = appDetails.value("tags").toArray();
|
||||
if(!tags_j.isEmpty())
|
||||
for(auto &&i : tags_j)
|
||||
if(i.isString()) tags << i.toString();
|
||||
|
||||
// Details string has a strangely appended LF. IDK but still should remove it.
|
||||
shortDesc = shortDesc.trimmed();
|
||||
|
||||
auto w = ui->PageAppDetails;
|
||||
w->mPkgName->setText(pkgName);
|
||||
w->mAppTitle->setText(name);
|
||||
w->mAppShortDesc->setText(shortDesc);
|
||||
w->mAppDescription->setText(details);
|
||||
w->mAuthor->SetValue(author);
|
||||
w->mContributor->SetValue(contributor);
|
||||
// w->mSite->SetValue(site); // Doesn't look good, I disabled it temporarily. Better solution?
|
||||
w->SetWebsiteLink(site);
|
||||
w->mArch->SetValue(arch);
|
||||
w->mSize->SetValue(SpkUtils::BytesToSize(packageSize));
|
||||
w->mVersion->setText(version);
|
||||
w->SetPackagePath(pkgPath);
|
||||
SwitchToPage(SpkUi::PgAppDetails);
|
||||
ui->AppDetailsItem->setHidden(false);
|
||||
ui->CategoryWidget->setCurrentItem(ui->AppDetailsItem);
|
||||
w->LoadAppResources(pkgName, iconPath, screenshots, tags);
|
||||
}
|
||||
|
||||
void SpkMainWindow::ReloadThemedUiIcons()
|
||||
{
|
||||
for(auto &i : mThemedUiIconReferences)
|
||||
i.first->SetIcon(SpkUi::GetThemedIcon(i.second), QSize { 20, 20 });
|
||||
}
|
||||
|
||||
// ==================== Main Window Initialization ====================
|
||||
|
||||
void SpkMainWindow::Initialize()
|
||||
{
|
||||
connect(ui->SidebarMgr, &SpkUi::SpkSidebarSelector::SwitchToPage,
|
||||
this, &SpkMainWindow::SwitchToPage);
|
||||
connect(ui->SidebarMgr, &SpkUi::SpkSidebarSelector::SwitchToCategory,
|
||||
this, &SpkMainWindow::EnterCategoryList);
|
||||
connect(ui->PageAppList, &SpkUi::SpkPageAppList::SwitchListPage,
|
||||
this, &SpkMainWindow::EnterCategoryList);
|
||||
connect(ui->PageAppList, &SpkUi::SpkPageAppList::SwitchSearchPage,
|
||||
this, &SpkMainWindow::SearchKeyword);
|
||||
connect(ui->SearchEdit, &QLineEdit::returnPressed,
|
||||
[=](){ emit SearchKeyword(ui->SearchEdit->text(), 1); });
|
||||
connect(ui->PageAppList, &SpkUi::SpkPageAppList::ApplicationClicked,
|
||||
this, &SpkMainWindow::EnterAppDetails);
|
||||
connect(ui->BtnDayNight, &QPushButton::clicked,
|
||||
this, &SpkMainWindow::SwitchDayNightTheme);
|
||||
if(SpkUi::States::IsUsingDtkPlugin)
|
||||
{
|
||||
connect(SpkUi::DtkPlugin, &SpkDtkPlugin::DarkLightThemeChanged,
|
||||
this, &SpkMainWindow::ReloadThemedUiIcons);
|
||||
}
|
||||
connect(ui->PageAppDetails, &SpkUi::SpkPageAppDetails::RequestDownload,
|
||||
ui->PageDownloads, &SpkUi::SpkPageDownloads::AddDownloadTask);
|
||||
connect(ui->PageHome->ui->btnReloadCategory, &QPushButton::clicked,
|
||||
this, &SpkMainWindow::RefreshCategoryData);
|
||||
|
||||
connect(&SpkUi::SpkUiMetaObject, &SpkUi::UiMetaObject::SetThemeButtonVisible,
|
||||
[=](bool visible)
|
||||
{
|
||||
ui->BtnDayNight->setVisible(visible);
|
||||
ReloadThemedUiIcons();
|
||||
});
|
||||
|
||||
// Register themed button icons
|
||||
// mThemedUiIconReferences.append({ ui->BtnSettings, "settings" });
|
||||
mThemedUiIconReferences.append({ ui->BtnDayNight, "daynight" });
|
||||
|
||||
ReloadThemedUiIcons();
|
||||
}
|
||||
|
||||
// ==================== Main Widget Initialization ====================
|
||||
|
||||
SpkUi::SpkMainWidget::SpkMainWidget(QWidget *parent) : QFrame(parent)
|
||||
{
|
||||
setObjectName("spk_mainwidget");
|
||||
|
||||
Pager = new QStackedWidget(this);
|
||||
Pager->setObjectName("spk_mw_pager");
|
||||
Pager->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
|
||||
SidebarMgr = new SpkSidebarSelector(this);
|
||||
SidebarMgr->setObjectName("spk_mw_sidebar_mgr");
|
||||
|
||||
BtnSettings = new SpkIconButton(this);
|
||||
BtnSettings->setObjectName("styPlainChkBtn");
|
||||
BtnSettings->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
BtnSettings->setCheckable(true);
|
||||
BtnSettings->setFixedSize({ 40, 40 });
|
||||
BtnSettings->SetIcon(QIcon(":/icons/settings.svg"), QSize(20, 20));
|
||||
BtnSettings->setProperty("spk_pageno", PgSettings);
|
||||
SidebarMgr->BindPageSwitcherButton(BtnSettings);
|
||||
|
||||
BtnDayNight = new SpkIconButton(this);
|
||||
BtnDayNight->setObjectName("styPlainChkBtn");
|
||||
BtnDayNight->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
BtnDayNight->setFixedSize({ 40, 40 });
|
||||
BtnDayNight->SetIcon(QIcon(":/icons/daynight.svg"), QSize(20, 20));
|
||||
|
||||
BtnBack = new SpkIconButton(this);
|
||||
BtnBack->setFixedSize({ 40, 40 });
|
||||
BtnBack->SetIcon(QIcon(":/icons/back.svg"), QSize(20, 20));
|
||||
BtnBack->setVisible(false);
|
||||
|
||||
using SpkUi::SpkSidebarSelector;
|
||||
CategoryWidget = new SpkSidebarTree(this);
|
||||
CategoryWidget->setObjectName("styMwCateg");
|
||||
CategoryWidget->setAutoFillBackground(true);
|
||||
CategoryWidget->setColumnCount(1);
|
||||
CategoryWidget->setHeaderHidden(true);
|
||||
CategoryWidget->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection);
|
||||
CategoryWidget->setFixedWidth(200);
|
||||
|
||||
//============ Sidebar entries BEGIN ============
|
||||
HomepageItem = new QTreeWidgetItem(QStringList(tr("Home")));
|
||||
HomepageItem->setData(0, SpkSidebarSelector::RoleItemIsCategory, false);
|
||||
HomepageItem->setData(0, SpkSidebarSelector::RoleItemCategoryPageId, SpkStackedPages::PgHomepage);
|
||||
|
||||
AppDetailsItem = new QTreeWidgetItem(QStringList(tr("App Details")));
|
||||
AppDetailsItem->setData(0, SpkSidebarSelector::RoleItemIsCategory, false);
|
||||
AppDetailsItem->setData(0, SpkSidebarSelector::RoleItemCategoryPageId, SpkStackedPages::PgAppDetails);
|
||||
|
||||
CategoryParentItem = new QTreeWidgetItem(QStringList(tr("Categories")));
|
||||
CategoryParentItem->setFlags(CategoryParentItem->flags().setFlag(Qt::ItemIsSelectable, false));
|
||||
|
||||
DownloadsItem = new QTreeWidgetItem(QStringList(tr("Downloads")));
|
||||
DownloadsItem->setData(0, SpkSidebarSelector::RoleItemIsCategory, false);
|
||||
DownloadsItem->setData(0, SpkSidebarSelector::RoleItemCategoryPageId, SpkStackedPages::PgDownloads);
|
||||
#ifndef NDEBUG
|
||||
UiTestItem = new QTreeWidgetItem(QStringList(tr("UI TEST")));
|
||||
UiTestItem->setData(0, SpkSidebarSelector::RoleItemIsCategory, false);
|
||||
UiTestItem->setData(0, SpkSidebarSelector::RoleItemCategoryPageId, SpkStackedPages::PgQssTest);
|
||||
#endif
|
||||
//============ Sidebar entries END ============
|
||||
|
||||
CategoryWidget->addTopLevelItem(HomepageItem);
|
||||
SidebarMgr->AddUnusableItem(CategoryParentItem);
|
||||
CategoryWidget->addTopLevelItem(AppDetailsItem);
|
||||
CategoryWidget->addTopLevelItem(CategoryParentItem);
|
||||
CategoryWidget->addTopLevelItem(DownloadsItem);
|
||||
CategoryWidget->addTopLevelItem(UiTestItem);
|
||||
|
||||
CategoryWidget->setFocusPolicy(Qt::NoFocus);
|
||||
|
||||
// Must be done after added into a view.
|
||||
AppDetailsItem->setHidden(true); // Hide until we actually open up a Details page
|
||||
CategoryParentItem->setExpanded(true);
|
||||
|
||||
// FIXMEIFPOSSIBLE: Fusion adds extra gradient.
|
||||
// Details: https://forum.qt.io/topic/128190/fusion-style-kept-adding-an-extra-
|
||||
// layer-of-gradient-to-my-selected-item-of-qtreewidget-even-with-qss
|
||||
if(SpkUi::OldSystemStyle)
|
||||
CategoryWidget->setStyle(SpkUi::OldSystemStyle);
|
||||
SidebarMgr->BindCategoryWidget(CategoryWidget);
|
||||
|
||||
HorizontalDivide = new QHBoxLayout;
|
||||
HorizontalDivide->setObjectName("spk_mw_divide_hlay");
|
||||
HorizontalDivide->setSpacing(0);
|
||||
HorizontalDivide->setContentsMargins(0, 0, 0, 0);
|
||||
HorizontalDivide->setAlignment(Qt::AlignLeft);
|
||||
if(!SpkUi::States::IsUsingDtkPlugin)
|
||||
HorizontalDivide->addSpacing(SpkWindow::BorderWidth);
|
||||
HorizontalDivide->addWidget(CategoryWidget);
|
||||
HorizontalDivide->addWidget(Pager);
|
||||
|
||||
//============ Search Bar ============
|
||||
|
||||
SearchEdit = new SpkFocusLineEdit(this);
|
||||
SearchEdit->setPlaceholderText(tr("Press Enter to search"));
|
||||
SearchEdit->setFixedWidth(30);
|
||||
SearchEdit->setFixedHeight(30);
|
||||
SearchBarAnim = new QTimeLine(300, this);
|
||||
SearchBarAnim->setDuration(300);
|
||||
SearchBarAnim->setEasingCurve(QEasingCurve::OutExpo);
|
||||
SearchBarAnim->setUpdateInterval(20);
|
||||
ActClearSearchBar = SearchEdit->addAction(QIcon(":/icons/clear-input.svg"),
|
||||
QLineEdit::TrailingPosition);
|
||||
ActClearSearchBar->setVisible(false); // Invisible by default
|
||||
ActSearchIcon = SearchEdit->addAction(QIcon(":/icons/search-mini.svg"), QLineEdit::LeadingPosition);
|
||||
connect(SearchEdit, &SpkFocusLineEdit::focusGained,
|
||||
[=](){
|
||||
ActClearSearchBar->setVisible(true);
|
||||
SearchBarAnim->setDirection(QTimeLine::Forward);
|
||||
SearchBarAnim->start();
|
||||
});
|
||||
connect(SearchEdit, &SpkFocusLineEdit::focusLost,
|
||||
[=](){
|
||||
ActClearSearchBar->setVisible(false);
|
||||
SearchBarAnim->setDirection(QTimeLine::Backward);
|
||||
SearchBarAnim->start();
|
||||
});
|
||||
connect(SearchBarAnim, &QTimeLine::valueChanged,
|
||||
[=](qreal v){
|
||||
SearchEdit->setFixedWidth(static_cast<int>(250 * v) + 30);
|
||||
});
|
||||
connect(ActClearSearchBar, &QAction::triggered, [=](){ SearchEdit->clear(); });
|
||||
connect(BtnBack, &QPushButton::clicked,
|
||||
[=](){
|
||||
SidebarMgr->GoBack();
|
||||
BtnBack->setEnabled(false);
|
||||
});
|
||||
|
||||
auto space = static_cast<SpkWindow*>(parent)->GetTitleBar()->GetUserSpace();
|
||||
|
||||
space->addSpacing(50);
|
||||
space->addWidget(BtnDayNight);
|
||||
space->addWidget(BtnSettings);
|
||||
space->addWidget(BtnBack);
|
||||
space->addWidget(SearchEdit);
|
||||
space->addStretch();
|
||||
|
||||
|
||||
//============ Pages =============
|
||||
|
||||
// Red-Black tree based map will be able to sort things. Just for convenience of ordering pages.
|
||||
QMap<SpkStackedPages, QWidget*> sorter;
|
||||
|
||||
// Initialize pages
|
||||
PageAppList = new SpkUi::SpkPageAppList(this);
|
||||
PageAppList->setProperty("spk_pageid", SpkStackedPages::PgAppList);
|
||||
sorter[PgAppList] = PageAppList;
|
||||
|
||||
PageAppDetails = new SpkUi::SpkPageAppDetails(this);
|
||||
PageAppDetails->setProperty("spk_pageid", SpkStackedPages::PgAppDetails);
|
||||
sorter[PgAppDetails] = PageAppDetails;
|
||||
|
||||
PageDownloads = new SpkUi::SpkPageDownloads(this);
|
||||
PageDownloads->setProperty("spk_pageid", SpkStackedPages::PgDownloads);
|
||||
sorter[PgDownloads] = PageDownloads;
|
||||
|
||||
PageSettings = new SpkUi::SpkPageSettings(this);
|
||||
PageSettings->setProperty("spk_pageid", SpkStackedPages::PgSettings);
|
||||
sorter[PgSettings] = PageSettings;
|
||||
|
||||
PageHome = new SpkUi::SpkPageHome(this);
|
||||
PageSettings->setProperty("spk_pageid", SpkStackedPages::PgHomepage);
|
||||
sorter[PgHomepage] = PageHome;
|
||||
|
||||
#ifndef NDEBUG // If only in debug mode should we initialize QSS test page
|
||||
PageQssTest = new SpkUi::SpkPageUiTest(this);
|
||||
PageQssTest->setProperty("spk_pageid", SpkStackedPages::PgQssTest);
|
||||
sorter[PgQssTest] = PageQssTest;
|
||||
#endif
|
||||
|
||||
for(auto i : sorter)
|
||||
Pager->addWidget(i);
|
||||
|
||||
// Default page selection : homepage
|
||||
HomepageItem->setSelected(true);
|
||||
// Manually "activate" the default page item to make the sidebar tree know about default item
|
||||
emit CategoryWidget->itemPressed(HomepageItem, 0);
|
||||
|
||||
setLayout(HorizontalDivide);
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
|
||||
#include <QScrollArea>
|
||||
#include <QDebug>
|
||||
#include <QGuiApplication>
|
||||
#include <QScreen>
|
||||
#include "spkui_general.h"
|
||||
#include "spkmainwindow.h"
|
||||
#include "spkmsgbox.h"
|
||||
#include "spkstore.h"
|
||||
|
||||
// Suppress unwanted Clazy check warnings
|
||||
// clazy:excludeall=connect-3arg-lambda,lambda-in-connect
|
||||
|
||||
const QSize SpkMsgBox::IconSize; // I don't know why I need it, compiler wants that
|
||||
|
||||
SpkMsgBox::SpkMsgBox(QWidget *parent)
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
|
||||
}
|
||||
|
||||
int SpkMsgBox::StaticExec(QString msg, QString title, QMessageBox::Icon icon,
|
||||
QMessageBox::StandardButtons buttons, QString extra, bool expanded)
|
||||
{
|
||||
SpkMsgBox *b = new SpkMsgBox(SpkStore::Instance->GetRootWindow());
|
||||
QWidget *wMsgWidget = new QWidget;
|
||||
QHBoxLayout *wMsg = new QHBoxLayout(wMsgWidget);
|
||||
QPushButton *wExpandBtn;
|
||||
QScrollArea *wExtraArea;
|
||||
QLabel *wMsgText = new QLabel,
|
||||
*wExtraInfo,
|
||||
*wIcon;
|
||||
int InitialHeight;
|
||||
bool hasextra = extra.length() != 0;
|
||||
|
||||
if(icon)
|
||||
{
|
||||
wIcon = new QLabel;
|
||||
QIcon icon_;
|
||||
switch(icon)
|
||||
{
|
||||
case QMessageBox::Critical:
|
||||
icon_ = QIcon::fromTheme("dialog-error");
|
||||
break;
|
||||
case QMessageBox::Warning:
|
||||
icon_ = QIcon::fromTheme("dialog-warning");
|
||||
break;
|
||||
case QMessageBox::Information:
|
||||
icon_ = QIcon::fromTheme("dialog-information");
|
||||
break;
|
||||
case QMessageBox::Question:
|
||||
icon_ = QIcon::fromTheme("dialog-question");
|
||||
break;
|
||||
case QMessageBox::NoIcon:
|
||||
break;
|
||||
}
|
||||
if(icon)
|
||||
wIcon->setPixmap(icon_.pixmap(IconSize));
|
||||
wMsg->addWidget(wIcon);
|
||||
}
|
||||
wMsgText->setText(msg);
|
||||
wMsgText->setAlignment(Qt::AlignLeft);
|
||||
wMsg->addWidget(wMsgText);
|
||||
wMsg->setSpacing(10);
|
||||
wMsgWidget->setLayout(wMsg);
|
||||
b->AddWidget(wMsgWidget);
|
||||
b->GetTitleBar()->SetTitle(title);
|
||||
b->GetTitleBar()->SetOperationButton(SpkTitleBar::OperationButton::Close);
|
||||
b->SetResizable(false);
|
||||
b->SetCentralMargin(Margin, Margin, Margin, Margin);
|
||||
b->setMaximumSize(SpkUi::PrimaryScreenSize * 0.6);
|
||||
|
||||
if(hasextra)
|
||||
{
|
||||
wExpandBtn = new QPushButton;
|
||||
wExtraInfo = new QLabel;
|
||||
wExtraArea = new QScrollArea;
|
||||
wExtraInfo->setText(extra);
|
||||
wExtraArea->setWidget(wExtraInfo);
|
||||
wExtraArea->setVisible(false);
|
||||
wExtraArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
wExpandBtn->setText(tr("Details"));
|
||||
wExpandBtn->setMaximumWidth(100);
|
||||
wExpandBtn->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||
wExpandBtn->setCheckable(true);
|
||||
wExpandBtn->setObjectName("styChkBtn");
|
||||
connect(wExpandBtn, &QPushButton::clicked,
|
||||
[&](){ // FIXME: hint doesn't change when visibility changes, this is a quirky hack
|
||||
wExtraArea->setVisible(wExpandBtn->isChecked());
|
||||
if(wExpandBtn->isChecked())
|
||||
b->setFixedHeight(b->sizeHint().height());
|
||||
else
|
||||
b->setFixedHeight(InitialHeight);
|
||||
});
|
||||
b->mBtnLay->addWidget(wExpandBtn);
|
||||
b->mBtnLay->addStretch();
|
||||
b->AddWidget(wExtraArea);
|
||||
}
|
||||
|
||||
b->AddSpacing(3);
|
||||
AddButtons(b, buttons);
|
||||
if(hasextra)
|
||||
{
|
||||
b->mBtnLay->addStretch(); // Keep conventional buttons centered
|
||||
if(expanded)
|
||||
emit wExpandBtn->clicked();
|
||||
}
|
||||
InitialHeight = b->minimumSizeHint().height();
|
||||
auto pos = (SpkUi::PrimaryScreenSize - b->sizeHint()) / 2;
|
||||
b->move(pos.width(), pos.height());
|
||||
b->setWindowModality(Qt::ApplicationModal);
|
||||
b->setFixedSize(b->sizeHint());
|
||||
|
||||
auto r = b->Exec();
|
||||
if(r != -1)
|
||||
r = b->mButtonList[r]; // Retrieve the correct button
|
||||
|
||||
delete b;
|
||||
return r;
|
||||
}
|
||||
|
||||
void SpkMsgBox::AddButtons(SpkMsgBox *me, QMessageBox::StandardButtons b)
|
||||
{
|
||||
// If anyone can do it better, please let me know, I wrote this on the airplane
|
||||
using btn = QMessageBox::StandardButton;
|
||||
if(!b) return;
|
||||
if(b.testFlag(btn::Ok)) { me->AddButton(tr("OK")); me->mButtonList << btn::Ok; };
|
||||
if(b.testFlag(btn::Cancel)) { me->AddButton(tr("Cancel")); me->mButtonList << btn::Cancel; };
|
||||
if(b.testFlag(btn::Yes)) { me->AddButton(tr("Yes")); me->mButtonList << btn::Yes; };
|
||||
if(b.testFlag(btn::No)) { me->AddButton(tr("No")); me->mButtonList << btn::No; };
|
||||
if(b.testFlag(btn::Apply)) { me->AddButton(tr("Apply")); me->mButtonList << btn::Apply; };
|
||||
if(b.testFlag(btn::Reset)) { me->AddButton(tr("Reset")); me->mButtonList << btn::Reset; };
|
||||
if(b.testFlag(btn::Abort)) { me->AddButton(tr("Abort")); me->mButtonList << btn::Abort; };
|
||||
if(b.testFlag(btn::Retry)) { me->AddButton(tr("Retry")); me->mButtonList << btn::Retry; };
|
||||
if(b.testFlag(btn::Ignore)) { me->AddButton(tr("Ignore")); me->mButtonList << btn::Ignore; };
|
||||
if(b.testFlag(btn::Reset)) { me->AddButton(tr("Reset")); me->mButtonList << btn::Reset; };
|
||||
if(b.testFlag(btn::Close)) { me->AddButton(tr("Close")); me->mButtonList << btn::Close; };
|
||||
if(b.testFlag(btn::Open)) { me->AddButton(tr("Open")); me->mButtonList << btn::Open; };
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
|
||||
#include <QPaintEvent>
|
||||
#include <QPainter>
|
||||
#include <QBrush>
|
||||
#include "spknotifydot.h"
|
||||
#include "spkstore.h"
|
||||
|
||||
/*
|
||||
* The font size and the actual geometry of this widget is hard coded
|
||||
* If you want to use this widget code please consider improving it
|
||||
*/
|
||||
|
||||
SpkNotifyDot::SpkNotifyDot(QWidget *parent) :
|
||||
QLabel(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SpkNotifyDot::paintEvent(QPaintEvent *e)
|
||||
{
|
||||
QPainter p(this);
|
||||
|
||||
int h = height();
|
||||
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
p.setBrush(QBrush(QColor(255, 70, 50)));
|
||||
p.setPen(Qt::transparent);
|
||||
p.drawEllipse(0, 0, h, h);
|
||||
p.setBrush(QBrush(QColor(Qt::white)));
|
||||
p.setPen(Qt::white);
|
||||
p.setFont(QFont("sansserif", 10, 1000));
|
||||
p.drawText(QRect(0, 0, h, h), Qt::AlignHCenter | Qt::AlignVCenter, text());
|
||||
|
||||
p.end();
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
|
||||
#include "spkpopup.h"
|
||||
#include <QDebug>
|
||||
|
||||
namespace SpkUi
|
||||
{
|
||||
SpkPopup::SpkPopup(QWidget *parent, int aMillis) : QWidget(parent)
|
||||
{
|
||||
setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
setWindowFlags(Qt::FramelessWindowHint);
|
||||
mText = new QLabel();
|
||||
mText->setStyleSheet("border-radius: 11px;"
|
||||
"background-color: rgba(0,0,0,150);"
|
||||
"color: white;"
|
||||
"padding: 5px;");
|
||||
mText->setText(tr("(No Text)"));
|
||||
mBox = new QHBoxLayout(this);
|
||||
mBox->addWidget(mText);
|
||||
mBox->setContentsMargins(0, 0, 0, 0);
|
||||
// The reason why we contain it in a widget is that, if we want a QLabel have rounded corners,
|
||||
// then it must be able to be displayed with a translucent background. However, setting
|
||||
// Qt::WA_TranslucentBackground will cause the entire background of QLabel transparent.
|
||||
// Therefore we need a container (SpkPopup) with a transparent background as the canvas layer
|
||||
// of the actual displayed text.
|
||||
mAnim = new QSequentialAnimationGroup(this);
|
||||
|
||||
// Disabled as translucency doesn't work well on every platform :(
|
||||
// mAnimFadeIn = new QPropertyAnimation(this, "windowOpacity");
|
||||
// mAnimFadeOut = new QPropertyAnimation(this, "windowOpacity");
|
||||
// mAnimFadeIn->setStartValue(0.0);
|
||||
// mAnimFadeIn->setEndValue(1.0);
|
||||
// mAnimFadeOut->setStartValue(1.0);
|
||||
// mAnimFadeOut->setEndValue(0.0);
|
||||
// Using moving animation instead
|
||||
mAnimFadeIn = new QPropertyAnimation(this, "pos");
|
||||
mAnimFadeOut = new QPropertyAnimation(this, "pos");
|
||||
mAnimFadeIn->setDuration(250);
|
||||
mAnimFadeOut->setDuration(250);
|
||||
mAnimFadeIn->setEasingCurve(QEasingCurve::InQuad);
|
||||
mAnimFadeOut->setEasingCurve(QEasingCurve::InQuad);
|
||||
|
||||
mAnim->addAnimation(mAnimFadeIn);
|
||||
mAnim->addPause(aMillis);
|
||||
mAnim->addAnimation(mAnimFadeOut);
|
||||
setVisible(false);
|
||||
|
||||
connect(mAnim, &QAnimationGroup::stateChanged,
|
||||
[=](QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
|
||||
{
|
||||
// qDebug() << "OldState" << oldState << "NewState" << newState;
|
||||
if(newState == QAbstractAnimation::Stopped)
|
||||
setVisible(false);
|
||||
});
|
||||
}
|
||||
|
||||
void SpkPopup::Show(QString aText)
|
||||
{
|
||||
if(mAnim->state() == QSequentialAnimationGroup::Running)
|
||||
mAnim->stop();
|
||||
QSize parentSize = parentWidget()->size();
|
||||
mText->setText(aText);
|
||||
adjustSize();
|
||||
move(QPoint((parentSize.width() - width()) / 2, parentSize.height() - height() - 30)/* +
|
||||
parentWidget()->pos()*/);
|
||||
setMaximumWidth(parentSize.width() - 200);
|
||||
setWindowOpacity(1);
|
||||
show();
|
||||
|
||||
mAnimFadeIn->setStartValue(QPoint((parentSize.width() - width()) / 2,
|
||||
parentSize.height() + height()));
|
||||
mAnimFadeIn->setEndValue(QPoint((parentSize.width() - width()) / 2,
|
||||
parentSize.height() - height() - 80));
|
||||
mAnimFadeOut->setStartValue(QPoint((parentSize.width() - width()) / 2,
|
||||
parentSize.height() - height() - 80));
|
||||
mAnimFadeOut->setEndValue(QPoint((parentSize.width() - width()) / 2,
|
||||
parentSize.height() + height()));
|
||||
|
||||
qDebug() << "Popup size " << size() << "position" << pos() << "parent size" << parentWidget()->size();
|
||||
mAnim->start();
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
|
||||
#include "spkqsshelper.h"
|
||||
|
||||
const std::list<SpkUi::Qss::ColorSetIndex> SpkUi::Qss::AccentColorExceptions
|
||||
{
|
||||
AccentColor,
|
||||
AccentColorHighlighted,
|
||||
TextOnAccentColor,
|
||||
};
|
||||
|
||||
const std::map<SpkUi::Qss::ColorSetIndex, const char *> SpkUi::Qss::ColorSet2Token
|
||||
{
|
||||
{ GlobalBgnd, "GBG_" },
|
||||
{ ControlsBgnd, "CBG_" },
|
||||
{ ControlsBgndHighlighted, "CBGH" },
|
||||
{ SelectionBgnd, "ACC_" },
|
||||
{ SelectionBgndHighlighted, "ACCH" },
|
||||
{ LightCtrlsGradLight, "LCTL1" },
|
||||
{ LightCtrlsGradDark, "LCTL2" },
|
||||
{ LightCtrlsGradDarker, "LCTL3" },
|
||||
{ LightCtrlsDisabledBackground, "LCTLD" },
|
||||
{ DarkCtrlsGradLight, "DCTL1" },
|
||||
{ DarkCtrlsGradDark, "DCTL2" },
|
||||
{ DarkCtrlsGradDarker, "DCTL3" },
|
||||
{ DarkCtrlsDisabledBackground, "DCTLD" },
|
||||
{ TextOnSelection, "TXACC" },
|
||||
{ TextOnGlobalBgnd, "TXGBG" },
|
||||
{ TextOnControlsBgnd, "TXCBG" },
|
||||
{ TextLighter, "TXL1" },
|
||||
{ TextEvenLighter, "TXL2" },
|
||||
{ TextDisabled, "TXD" },
|
||||
{ GlossyEdge, "GLS" },
|
||||
{ ShadesEdge, "SHD" },
|
||||
{ ScrollBarNorm, "SCBN" },
|
||||
{ ScrollBarHover, "SCBH" },
|
||||
{ DivideLine, "DVL" },
|
||||
};
|
||||
|
||||
const std::map<SpkUi::Qss::ColorSetIndex, QColor> SpkUi::Qss::DarkColorSet
|
||||
{
|
||||
{ GlobalBgnd, 0x282828 },
|
||||
{ ControlsBgnd, 0x323232 },
|
||||
{ ControlsBgndHighlighted, 0xff0000 },
|
||||
{ SelectionBgnd, 0x0070ff },
|
||||
{ SelectionBgndHighlighted, QColor(0x0070ff).lighter(120) },
|
||||
{ LightCtrlsGradLight, 0x6b6b6b },
|
||||
{ LightCtrlsGradDark, 0x656565 },
|
||||
{ LightCtrlsGradDarker, 0x606060 },
|
||||
{ LightCtrlsDisabledBackground, 0x808080 },
|
||||
{ DarkCtrlsGradLight, 0x404040 },
|
||||
{ DarkCtrlsGradDark, 0x383838 },
|
||||
{ DarkCtrlsGradDarker, 0x323232 },
|
||||
{ DarkCtrlsDisabledBackground, 0x525252 },
|
||||
{ TextOnSelection, ColorTextOnBackground(0x0070ff) },
|
||||
{ TextOnGlobalBgnd, ColorTextOnBackground(0x282828) },
|
||||
{ TextOnControlsBgnd, ColorTextOnBackground(0x282828) },
|
||||
{ TextLighter, 0xd5d5d5 },
|
||||
{ TextEvenLighter, 0x505050 },
|
||||
{ TextDisabled, 0xbebebe },
|
||||
{ GlossyEdge, 0x656565 },
|
||||
{ ShadesEdge, 0x7b7b7b },
|
||||
{ ScrollBarNorm, 0x404040 },
|
||||
{ ScrollBarHover, 0x656565 },
|
||||
{ DivideLine, 0x424242 },
|
||||
};
|
||||
|
||||
const std::map<SpkUi::Qss::ColorSetIndex, QColor> SpkUi::Qss::LightColorSet
|
||||
{
|
||||
{ GlobalBgnd, 0xf8f8f8 },
|
||||
{ ControlsBgnd, 0xf8f8f8 },
|
||||
{ ControlsBgndHighlighted, 0xff0000 },
|
||||
{ SelectionBgnd, 0x0070ff },
|
||||
{ SelectionBgndHighlighted, QColor(0x0070ff).lighter(120) },
|
||||
{ LightCtrlsGradLight, 0xfbfbfb },
|
||||
{ LightCtrlsGradDark, 0xf2f2f2 },
|
||||
{ LightCtrlsGradDarker, 0xebebeb },
|
||||
{ LightCtrlsDisabledBackground, 0xe0e0e0 },
|
||||
{ DarkCtrlsGradLight, 0xe4e4e4 },
|
||||
{ DarkCtrlsGradDark, 0xcecece },
|
||||
{ DarkCtrlsGradDarker, 0xb8b8b8 },
|
||||
{ DarkCtrlsDisabledBackground, 0xababab },
|
||||
{ TextOnSelection, ColorTextOnBackground(0x0070ff) },
|
||||
{ TextOnGlobalBgnd, ColorTextOnBackground(0xf8f8f8) },
|
||||
{ TextOnControlsBgnd, ColorTextOnBackground(0xf8f8f8) },
|
||||
{ TextLighter, 0x2a2a2a },
|
||||
{ TextEvenLighter, 0xa0a0a0 },
|
||||
{ TextDisabled, 0x8a8a8a },
|
||||
{ GlossyEdge, 0x9d9d9d },
|
||||
{ ShadesEdge, 0xc5c5c5 },
|
||||
{ ScrollBarNorm, 0xa0a0a0 },
|
||||
{ ScrollBarHover, 0x858585 },
|
||||
{ DivideLine, 0xd5d5d5 },
|
||||
};
|
||||
@@ -1,31 +0,0 @@
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include "spksidebartree.h"
|
||||
|
||||
SpkUi::SpkSidebarTree::SpkSidebarTree(QWidget *parent) :
|
||||
QTreeWidget(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SpkUi::SpkSidebarTree::mouseMoveEvent(QMouseEvent *e)
|
||||
{
|
||||
// This is solely for forcibly disabling the view to change selection when dragging on the view
|
||||
// and probably the only reason why this class began its existence
|
||||
if((e->buttons() & Qt::LeftButton))
|
||||
setState(NoState);
|
||||
else
|
||||
QTreeWidget::mouseMoveEvent(e);
|
||||
}
|
||||
|
||||
void SpkUi::SpkSidebarTree::mousePressEvent(QMouseEvent *e)
|
||||
{
|
||||
// Prevent anything being deselected
|
||||
if(e->modifiers().testFlag(Qt::ControlModifier) && e->buttons().testFlag(Qt::LeftButton))
|
||||
{
|
||||
auto i = itemAt(e->pos());
|
||||
if(i && i->isSelected())
|
||||
return;
|
||||
}
|
||||
QTreeWidget::mousePressEvent(e);
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
|
||||
#include "spkstretchlayout.h"
|
||||
|
||||
SpkStretchLayout::SpkStretchLayout(QWidget *parent) : QLayout(parent)
|
||||
{
|
||||
}
|
||||
|
||||
SpkStretchLayout::~SpkStretchLayout()
|
||||
{
|
||||
QLayoutItem *item;
|
||||
while((item = takeAt(0)))
|
||||
delete item;
|
||||
}
|
||||
|
||||
void SpkStretchLayout::addItem(QLayoutItem *item)
|
||||
{
|
||||
mItems.append(item);
|
||||
}
|
||||
|
||||
QSize SpkStretchLayout::sizeHint() const
|
||||
{
|
||||
if(mItems.isEmpty())
|
||||
return { 300, 300 };
|
||||
auto w = geometry().width() - spacing();
|
||||
auto it = mItems.first();
|
||||
int countPerLine = w / (it->minimumSize().width() + spacing());
|
||||
int lines = ceil((double)mItems.size() / countPerLine);
|
||||
auto h = static_cast<int>(it->minimumSize().height() * lines + spacing() * lines);
|
||||
return { w, h };
|
||||
}
|
||||
|
||||
QSize SpkStretchLayout::minimumSize() const
|
||||
{
|
||||
// It works this way, but I honestly have no idea WHY IT WORKS
|
||||
auto r = sizeHint();
|
||||
r.setWidth(300);
|
||||
return r;
|
||||
}
|
||||
|
||||
int SpkStretchLayout::count() const
|
||||
{
|
||||
return mItems.size();
|
||||
}
|
||||
|
||||
QLayoutItem *SpkStretchLayout::itemAt(int i) const
|
||||
{
|
||||
return mItems.value(i);
|
||||
}
|
||||
|
||||
QLayoutItem *SpkStretchLayout::takeAt(int i)
|
||||
{
|
||||
return i >= 0 && i < mItems.size() ? mItems.takeAt(i) : nullptr;
|
||||
}
|
||||
|
||||
void SpkStretchLayout::setGeometry(const QRect &rect)
|
||||
{
|
||||
QLayout::setGeometry(rect);
|
||||
if(mItems.isEmpty())
|
||||
return;
|
||||
|
||||
int spc = spacing(), w = rect.width() - spc;
|
||||
QSize size;
|
||||
auto itm = mItems.first();
|
||||
|
||||
// All items are considered the same, so we only calculate with the first item.
|
||||
// Figure out how many at most can we squeeze into one line
|
||||
int countPerLine = w / (itm->minimumSize().width() + spacing());
|
||||
|
||||
if(countPerLine < 1)
|
||||
countPerLine = 1;
|
||||
|
||||
if(countPerLine >= mItems.size()) // All items fit in one line
|
||||
size = itm->minimumSize();
|
||||
// Won't fit in one line.
|
||||
else // Stretch items.
|
||||
size = QSize {(w / countPerLine - spc), itm->maximumSize().height() };
|
||||
|
||||
auto origin = geometry().topLeft();
|
||||
|
||||
QLayoutItem *o;
|
||||
for(int i = 0; i < mItems.size(); i++)
|
||||
{
|
||||
o = mItems.at(i);
|
||||
QRect geo;
|
||||
geo.setSize(size);
|
||||
geo.moveTo((i % countPerLine) * (size.width() + spc) + spc + origin.x(),
|
||||
(i / countPerLine) * (size.height() + spacing()) + spc + origin.y());
|
||||
o->setGeometry(geo);
|
||||
}
|
||||
|
||||
// qDebug() << rect;
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
|
||||
#include <QEvent>
|
||||
#include <QMouseEvent>
|
||||
#include "spkwindow.h"
|
||||
#include "spkui_general.h"
|
||||
#include "spktitlebar.h"
|
||||
|
||||
SpkTitleBar::SpkTitleBar(QWidget *parent) : QFrame(parent)
|
||||
{
|
||||
mLinkedWindow = nullptr;
|
||||
|
||||
setFixedHeight(Height);
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
|
||||
mIcon = new QLabel(this);
|
||||
mTitle = new QLabel(this);
|
||||
mIcon->setFixedSize(40, 40);
|
||||
|
||||
mMainLayout = new QHBoxLayout(this);
|
||||
mUserSpace = new QHBoxLayout();
|
||||
mBtnGroup = new QHBoxLayout();
|
||||
mBtnMin = new SpkTitleBarDefaultButton(this);
|
||||
mBtnMaxRestore = new SpkTitleBarDefaultButton(this);
|
||||
mBtnClose= new SpkTitleBarDefaultButton(this);
|
||||
mMainLayout->setSpacing(8);
|
||||
mBtnGroup->setSpacing(0);
|
||||
|
||||
mMainLayout->addSpacing(12);
|
||||
mMainLayout->addWidget(mIcon);
|
||||
mMainLayout->addWidget(mTitle);
|
||||
mMainLayout->addLayout(mUserSpace);
|
||||
mMainLayout->addLayout(mBtnGroup);
|
||||
mBtnGroup->addWidget(mBtnMin);
|
||||
mBtnGroup->addWidget(mBtnMaxRestore);
|
||||
mBtnGroup->addWidget(mBtnClose);
|
||||
|
||||
mBtnMin->SetRole(OperationButton::Minimize);
|
||||
mBtnMaxRestore->SetRole(OperationButton::MaximizeRestore);
|
||||
mBtnClose->SetRole(OperationButton::Close);
|
||||
|
||||
mMainLayout->setContentsMargins(0, 0, 0, 1);
|
||||
|
||||
setLayout(mMainLayout);
|
||||
|
||||
connect(mBtnClose, &QPushButton::clicked, this, &SpkTitleBar::CloseWindow);
|
||||
connect(mBtnMin, &QPushButton::clicked, this, &SpkTitleBar::MinimizeWindow);
|
||||
connect(mBtnMaxRestore, &QPushButton::clicked, this, &SpkTitleBar::MaximizeRestoreWindow);
|
||||
}
|
||||
|
||||
SpkTitleBar::~SpkTitleBar()
|
||||
{
|
||||
//qDebug() << "Freed title bar!";
|
||||
}
|
||||
|
||||
void SpkTitleBar::SetOperationButton(OperationButton type)
|
||||
{
|
||||
mBtnClose->setVisible(type & OperationButton::Close);
|
||||
mBtnMaxRestore->setVisible(type & OperationButton::MaximizeRestore);
|
||||
mBtnMin->setVisible(type & OperationButton::Minimize);
|
||||
}
|
||||
|
||||
bool SpkTitleBar::event(QEvent *evt)
|
||||
{
|
||||
switch(evt->type())
|
||||
{
|
||||
case QEvent::MouseButtonDblClick:
|
||||
{
|
||||
if(static_cast<QMouseEvent*>(evt)->button())
|
||||
emit mBtnMaxRestore->clicked();
|
||||
break;
|
||||
}
|
||||
default:;
|
||||
}
|
||||
return QWidget::event(evt);
|
||||
}
|
||||
|
||||
void SpkTitleBar::CloseWindow()
|
||||
{
|
||||
if(mLinkedWindow)
|
||||
mLinkedWindow->close();
|
||||
}
|
||||
|
||||
void SpkTitleBar::MinimizeWindow()
|
||||
{
|
||||
if(mLinkedWindow)
|
||||
mLinkedWindow->setWindowState(Qt::WindowMinimized);
|
||||
}
|
||||
|
||||
void SpkTitleBar::MaximizeRestoreWindow()
|
||||
{
|
||||
if(mLinkedWindow)
|
||||
{
|
||||
if(mLinkedWindow->windowState().testFlag(Qt::WindowMaximized))
|
||||
mLinkedWindow->setWindowState(mLinkedWindow->windowState() & ~Qt::WindowMaximized);
|
||||
else
|
||||
mLinkedWindow->setWindowState(Qt::WindowMaximized);
|
||||
}
|
||||
}
|
||||
|
||||
SpkTitleBarDefaultButton::SpkTitleBarDefaultButton(QWidget* parent) : QPushButton(parent)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
||||
setMaximumWidth(ButtonWidth);
|
||||
setMinimumWidth(ButtonWidth);
|
||||
setFocusPolicy(Qt::NoFocus);
|
||||
}
|
||||
|
||||
void SpkTitleBarDefaultButton::paintEvent(QPaintEvent *e)
|
||||
{
|
||||
QPushButton::paintEvent(e);
|
||||
QPainter painter;
|
||||
painter.begin(this);
|
||||
PaintSymbol(painter);
|
||||
painter.end();
|
||||
}
|
||||
|
||||
void SpkTitleBarDefaultButton::PaintSymbol(QPainter &p)
|
||||
{
|
||||
QPen pen(SpkUi::ColorLine);
|
||||
p.setPen(pen);
|
||||
auto mh = height() / 2, mw = width() / 2, h = height(), w = width();
|
||||
constexpr int fr = 10;
|
||||
switch(Role)
|
||||
{
|
||||
case Minimize:
|
||||
p.drawLine(mw - w / fr, mh, mw + w / fr, mh);
|
||||
break;
|
||||
case MaximizeRestore:
|
||||
p.drawRect(mw - w / fr, mh - h / fr,
|
||||
w / fr * 2, h / fr * 2);
|
||||
break;
|
||||
case Restore:
|
||||
p.drawRect(mw - w / fr - 2, mh - w / fr + 2, w / fr * 2, h / fr * 2);
|
||||
p.drawLine(mw - w / fr, mh - h / fr - 2, mw + w / fr, mh - h / fr - 2);
|
||||
p.drawLine(mw + w / fr, mh - h / fr - 2, mw + w / fr, mh + h / fr - 2);
|
||||
break;
|
||||
case Close:
|
||||
p.drawLine(mw - h / fr * 1.3, mh - h / fr * 1.3,
|
||||
mw + h / fr * 1.3, mh + h / fr * 1.3);
|
||||
p.drawLine(mw - h / fr * 1.3, mh + h / fr * 1.3,
|
||||
mw + h / fr * 1.3, mh - h / fr * 1.3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SpkTitleBarDefaultButton::SetRole(OperationButton role)
|
||||
{
|
||||
Role = role;
|
||||
}
|
||||
@@ -1,332 +0,0 @@
|
||||
//
|
||||
// Created by rigoligo on 2021/5/8.
|
||||
//
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QLibrary>
|
||||
#include <QDir>
|
||||
#include <QMessageBox>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QScreen>
|
||||
#include <QPluginLoader>
|
||||
#include <QStyleFactory>
|
||||
#include <csignal>
|
||||
#include <execinfo.h>
|
||||
|
||||
#include "spkui_general.h"
|
||||
#include "spkmsgbox.h"
|
||||
#include "spkpopup.h"
|
||||
#include "spklogging.h"
|
||||
#include "spkstore.h"
|
||||
#include "spkutils.h"
|
||||
|
||||
namespace SpkUi
|
||||
{
|
||||
UiMetaObject SpkUiMetaObject;
|
||||
SpkUiStyle CurrentStyle;
|
||||
QString StylesheetBase, CurrentStylesheet;
|
||||
QColor ColorLine, ColorBack, ColorBtnMaskSelected, ColorBtnMaskUnselected;
|
||||
QSize PrimaryScreenSize;
|
||||
SpkDtkPlugin *DtkPlugin = nullptr;
|
||||
QStyle *OldSystemStyle = nullptr;
|
||||
|
||||
std::map<Qss::ColorSetIndex, QColor> CurrentColorSet;
|
||||
|
||||
SpkPopup *Popup;
|
||||
|
||||
namespace States
|
||||
{
|
||||
bool IsDDE = false, IsUsingDtkPlugin = false;
|
||||
|
||||
bool DoRespondAutoTheme = false;
|
||||
int LightDarkMode = 3; // Default to Manual
|
||||
|
||||
bool ThemeConfigCallback()
|
||||
{
|
||||
switch(LightDarkMode)
|
||||
{
|
||||
case 0:
|
||||
if(!DtkPlugin) return false;
|
||||
SpkUiMetaObject.SetDarkLightTheme(DtkPlugin->GetIsDarkTheme());
|
||||
break;
|
||||
case 1:
|
||||
SetGlobalStyle(Light, true);
|
||||
SpkUiMetaObject.SetThemeButtonVisible(false);
|
||||
break;
|
||||
case 2:
|
||||
SetGlobalStyle(Dark, true);
|
||||
SpkUiMetaObject.SetThemeButtonVisible(false);
|
||||
break;
|
||||
case 3:
|
||||
SpkUiMetaObject.SetThemeButtonVisible(true);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Priv
|
||||
{
|
||||
bool CrashHandlerActivated;
|
||||
}
|
||||
|
||||
// ======================= Static Linkage Private Functions ========================
|
||||
|
||||
static void SetBtnMaskColor()
|
||||
{
|
||||
ColorBtnMaskUnselected = ColorTextOnBackground(CurrentColorSet[Qss::ControlsBgnd]);
|
||||
ColorBtnMaskSelected = ColorTextOnBackground(CurrentColorSet[Qss::AccentColor]);
|
||||
}
|
||||
|
||||
// ======================== Public Functions =========================
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
// Obtain global stylesheets
|
||||
QFile ObtainStylesheet;
|
||||
ObtainStylesheet.setFileName(CFG->ReadField("internal/qss_path",
|
||||
":/stylesheet/stylesheet/default.css")
|
||||
.toString());
|
||||
ObtainStylesheet.open(QIODevice::ReadOnly);
|
||||
StylesheetBase = ObtainStylesheet.readAll();
|
||||
ObtainStylesheet.close();
|
||||
|
||||
CurrentStyle = SpkUiStyle::Invalid;
|
||||
|
||||
#ifdef NDEBUG
|
||||
SetGlobalStyle(Light, false);
|
||||
#else
|
||||
SetGlobalStyle(qEnvironmentVariableIntValue("SPK_FORCE_DARK") ? Dark : Light, false);
|
||||
#endif
|
||||
|
||||
// Initalize crash handler
|
||||
signal(SIGSEGV, SpkUi::CrashSignalHandler);
|
||||
signal(SIGABRT, SpkUi::CrashSignalHandler);
|
||||
signal(SIGFPE, SpkUi::CrashSignalHandler);
|
||||
|
||||
// Prepare theme following for DDE
|
||||
if((States::IsDDE = CheckIsDeepinDesktop()))
|
||||
PrepareForDeepinDesktop();
|
||||
|
||||
// Misc data initialization
|
||||
PrimaryScreenSize = QGuiApplication::primaryScreen()->size();
|
||||
CFG->BindField("ui/theme", &States::LightDarkMode, 3, States::ThemeConfigCallback);
|
||||
}
|
||||
|
||||
void GuessAppropriateTheme()
|
||||
{
|
||||
// FIXME: Too difficult, not implementing it
|
||||
}
|
||||
|
||||
bool CheckIsDeepinDesktop()
|
||||
{
|
||||
QString Desktop(getenv("XDG_CURRENT_DESKTOP"));
|
||||
// This method of checking is from DTK source code.
|
||||
if(Desktop.contains("deepin", Qt::CaseInsensitive) ||
|
||||
Desktop.contains("tablet", Qt::CaseInsensitive))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void PrepareForDeepinDesktop()
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
qApp->addLibraryPath(qApp->applicationDirPath() + "/plugin/dtkplugin");
|
||||
#else
|
||||
// You must `make install' before these work in release mode
|
||||
qApp->addLibraryPath("/usr/local/lib");
|
||||
qApp->addLibraryPath("/usr/lib");
|
||||
#endif
|
||||
if(!qEnvironmentVariableIntValue("SPARK_NO_DTK_PLUGIN"))
|
||||
{
|
||||
QPluginLoader p("libspkdtkplugin");
|
||||
if(p.load())
|
||||
{
|
||||
auto i = qobject_cast<SpkDtkPlugin*>(p.instance());
|
||||
if(i)
|
||||
{
|
||||
DtkPlugin = i;
|
||||
States::IsUsingDtkPlugin = true;
|
||||
|
||||
i->Initialize();
|
||||
|
||||
SpkUiMetaObject.SetAccentColor(i->GetAccentColor()); // Match OS accent color
|
||||
SpkUiMetaObject.SetDarkLightTheme(i->GetIsDarkTheme()); // Match OS dark theme type
|
||||
|
||||
QObject::connect(i, &SpkDtkPlugin::AccentColorChanged,
|
||||
&SpkUiMetaObject, &UiMetaObject::SetAccentColor);
|
||||
QObject::connect(i, &SpkDtkPlugin::DarkLightThemeChanged,
|
||||
&SpkUiMetaObject, &UiMetaObject::SetDarkLightTheme);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Chameleon style kept adding unwanted blue focus indication border
|
||||
// to widgets that shouldn't have borders.
|
||||
// We need to eliminate this irritating problem.
|
||||
if(qEnvironmentVariableIntValue("SPARK_NO_QSTYLE_CHANGE"))
|
||||
return;
|
||||
OldSystemStyle = QStyleFactory::create("chameleon"); // TreeWidget doesn't work well with Fusion
|
||||
auto styles = QStyleFactory::keys();
|
||||
styles.removeAll("chameleon");
|
||||
if(styles.contains("Fusion"))
|
||||
{
|
||||
auto style = QStyleFactory::create("Fusion");
|
||||
qApp->setStyle(style);
|
||||
}
|
||||
else if(styles.size()) // What? This shouldn't happen.
|
||||
qApp->setStyle(QStyleFactory::create(styles[0]));
|
||||
else // Duh...
|
||||
sWarn(QObject::tr("Cannot find styles other than 'chameleon'! You may see widgets "
|
||||
"with unwanted blue borders."));
|
||||
}
|
||||
|
||||
void SetGlobalStyle(const SpkUiStyle aStyle, const bool aPreserveAccentColor)
|
||||
{
|
||||
if(aStyle == CurrentStyle) // Don't waste precious CPU time parsing new style sheet!
|
||||
return;
|
||||
CurrentStyle = aStyle;
|
||||
Qss::ColorSet tempset;
|
||||
switch(aStyle)
|
||||
{
|
||||
case Invalid:
|
||||
case Light:
|
||||
tempset = Qss::LightColorSet;
|
||||
ColorLine = Qt::black;
|
||||
break;
|
||||
case Dark:
|
||||
tempset = Qss::DarkColorSet;
|
||||
ColorLine = Qt::white;
|
||||
break;
|
||||
}
|
||||
if(aPreserveAccentColor)
|
||||
{
|
||||
for(auto i : Qss::AccentColorExceptions)
|
||||
tempset[i] = CurrentColorSet[i];
|
||||
}
|
||||
CurrentColorSet = tempset;
|
||||
CurrentStylesheet = StylesheetFromColors(CurrentColorSet);
|
||||
SetBtnMaskColor();
|
||||
qApp->setStyleSheet(CurrentStylesheet);
|
||||
}
|
||||
|
||||
QString WriteStackTrace(const QString &aStackTrace)
|
||||
{
|
||||
QString path = QDir::homePath() + "/.local/share/spark-store/crash/";
|
||||
QFile StackTraceFile;
|
||||
if(!QDir().exists(path))
|
||||
if(!QDir().mkpath(path))
|
||||
return QObject::tr("Stack trace directory %1 cannot be created. "
|
||||
"Stack trace wasn't saved.").arg(path);
|
||||
path += QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
|
||||
while(QFile::exists(path))
|
||||
path += "_";
|
||||
StackTraceFile.setFileName(path);
|
||||
StackTraceFile.open(QIODevice::WriteOnly);
|
||||
if(StackTraceFile.isOpen() && StackTraceFile.isWritable())
|
||||
{
|
||||
QTextStream StackTraceWriter;
|
||||
StackTraceWriter.setDevice(&StackTraceFile);
|
||||
StackTraceWriter << QDateTime::currentDateTime().toLocalTime().toString() << "\n\n";
|
||||
StackTraceWriter << aStackTrace;
|
||||
StackTraceFile.close();
|
||||
return QObject::tr("Stack trace written to \"%1\".").arg(path);
|
||||
}
|
||||
return QObject::tr("Stack trace file %1 cannot be opened. "
|
||||
"Stack trace wasn't saved.").arg(path);
|
||||
}
|
||||
|
||||
void CrashSignalHandler(int sig)
|
||||
{
|
||||
QString msg(QObject::tr("Program has received signal %1 during normal execution.\n\n")),
|
||||
trace;
|
||||
switch(sig)
|
||||
{
|
||||
case SIGSEGV:
|
||||
msg = msg.arg(QObject::tr("\"SIGSEGV\" (Segmentation fault)"));
|
||||
goto CRASH;
|
||||
case SIGFPE:
|
||||
msg = msg.arg(QObject::tr("\"SIGFPE\" (Arithmetic exception)"));
|
||||
goto CRASH;
|
||||
case SIGABRT:
|
||||
msg = msg.arg(QObject::tr("\"SIGABRT\" (Abort)"));
|
||||
CRASH:
|
||||
{
|
||||
if(Priv::CrashHandlerActivated) // If error occured in the handler...
|
||||
{
|
||||
signal(SIGABRT, SIG_DFL); // Return control flow to OS and give up
|
||||
raise(SIGABRT);
|
||||
exit(2);
|
||||
}
|
||||
Priv::CrashHandlerActivated = true;
|
||||
void* TraceStack[StackTraceArraySize];
|
||||
int StackTraceSize = backtrace(TraceStack, StackTraceArraySize);
|
||||
auto TraceTextArray = backtrace_symbols(TraceStack, StackTraceArraySize);
|
||||
trace = QString(QObject::tr("Stack trace:\n"));
|
||||
for(int i = 0; i < StackTraceSize; i++)
|
||||
trace += QString::number(i) + "> " + QString(TraceTextArray[i]) + '\n';
|
||||
msg += QObject::tr("Spark Store cannot continue.\n\n");
|
||||
msg += WriteStackTrace(trace);
|
||||
SpkMsgBox::StaticExec(msg, QObject::tr("Spark Store Crashed"), QMessageBox::Critical,
|
||||
QMessageBox::Ok, trace);
|
||||
exit(2);
|
||||
}
|
||||
default:
|
||||
sErrPop(QObject::tr("Unknown signal %1 received in crash handler. "
|
||||
"Program internals may be corrupted. Please decide if you want "
|
||||
"to continue execution.").arg(sig));
|
||||
}
|
||||
}
|
||||
|
||||
QIcon GetThemedIcon(QString name)
|
||||
{
|
||||
if(CurrentStyle == SpkUiStyle::Dark)
|
||||
name += "-dark";
|
||||
return QIcon(":/icons/" + name + ".svg");
|
||||
}
|
||||
|
||||
QString StylesheetFromColors(Qss::ColorSet aColors)
|
||||
{
|
||||
QString ret = StylesheetBase;
|
||||
foreach(auto &i, aColors)
|
||||
ret = ret.replace(Qss::ColorSet2Token.at(i.first), i.second.name());
|
||||
return ret;
|
||||
}
|
||||
|
||||
QColor ColorTextOnBackground(QColor c)
|
||||
{
|
||||
// From https://github.com/feiyangqingyun/qtkaifajingyan
|
||||
double gray = (0.299 * c.red() + 0.587 * c.green() + 0.114 * c.blue()) / 255;
|
||||
return gray > 0.5 ? Qt::black : Qt::white;
|
||||
}
|
||||
|
||||
// =================== UiMetaObject =======================
|
||||
// UiMetaObject is the signal-slot receiver for DDE plugin, receiving the DDE system level
|
||||
// notifications of UI theme changes
|
||||
// Communications with UI widgets are also done here
|
||||
|
||||
void UiMetaObject::SetAccentColor(QColor aColor)
|
||||
{
|
||||
if(!SpkUi::States::DoRespondAutoTheme)
|
||||
return;
|
||||
CurrentColorSet[Qss::AccentColor] = aColor.lighter(90);
|
||||
CurrentColorSet[Qss::AccentColorHighlighted] = aColor.lighter(105);
|
||||
CurrentColorSet[Qss::TextOnAccentColor] = ColorTextOnBackground(aColor);
|
||||
SetBtnMaskColor();
|
||||
qApp->setStyleSheet(StylesheetFromColors(CurrentColorSet));
|
||||
}
|
||||
|
||||
void UiMetaObject::SetDarkLightTheme(bool isDark)
|
||||
{
|
||||
if(!SpkUi::States::DoRespondAutoTheme)
|
||||
return;
|
||||
if(isDark)
|
||||
SetGlobalStyle(Dark, true);
|
||||
else
|
||||
SetGlobalStyle(Light, true);
|
||||
}
|
||||
}
|
||||
@@ -1,326 +0,0 @@
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QApplication>
|
||||
#include <QStyleHints>
|
||||
#include <QPainterPath>
|
||||
#include <QFile>
|
||||
#include <QPushButton>
|
||||
#include <QMouseEvent>
|
||||
#include "spklogging.h"
|
||||
#include "spkwindow.h"
|
||||
#include "spkui_general.h"
|
||||
#include "spktitlebar.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
SpkWindow::SpkWindow(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
mUseCustomEvents = SpkUi::DtkPlugin == nullptr; // Put to the front, to prevent warnings
|
||||
if(SpkUi::DtkPlugin && !qEnvironmentVariableIntValue("SPARK_NO_DXCB"))
|
||||
SpkUi::DtkPlugin->addWindow(this, parent); // Register window to DXcb so we got Deepin
|
||||
else
|
||||
setWindowFlags(Qt::FramelessWindowHint); // Remove default title bar
|
||||
setAttribute(Qt::WA_Hover);
|
||||
mCornerRadius = 5;
|
||||
mUserCentralWidget = nullptr;
|
||||
mResizable = true;
|
||||
mMoving = mResizing = false;
|
||||
mCloseHook = nullptr;
|
||||
mMaximized = windowState().testFlag(Qt::WindowMaximized);
|
||||
setMouseTracking(true);
|
||||
|
||||
PopulateUi();
|
||||
}
|
||||
|
||||
SpkWindow::~SpkWindow()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool SpkWindow::event(QEvent *evt)
|
||||
{
|
||||
// These custom events weren't useful for Deepin platform
|
||||
if(!mUseCustomEvents)
|
||||
return QWidget::event(evt);
|
||||
|
||||
switch(evt->type())
|
||||
{
|
||||
case QEvent::WindowStateChange:
|
||||
{
|
||||
mMaximized = windowState().testFlag(Qt::WindowMaximized);
|
||||
if(mMaximized)
|
||||
mTitleBarComponent->mBtnMaxRestore->SetRole(SpkTitleBarDefaultButton::Restore);
|
||||
else
|
||||
mTitleBarComponent->mBtnMaxRestore->SetRole(SpkTitleBarDefaultButton::MaximizeRestore);
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseButtonPress:
|
||||
{
|
||||
// if(!mResizable) break;
|
||||
auto e = static_cast<QMouseEvent*>(evt);
|
||||
if(e->button() != Qt::LeftButton) break;
|
||||
auto edge = DetectEdgeOnThis(e->pos());
|
||||
if(edge)
|
||||
{
|
||||
mResizing = true;
|
||||
mEdgesBeingResized = edge;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!QWidget::event(evt) || 1) // Movable property is not implemented, let move anywhere
|
||||
{
|
||||
mMoveOffset = e->globalPos() - pos();
|
||||
mMoving = true;
|
||||
mResizing = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseButtonRelease:
|
||||
{
|
||||
// if(!mResizable) break;
|
||||
auto e = static_cast<QMouseEvent*>(evt);
|
||||
if(e->button() != Qt::LeftButton) break;
|
||||
mResizing = false;
|
||||
mMoving = false;
|
||||
unsetCursor();
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
case QEvent::HoverMove:
|
||||
{
|
||||
if((mResizing || !mResizable) && !mMoving) break;
|
||||
if(mMaximized)
|
||||
{
|
||||
unsetCursor();
|
||||
break;
|
||||
}
|
||||
if(mResizable && !mMoving)
|
||||
{
|
||||
auto e = static_cast<QHoverEvent*>(evt);
|
||||
auto edge = DetectEdgeOnThis(e->pos());
|
||||
SetMouseCursor(edge);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseMove:
|
||||
{
|
||||
if(mMaximized) break;
|
||||
auto e = static_cast<QMouseEvent*>(evt);
|
||||
if(mResizing && mResizable)
|
||||
{
|
||||
ResizeWindowByCursor(e->globalPos());
|
||||
return true; // Intercept resize movements
|
||||
}
|
||||
else if(mMoving)
|
||||
{
|
||||
move(e->globalPos() - mMoveOffset);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
;
|
||||
}
|
||||
return QWidget::event(evt);
|
||||
}
|
||||
|
||||
Qt::Edges SpkWindow::DetectEdgeOnThis(QPoint p)
|
||||
{
|
||||
Qt::Edges edge;
|
||||
if(p.x() < BorderWidth) edge |= Qt::LeftEdge;
|
||||
if(p.x() > width() - BorderWidth) edge |= Qt::RightEdge;
|
||||
if(p.y() < BorderWidth) edge |= Qt::TopEdge;
|
||||
if(p.y() > height() - BorderWidth) edge |= Qt::BottomEdge;
|
||||
return edge;
|
||||
}
|
||||
|
||||
void SpkWindow::SetMouseCursor(Qt::Edges e)
|
||||
{
|
||||
switch(e)
|
||||
{
|
||||
case Qt::TopEdge:
|
||||
case Qt::BottomEdge:
|
||||
setCursor(Qt::SizeVerCursor);
|
||||
break;
|
||||
case Qt::LeftEdge:
|
||||
case Qt::RightEdge:
|
||||
setCursor(Qt::SizeHorCursor);
|
||||
break;
|
||||
case Qt::TopEdge | Qt::LeftEdge:
|
||||
case Qt::BottomEdge | Qt::RightEdge:
|
||||
setCursor(Qt::SizeFDiagCursor);
|
||||
break;
|
||||
case Qt::TopEdge | Qt::RightEdge:
|
||||
case Qt::BottomEdge | Qt::LeftEdge:
|
||||
setCursor(Qt::SizeBDiagCursor);
|
||||
break;
|
||||
default:
|
||||
unsetCursor();
|
||||
}
|
||||
}
|
||||
|
||||
void SpkWindow::ResizeWindowByCursor(QPoint p)
|
||||
{
|
||||
auto r_ = geometry(), r = r_;
|
||||
switch(mEdgesBeingResized)
|
||||
{
|
||||
case Qt::TopEdge | Qt::LeftEdge:
|
||||
r.setLeft(p.x());
|
||||
if(r.width() < minimumWidth()) // If smaller than minimum the window moves, so we stop it
|
||||
r.setLeft(r_.left());
|
||||
case Qt::TopEdge:
|
||||
r.setTop(p.y());
|
||||
if(r.height() < minimumHeight()) // Same
|
||||
r.setTop(r_.top());
|
||||
break;
|
||||
case Qt::BottomEdge | Qt::LeftEdge:
|
||||
r.setLeft(p.x());
|
||||
if(r.width() < minimumWidth())
|
||||
r.setLeft(r_.left());
|
||||
case Qt::BottomEdge:
|
||||
r.setBottom(p.y());
|
||||
if(r.height() < minimumHeight())
|
||||
r.setBottom(r_.bottom());
|
||||
break;
|
||||
case Qt::TopEdge | Qt::RightEdge:
|
||||
r.setTop(p.y());
|
||||
r.setRight(p.x());
|
||||
if(r.height() < minimumHeight())
|
||||
r.setTop(r_.top());
|
||||
if(r.width() < minimumWidth())
|
||||
r.setRight(r_.right());
|
||||
break;
|
||||
case Qt::BottomEdge | Qt::RightEdge:
|
||||
r.setBottom(p.y());
|
||||
if(r.height() < minimumHeight())
|
||||
r.setBottom(r_.bottom());
|
||||
case Qt::RightEdge:
|
||||
r.setRight(p.x());
|
||||
if(r.width() < minimumWidth())
|
||||
r.setRight(r_.right());
|
||||
break;
|
||||
case Qt::LeftEdge:
|
||||
r.setLeft(p.x());
|
||||
if(r.width() < minimumWidth())
|
||||
r.setLeft(r_.left());
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
setGeometry(r);
|
||||
}
|
||||
|
||||
void SpkWindow::closeEvent(QCloseEvent *e)
|
||||
{
|
||||
if(mCloseHook)
|
||||
{
|
||||
if(mCloseHook())
|
||||
e->accept();
|
||||
else
|
||||
e->ignore();
|
||||
emit Closed();
|
||||
return;
|
||||
}
|
||||
e->accept();
|
||||
emit Closed();
|
||||
}
|
||||
|
||||
void SpkWindow::paintEvent(QPaintEvent *e)
|
||||
{
|
||||
QWidget::paintEvent(e);
|
||||
if(!mUseCustomEvents)
|
||||
return;
|
||||
|
||||
QPainter painter(this);
|
||||
painter.setBrush(QBrush(Qt::NoBrush));
|
||||
painter.setPen(QPen(SpkUi::ColorLine));
|
||||
QRect rect = this->rect();
|
||||
rect.adjust(0, 0, -1, -1);
|
||||
painter.drawRect(rect);
|
||||
}
|
||||
|
||||
void SpkWindow::SetCornerRadius(int radius)
|
||||
{
|
||||
mCornerRadius = radius;
|
||||
}
|
||||
|
||||
void SpkWindow::PopulateUi()
|
||||
{
|
||||
mMainVLayout = new QVBoxLayout;
|
||||
mTitleBarComponent = new SpkTitleBar(this);
|
||||
|
||||
setLayout(mMainVLayout);
|
||||
|
||||
mMainVLayout->addWidget(mTitleBarComponent);
|
||||
mMainVLayout->setAlignment(Qt::AlignTop);
|
||||
if(mUseCustomEvents)
|
||||
mMainVLayout->setContentsMargins(1, 1, 1, 1);
|
||||
else
|
||||
mMainVLayout->setContentsMargins(0, 0, 0, 0);
|
||||
mMainVLayout->setSpacing(0);
|
||||
|
||||
mTitleBarComponent->SetTitle(qAppName());
|
||||
mTitleBarComponent->SetUseIcon(false);
|
||||
mTitleBarComponent->SetLinkedWindow(this);
|
||||
setWindowFlag(Qt::NoDropShadowWindowHint, false);
|
||||
}
|
||||
|
||||
void SpkWindow::SetCentralWidget(QWidget *widget)
|
||||
{
|
||||
if(mUserCentralWidget)
|
||||
mMainVLayout->removeWidget(mUserCentralWidget);
|
||||
mUserCentralWidget = widget;
|
||||
mMainVLayout->addWidget(widget);
|
||||
}
|
||||
|
||||
void SpkWindow::SetUseTitleBar(bool x)
|
||||
{
|
||||
mTitleBarComponent->setVisible(x);
|
||||
}
|
||||
|
||||
void SpkWindow::SetCentralMargin(int a, int b, int c, int d)
|
||||
{
|
||||
if(mUserCentralWidget)
|
||||
mUserCentralWidget->setContentsMargins(a, b, c, d);
|
||||
}
|
||||
|
||||
void SpkWindow::SetCloseHook(bool (*f)())
|
||||
{
|
||||
mCloseHook = f;
|
||||
}
|
||||
|
||||
void SpkWindow::ClearCloseHook()
|
||||
{
|
||||
mCloseHook = nullptr;
|
||||
}
|
||||
|
||||
void SpkWindow::RecalculateSize()
|
||||
{
|
||||
mMainVLayout->activate();
|
||||
}
|
||||
|
||||
bool SpkWindow::GetUseTitleBar()
|
||||
{
|
||||
return mTitleBarComponent->isVisible();
|
||||
}
|
||||
|
||||
SpkTitleBar *SpkWindow::GetTitleBar()
|
||||
{
|
||||
return mTitleBarComponent;
|
||||
}
|
||||
|
||||
SpkTitleBar *SpkWindow::SetTitleBar(SpkTitleBar *bar, bool replace)
|
||||
{
|
||||
if(!bar)
|
||||
return nullptr;
|
||||
auto ret = mTitleBarComponent;
|
||||
mMainVLayout->removeWidget(mTitleBarComponent);
|
||||
if(replace)
|
||||
mMainVLayout->insertWidget(0, bar);
|
||||
mTitleBarComponent = bar;
|
||||
bar->SetLinkedWindow(this);
|
||||
return ret;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
//
|
||||
// Created by rigoligo on 2021/5/8.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// Stub
|
||||
|
||||
#endif //_DEEPINPLATFORM_H_
|
||||
@@ -1,22 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class SpkDtkPlugin : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
virtual ~SpkDtkPlugin() = default;
|
||||
virtual void Initialize() = 0;
|
||||
virtual void addWindow(QWidget* w, QObject* parent) = 0;
|
||||
virtual QColor GetAccentColor() = 0;
|
||||
virtual bool GetIsDarkTheme() = 0;
|
||||
|
||||
signals:
|
||||
void AccentColorChanged(QColor);
|
||||
void DarkLightThemeChanged(bool isDark);
|
||||
};
|
||||
QT_BEGIN_NAMESPACE
|
||||
Q_DECLARE_INTERFACE(SpkDtkPlugin, "org.spark-store.client.dtkplugin")
|
||||
QT_END_NAMESPACE
|
||||
@@ -1,8 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace GitVer
|
||||
{
|
||||
const char *DescribeTags();
|
||||
const char *CommitDate();
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QLabel>
|
||||
#include <QScrollArea>
|
||||
#include <QVBoxLayout>
|
||||
#include <QFormLayout>
|
||||
#include "page/spkpagebase.h"
|
||||
#include "spkstretchlayout.h"
|
||||
#include "spkimgviewer.h"
|
||||
|
||||
namespace SpkUi
|
||||
{
|
||||
class SpkDetailEntry;
|
||||
|
||||
class SpkClickLabel : public QLabel
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
virtual void mousePressEvent(QMouseEvent *e) override { emit Pressed(); }
|
||||
signals:
|
||||
void Pressed();
|
||||
};
|
||||
|
||||
class SpkPageAppDetails : public SpkPageBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SpkPageAppDetails(QWidget *parent = nullptr);
|
||||
~SpkPageAppDetails();
|
||||
|
||||
void LoadAppResources(QString pkgName, QString icon, QStringList screenshots, QStringList tags);
|
||||
void SetWebsiteLink(QString url);
|
||||
void SetPackagePath(QString url);
|
||||
|
||||
private:
|
||||
QString mPkgPath;
|
||||
QPixmap mBrokenImg, mIconLoading;
|
||||
|
||||
public slots:
|
||||
void ResourceAcquisitionFinished(int id, ResourceResult result);
|
||||
void Activated();
|
||||
|
||||
public:
|
||||
static constexpr QSize IconSize { 144, 144 };
|
||||
|
||||
// Main Area
|
||||
QScrollArea *mMainArea, *mScreenshotArea;
|
||||
QWidget *mDetailWidget, *mIconTitleWidget, *mWid4MainArea, *mWid4ShotArea;
|
||||
QLabel *mAppTitle, *mAppIcon, *mAppDescription, *mAppShortDesc, *mPkgName, *mVersion,
|
||||
*mWebsite;
|
||||
SpkDetailEntry *mAuthor, *mContributor, *mSite, *mArch, *mSize;
|
||||
SpkStretchLayout *mDetailLay;
|
||||
QVBoxLayout *mDetailsLay, *mTitleLay, *mMainLay;
|
||||
QHBoxLayout *mIconTitleLay, *mScreenshotLay;
|
||||
QList<SpkClickLabel*> mScreenshotPreviews;
|
||||
|
||||
QMap<int, QPixmap> mAppImages;
|
||||
SpkImgViewer *mImgViewer;
|
||||
|
||||
// Bottom bar
|
||||
QWidget *mBottomBar;
|
||||
QPushButton *mBtnInstall, *mBtnDownload, *mBtnUninstall, *mBtnRequestUpdate, *mBtnReport;
|
||||
QHBoxLayout *mBottomBarLay;
|
||||
|
||||
signals:
|
||||
void RequestDownload(QString name, QString pkgName, QString path);
|
||||
|
||||
private slots:
|
||||
void ImageClicked();
|
||||
};
|
||||
|
||||
class SpkDetailEntry : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SpkDetailEntry(QWidget *parent = nullptr);
|
||||
void SetTitle(const QString &s) { mTitle.setText(s); }
|
||||
void SetValue(const QString &s) { mField.setText(s); }
|
||||
|
||||
private:
|
||||
QLabel mTitle, mField;
|
||||
QHBoxLayout mLay;
|
||||
};
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtWidgets>
|
||||
#include "spkresource.h"
|
||||
#include "spkappitem.h"
|
||||
#include "page/spkpagebase.h"
|
||||
#include "spkstretchlayout.h"
|
||||
|
||||
namespace SpkUi
|
||||
{
|
||||
class SpkPageAppList : public SpkPageBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SpkPageAppList(QWidget *parent = nullptr);
|
||||
|
||||
void AddApplicationEntry(QString name, QString pkgName, QString description, QString iconUrl,
|
||||
int appId);
|
||||
void ClearAll();
|
||||
void SetPageStatus(int total, int current, int itemCount, QString &keyword);
|
||||
void SetCurrentCategory(int categoryId) { mCategoryId = categoryId; }
|
||||
|
||||
private:
|
||||
void DisablePageSwitchers();
|
||||
|
||||
public:
|
||||
|
||||
private:
|
||||
QVBoxLayout *mMainLay;
|
||||
QHBoxLayout *mPageSwitchLay;
|
||||
QPushButton *mBtnPgUp, *mBtnPgDown, *mBtnGotoPage;
|
||||
QLineEdit *mPageInput;
|
||||
QScrollArea *mAppsArea;
|
||||
QLabel *mPageIndicator;
|
||||
QWidget *mAppsWidget, *mPageSwitchWidget;
|
||||
SpkStretchLayout *mItemLay;
|
||||
QList<SpkAppItem *> mAppItemList;
|
||||
|
||||
// Cached icons
|
||||
QPixmap *mLoadingIcon,
|
||||
*mBrokenIcon;
|
||||
|
||||
QIntValidator *mPageValidator;
|
||||
|
||||
int mCategoryId, mCurrentPage;
|
||||
QString mKeyword;
|
||||
|
||||
signals:
|
||||
void ApplicationClicked(int appId);
|
||||
void SwitchListPage(int categoryId, int page);
|
||||
void SwitchSearchPage(QString keyword, int page);
|
||||
|
||||
public slots:
|
||||
void ResourceAcquisitionFinished(int id, ResourceResult result);
|
||||
void Activated();
|
||||
|
||||
private slots:
|
||||
void PageUp();
|
||||
void PageDown();
|
||||
void GotoPage();
|
||||
};
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtWidgets>
|
||||
#include <spkresource.h>
|
||||
|
||||
class SpkPageBase : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SpkPageBase(QWidget *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief This signal is emitted by resource manager when a resource acquisition requested
|
||||
* has finished.
|
||||
* @param id The request ID
|
||||
* @param result The data retrieved
|
||||
*/
|
||||
virtual void ResourceAcquisitionFinished(int id, ResourceResult result);
|
||||
|
||||
/**
|
||||
* @brief This is an optional signal for Resource Context objects, mainly used for notifying the
|
||||
* context that it is now activated (therefore it needs to acquire the resource manager).
|
||||
*/
|
||||
virtual void Activated();
|
||||
};
|
||||
@@ -1,45 +0,0 @@
|
||||
#ifndef SPKPAGEDOWNLOADS_H
|
||||
#define SPKPAGEDOWNLOADS_H
|
||||
|
||||
#include "spkdownload.h"
|
||||
#include "spkdownloadentry.h"
|
||||
#include "page/spkpagebase.h"
|
||||
#include "pkgs/spkpkgmgrbase.h"
|
||||
|
||||
namespace SpkUi
|
||||
{
|
||||
class SpkPageDownloads : public SpkPageBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SpkPageDownloads(QWidget *parent = nullptr);
|
||||
~SpkPageDownloads();
|
||||
|
||||
public slots:
|
||||
void AddDownloadTask(QString name, QString pkgName, QString path);
|
||||
|
||||
private:
|
||||
// Logic
|
||||
SpkDownloadMgr *mDownloadMgr;
|
||||
QMap<uint, SpkDownloadEntry*> mEntries;
|
||||
uint mNextDownloadId;
|
||||
QQueue<QPair<int, QString>> mWaitingDownloads;
|
||||
enum { Idle, Waiting, Downloading } mCurrentStatus;
|
||||
|
||||
// UI
|
||||
QVBoxLayout *mLayEntries, *mMainLay;
|
||||
QWidget *mScrollWidget;
|
||||
QScrollArea *mScrollArea;
|
||||
|
||||
private slots:
|
||||
void DownloadProgress(qint64 downloadedBytes, qint64 totalBytes, int id);
|
||||
void DownloadStopped(SpkDownloadMgr::TaskResult status, int id);
|
||||
void EntryAction(SpkDownloadEntry::EntryAction);
|
||||
void InstallationEnded(int id, SpkPkgMgrBase::PkgInstallResult, int exitCode);
|
||||
|
||||
private:
|
||||
void NewDownloadTask(int id, QString downloadPath);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // SPKPAGEDOWNLOADS_H
|
||||
@@ -1,25 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include "page/spkpagebase.h"
|
||||
#include "ui_homepage.h"
|
||||
|
||||
namespace SpkUi
|
||||
{
|
||||
class SpkPageHome : public SpkPageBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SpkPageHome(QWidget *parent = nullptr);
|
||||
~SpkPageHome() { }
|
||||
|
||||
Ui::SpkHomepage *ui;
|
||||
|
||||
private slots:
|
||||
void LinkActivated(QString);
|
||||
|
||||
private:
|
||||
void SetupUi();
|
||||
};
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QScrollArea>
|
||||
#include <QVBoxLayout>
|
||||
#include <QFutureWatcher>
|
||||
#include <QMutex>
|
||||
#include "page/spkpagebase.h"
|
||||
#include "ui_settings.h"
|
||||
|
||||
namespace SpkUi
|
||||
{
|
||||
class SpkPageSettings : public SpkPageBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SpkPageSettings(QWidget *parent = nullptr);
|
||||
~SpkPageSettings();
|
||||
|
||||
void SetupUi();
|
||||
void ReadConfiguration();
|
||||
void SaveConfiguration();
|
||||
|
||||
void CountCleaning();
|
||||
|
||||
virtual void Activated() override;
|
||||
|
||||
private slots:
|
||||
void on_btnCleanDownloadedContent_clicked();
|
||||
void on_btnCleanResourceCache_clicked();
|
||||
void on_btnViewDownloadedContent_clicked();
|
||||
void on_btnViewResourceCache_clicked();
|
||||
|
||||
void CountFinishResource();
|
||||
void CountFinishDownload();
|
||||
void CleanedResource();
|
||||
void CleanedDownload();
|
||||
|
||||
private:
|
||||
QScrollArea *mMainArea;
|
||||
QVBoxLayout *mMainLay;
|
||||
QWidget *mSettingsWidget;
|
||||
Ui::SpkUiSettings *ui;
|
||||
|
||||
QString mRepoListUrl;
|
||||
|
||||
QFutureWatcher<void> mFwResourceCount,
|
||||
mFwDownloadCount,
|
||||
mFwResourceClean,
|
||||
mFwDownloadClean;
|
||||
QMutex mMutResource, mMutDownload;
|
||||
int64_t mBytesResource, mBytesDownloads;
|
||||
|
||||
};
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <QSplitter>
|
||||
#include <QPushButton>
|
||||
#include <QRadioButton>
|
||||
#include <QCheckBox>
|
||||
#include <QGroupBox>
|
||||
#include <QTextEdit>
|
||||
#include <QLineEdit>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QSlider>
|
||||
#include <QProgressBar>
|
||||
#include "spkappitem.h"
|
||||
#include "spkstretchlayout.h"
|
||||
#include "page/spkpageappdetails.h"
|
||||
#include "spkiconbutton.h"
|
||||
|
||||
#include "spkloading.h"
|
||||
|
||||
namespace SpkUi
|
||||
{
|
||||
class SpkPageUiTest : public QSplitter
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SpkPageUiTest(QWidget *parent = nullptr);
|
||||
QWidget *WidL, *WidR;
|
||||
QVBoxLayout *VLayWidgets,
|
||||
*VLayTestWidgets,
|
||||
*VLayInput;
|
||||
QHBoxLayout *HLay4Slider,
|
||||
*HLayInputBtns;
|
||||
QTextEdit *TextStylesheet;
|
||||
QPushButton *BtnApply;
|
||||
QPushButton *BtnFetch;
|
||||
|
||||
QPushButton *Btn;
|
||||
QCheckBox *Chk;
|
||||
QRadioButton *Rad;
|
||||
QGroupBox *Group;
|
||||
QSlider *SlideH;
|
||||
QSlider *SlideV;
|
||||
SpkIconButton *IconBtn;
|
||||
QProgressBar *Prog;
|
||||
SpkLoading *Loading;
|
||||
SpkAppItem *AppItem;
|
||||
SpkStretchLayout *DetailsLay;
|
||||
SpkDetailEntry *Detail1, *Detail2, *Detail3;
|
||||
QWidget *DetailsWidget;
|
||||
|
||||
QLineEdit *PopupText;
|
||||
QPushButton *ShowPopup,
|
||||
*ShowAbout,
|
||||
*ShowPkgmgr;
|
||||
|
||||
public slots:
|
||||
void SetStylesheet();
|
||||
void FetchStylesheet();
|
||||
void ShowPopupSlot();
|
||||
};
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "spkpkgmgrbase.h"
|
||||
#include <QProcess>
|
||||
|
||||
class SpkPkgMgrApt final : public SpkPkgMgrBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SpkPkgMgrApt(QObject *parent = nullptr);
|
||||
|
||||
static bool DetectRequirements();
|
||||
|
||||
virtual PkgInstallResult ExecuteInstallation(QString pkgPath,
|
||||
int entryId) override;
|
||||
|
||||
// APT backend specific
|
||||
bool ChangeServerRepository(QString content);
|
||||
|
||||
private:
|
||||
void CheckInstallerAvailability();
|
||||
|
||||
private slots:
|
||||
void InstallerExited(int, QProcess::ExitStatus);
|
||||
|
||||
private:
|
||||
QAction *mActAptitudeTerm,
|
||||
*mActAptTerm,
|
||||
*mActGdebi,
|
||||
*mActDeepinPkgInst;
|
||||
|
||||
QProcess mInstaller;
|
||||
|
||||
};
|
||||
@@ -1,91 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
#include <QCursor>
|
||||
#include <QUrl>
|
||||
#include <QDesktopServices>
|
||||
|
||||
#include "spkutils.h"
|
||||
|
||||
class SpkPkgMgrBase : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SpkPkgMgrBase(QObject *parent = nullptr) : QObject(parent)
|
||||
{
|
||||
Q_ASSERT(mInstance == nullptr);
|
||||
mInstance = this;
|
||||
|
||||
mActOpen = new QAction(tr("Open package"), this);
|
||||
mActOpenDir = new QAction(tr("Open containing directory"), this);
|
||||
mMenu = new QMenu(tr("Package Actions"));
|
||||
mMenu->addAction(mActOpen);
|
||||
mMenu->addAction(mActOpenDir);
|
||||
mMenu->setAttribute(Qt::WA_TranslucentBackground);
|
||||
mMenu->setWindowFlags(Qt::Popup | Qt::FramelessWindowHint);
|
||||
}
|
||||
|
||||
enum PkgInstallResult
|
||||
{
|
||||
Failed,
|
||||
Succeeded,
|
||||
Ignored ///< No installation action is taken, no messages be displayed
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Detects if this system qualified to use this kind of packaging
|
||||
*/
|
||||
static bool DetectRequirements() { return true; }
|
||||
|
||||
/**
|
||||
* @brief Popup a menu at cursor to select installation methods
|
||||
* and do installation accordingly
|
||||
* @param pkgPath Path to the package file
|
||||
* @param entryId ID of the download entry
|
||||
*/
|
||||
virtual PkgInstallResult ExecuteInstallation(QString pkgPath, int entryId)
|
||||
{
|
||||
Q_UNUSED(entryId);
|
||||
auto item = mMenu->exec(QCursor::pos());
|
||||
if(item == mActOpenDir)
|
||||
QDesktopServices::openUrl(QUrl(SpkUtils::CutPath(pkgPath)));
|
||||
else if(item == mActOpen)
|
||||
QDesktopServices::openUrl(QUrl(pkgPath));
|
||||
return Ignored;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Called when Spark Store installs a software when it's running
|
||||
* in CLI mode
|
||||
* @param pkgPath Path to the package file
|
||||
*/
|
||||
virtual PkgInstallResult CliInstall(QString pkgPath)
|
||||
{
|
||||
qInfo() << tr("Spark Store cannot install your package because no supported "
|
||||
"packaging system has been found. You shall decide what you "
|
||||
"want to do with the downloaded package.\n\n"
|
||||
"File path:")
|
||||
<< pkgPath;
|
||||
return Ignored;
|
||||
}
|
||||
|
||||
public:
|
||||
static SpkPkgMgrBase *Instance() { return mInstance; }
|
||||
|
||||
protected:
|
||||
QAction *mActOpenDir, *mActOpen, *mActDesc;
|
||||
QMenu *mMenu;
|
||||
int mCurrentItemId; ///< ID of currently installing download item
|
||||
|
||||
private:
|
||||
static SpkPkgMgrBase *mInstance;
|
||||
|
||||
signals:
|
||||
void ReportInstallResult(int entryId,
|
||||
SpkPkgMgrBase::PkgInstallResult result,
|
||||
int exitCode);
|
||||
};
|
||||
@@ -1,20 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "spkpkgmgrbase.h"
|
||||
|
||||
class SpkPkgMgrPacman final : public SpkPkgMgrBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SpkPkgMgrPacman(QObject *parent = nullptr);
|
||||
|
||||
static bool DetectRequirements();
|
||||
|
||||
virtual PkgInstallResult ExecuteInstallation(QString pkgPath,
|
||||
int entryId) override;
|
||||
|
||||
|
||||
|
||||
};
|
||||
@@ -1,87 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtCore module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** BSD License Usage
|
||||
** Alternatively, you may use this file under the terms of the BSD license
|
||||
** as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Slight modifications has been done to the code to make it fit into the project.
|
||||
*/
|
||||
|
||||
#include <QFrame>
|
||||
#include <QString>
|
||||
|
||||
//! [0]
|
||||
class ElidedLabel : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString text READ text WRITE setText)
|
||||
Q_PROPERTY(bool isElided READ isElided)
|
||||
|
||||
public:
|
||||
explicit ElidedLabel(const QString &text, QWidget *parent = nullptr);
|
||||
|
||||
explicit ElidedLabel(QWidget *parent = nullptr);
|
||||
|
||||
void setText(const QString &text);
|
||||
const QString & text() const { return content; }
|
||||
bool isElided() const { return elided; }
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
signals:
|
||||
void elisionChanged(bool elided);
|
||||
|
||||
private:
|
||||
bool elided;
|
||||
QString content;
|
||||
};
|
||||
//! [0]
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QHBoxLayout>
|
||||
#include "spkdialog.h"
|
||||
|
||||
class SpkAbout : public SpkDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SpkAbout(QWidget* parent = nullptr);
|
||||
~SpkAbout();
|
||||
static void Show();
|
||||
|
||||
private:
|
||||
QHBoxLayout *mIconLay;
|
||||
QLabel *mSpkIcon;
|
||||
QLabel *mSpkVersion;
|
||||
QLabel *mDescriptionText;
|
||||
};
|
||||
@@ -1,41 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include "qt/elidedlabel.h"
|
||||
|
||||
class SpkAppItem : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SpkAppItem(int appId, QWidget *parent = nullptr);
|
||||
void SetIcon(QPixmap p) { mIcon->setPixmap(p); }
|
||||
void SetTitle(QString s) { mTitle->setText(s); }
|
||||
void SetDescription(QString s) { mDescription->setText(s); }
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
void mouseReleaseEvent(QMouseEvent *e);
|
||||
|
||||
public:
|
||||
static constexpr int IconSize = 72;
|
||||
static constexpr QSize IconSize_ = { IconSize, IconSize };
|
||||
|
||||
private:
|
||||
QLabel *mIcon;
|
||||
QLabel *mTitle;
|
||||
ElidedLabel *mDescription;
|
||||
int mAppId;
|
||||
|
||||
bool mPressCond;
|
||||
|
||||
QVBoxLayout *mLayText;
|
||||
QHBoxLayout *mMainLay;
|
||||
|
||||
signals:
|
||||
void clicked(int);
|
||||
};
|
||||
@@ -1,51 +0,0 @@
|
||||
#ifndef SPKCONFIG_H
|
||||
#define SPKCONFIG_H
|
||||
|
||||
#include <QSettings>
|
||||
#include <QHash>
|
||||
#include <QPair>
|
||||
#include <functional>
|
||||
|
||||
class SpkConfig : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SpkConfig(QObject *parent, QString configPath);
|
||||
~SpkConfig();
|
||||
|
||||
/**
|
||||
* @brief BindField If a variable is bound to the specified key, then future chanegs via SetField
|
||||
* will modify the provided variable. A callback can also be specified to make
|
||||
* sure the chanegs are acceptable.
|
||||
* @param key
|
||||
* @param value A pointer to the variable to be bound
|
||||
* @param defaultValue
|
||||
* @param callback When SetField is called to modify this specific key associated with a callback,
|
||||
* the callback is called. If the callback returned false then the original value
|
||||
* is restored to the value target, and changes won't be saved in mSettings, and
|
||||
* SetField will return false too. It is used to ensure if the target can accept
|
||||
* the changes.
|
||||
* @return false when the key is already bound.
|
||||
*/
|
||||
bool BindField(QString key, QString* value, QString defaultValue, std::function<bool(void)> callback = nullptr);
|
||||
bool BindField(QString key, int* value, int defaultValue, std::function<bool(void)> callback = nullptr);
|
||||
|
||||
bool SetField(QString key, QString value);
|
||||
bool SetField(QString key, int value);
|
||||
|
||||
// Wrapper of QSettings::value, used for "read once on startup" configurations
|
||||
QVariant ReadField(QString key, QVariant defaultValue);
|
||||
// Wrapper of QSettings::setValue, used for "set and restart to take effect" configurations
|
||||
void SetSettings(QString key, QVariant value);
|
||||
// Wrapper of QSettings::sync
|
||||
void Sync();
|
||||
|
||||
private:
|
||||
QSettings mSettings;
|
||||
|
||||
QHash<QString, QPair<QString*, std::function<bool(void)>>> mStringBindMap;
|
||||
QHash<QString, QPair<int*,std::function<bool(void)>>> mIntBindMap;
|
||||
|
||||
};
|
||||
|
||||
#endif // SPKCONFIG_H
|
||||
@@ -1,40 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <QList>
|
||||
#include <QButtonGroup>
|
||||
#include "spkui_general.h"
|
||||
#include "spktitlebar.h"
|
||||
#include "spkwindow.h"
|
||||
|
||||
class SpkDialog : public SpkWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
friend class SpkMsgBox;
|
||||
public:
|
||||
SpkDialog(QWidget *parent = nullptr);
|
||||
~SpkDialog();
|
||||
void AddButton(QString text, SpkUi::SpkButtonStyle style = SpkUi::SpkButtonStyle::Normal);
|
||||
void AddWidget(QWidget*);
|
||||
void AddLayout(QLayout*);
|
||||
void AddSpacing(int);
|
||||
void AddStretch(int a = 0);
|
||||
void SetMargin(int);
|
||||
void SetMargin(int, int, int, int);
|
||||
int Exec();
|
||||
|
||||
private slots:
|
||||
void ButtonPressed(int);
|
||||
void ForceClose();
|
||||
|
||||
signals:
|
||||
void ExitEventLoop(int);
|
||||
void CloseWindow();
|
||||
|
||||
protected:
|
||||
QWidget *mDialogWidget;
|
||||
private:
|
||||
QVBoxLayout *mMainVLay, *mWidgetsVLay;
|
||||
QHBoxLayout *mBtnLay;
|
||||
QButtonGroup *mBtnGroup;
|
||||
QList<QObject*> mWidgetsList, mParentsList;
|
||||
};
|
||||
@@ -1,125 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "spkstore.h"
|
||||
#include <QTimer>
|
||||
|
||||
/**
|
||||
* @note SpkDownloadMgr does NOT do download scheduling and other things; it's only a multithreaded
|
||||
* downloader; it manages the threads that are downloading stuff from the Internet.
|
||||
*
|
||||
* Because of this, SpkDownloadMgr does not support complex download queues, cannot handle
|
||||
* pauses, and can only work on a sequential list of tasks.
|
||||
*/
|
||||
|
||||
class SpkDownloadMgr : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SpkDownloadMgr(QObject *parent = nullptr);
|
||||
~SpkDownloadMgr();
|
||||
|
||||
static constexpr int MaximumThreadRetryCount = 3;
|
||||
|
||||
enum TaskResult
|
||||
{
|
||||
Success = 0,
|
||||
FailCannotCreateFile, ///< Failed because destination file cannot be created
|
||||
FailNoVaibleServer, ///< Failed because no server provides file size or download stalled on
|
||||
///< all of them
|
||||
FailCancel, ///< User has cancelled the task
|
||||
Fail
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief DownloadWorker is not a real worker but more of a worker-like structure. It holds
|
||||
* information about one download thread, such as offset, total bytes and received bytes.
|
||||
* Workers' scheduling is still done by SpkDownloadMgr synchronously, avoiding
|
||||
* unnecessary race conditions and data safety problems.
|
||||
* DownloadWorker is also used in mFailureRetryQueue to indicate the blocks that needed
|
||||
* to be retried on other servers.
|
||||
*
|
||||
* Each worker has a watch dog value, incremented each time the download speed is
|
||||
* updated, and zeroed each time the worker has data ready. If the value exceeds a
|
||||
* preset maximum, then this worker is considered timed out and killed.
|
||||
*/
|
||||
struct DownloadWorker
|
||||
{
|
||||
QNetworkReply *Reply; ///< Reply from the network
|
||||
int Watchdog; ///< Watch dog value watching for a timed out worker
|
||||
qint64 BeginOffset; ///< Where should a worker start downloading
|
||||
qint64 BytesNeeded; ///< How many bytes a worker should fetch in total
|
||||
qint64 BytesRecvd; ///< How many bytes a worker has received till now
|
||||
};
|
||||
|
||||
constexpr static int WatchDogMaximum = 7;
|
||||
|
||||
struct RemoteFileInfo
|
||||
{
|
||||
qint64 Size = -1;
|
||||
bool SupportPartialDownload = false; ///< Whether this file can be downloaded multithreaded
|
||||
QByteArray Md5;
|
||||
};
|
||||
|
||||
void SetNewServers(QList<QString> servers);
|
||||
|
||||
/**
|
||||
* @note This function uses BLOCKING IO!
|
||||
*/
|
||||
static RemoteFileInfo GetRemoteFileInfo(QUrl url);
|
||||
|
||||
QString GetDestFilePath(QString downloadPath);
|
||||
|
||||
private:
|
||||
QList<QString> mServers; ///< Multithreaded download
|
||||
|
||||
QList<DownloadWorker> mScheduledWorkers;
|
||||
|
||||
// If one scheduled task fails a few times in a row, we must give it up on that server and put
|
||||
// its responsible block onto this queue so we can try downloading the block from other servers
|
||||
QQueue<DownloadWorker> mFailureRetryQueue;
|
||||
|
||||
QFile mDestFile;
|
||||
QString mDestFolder, mCurrentRemotePath;
|
||||
RemoteFileInfo mCurrentRemoteFileInfo;
|
||||
QTimer mProgressEmitterTimer;
|
||||
qint64 mDownloadedBytes;
|
||||
|
||||
int mCurrentDownloadId; ///< Indicates download status. -1 means no download going on.
|
||||
int mActiveWorkerCount;
|
||||
|
||||
QString mBulkServerPaths; ///< Config string, modification are taken care of by callback.
|
||||
|
||||
public slots:
|
||||
void SetDestinationFolder(QString path);
|
||||
|
||||
/**
|
||||
* @brief StartNewDownload try to start new download task.
|
||||
* @param path File path. Domain name excluded. No leading slashes.
|
||||
* @param downloadId Emitted with progress, finish and error so the UI know whose status it is.
|
||||
* @return true for success and false for failure.
|
||||
*/
|
||||
bool StartNewDownload(QString path, int downloadId);
|
||||
bool PauseCurrentDownload();
|
||||
bool CancelCurrentDownload();
|
||||
|
||||
private slots:
|
||||
void WorkerFinish();
|
||||
void WorkerDownloadProgress(); ///< Be connected to ***QNetworkReply::readyRead***
|
||||
void WorkerError(QNetworkReply::NetworkError);
|
||||
void ProgressTimer();
|
||||
|
||||
private:
|
||||
void ProcessWorkerError(DownloadWorker &, int id);
|
||||
void LinkReplyWithMe(QNetworkReply*);
|
||||
void TryScheduleFailureRetries();
|
||||
void TryScheduleFailureRetries(int i); ///< Try schedule on a specific task slot.
|
||||
|
||||
bool ServerAddressesChangedCallback(); ///< Called by SpkConfig upon address changing
|
||||
|
||||
signals:
|
||||
void DownloadProgressed(qint64 bytes, qint64 total, int id);
|
||||
void DownloadStopped(TaskResult status, int id);
|
||||
|
||||
|
||||
};
|
||||
@@ -1,78 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <QPushButton>
|
||||
#include <QLabel>
|
||||
#include "qt/elidedlabel.h"
|
||||
#include "spkloading.h"
|
||||
#include <QProgressBar>
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QTime>
|
||||
|
||||
class SpkDownloadEntry : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SpkDownloadEntry(QWidget* parent = nullptr);
|
||||
~SpkDownloadEntry();
|
||||
|
||||
static constexpr QSize IconSize { 64, 64 };
|
||||
|
||||
enum DownloadEntryStatus
|
||||
{
|
||||
Invalid = -1,
|
||||
Waiting,
|
||||
Starting,
|
||||
Downloading,
|
||||
DownloadFailed,
|
||||
ToBeInstalled,
|
||||
Installing,
|
||||
Installed,
|
||||
InstallFailed
|
||||
};
|
||||
|
||||
void SetTotalBytes(qint64 total);
|
||||
void SetBasicInfo(QString name, QPixmap icon, QString filePath);
|
||||
void SetStatus(DownloadEntryStatus status, QString msg = "");
|
||||
void Progress(qint64 bytes);
|
||||
QString GetTaskName() { return mAppName->text(); }
|
||||
QString GetFilePath() { return mFilePath; }
|
||||
|
||||
enum EntryAction
|
||||
{
|
||||
AbortDownload,
|
||||
RetryDownload,
|
||||
StartInstall,
|
||||
RemoveEntry
|
||||
};
|
||||
|
||||
private slots:
|
||||
void ActionButton();
|
||||
void DeleteButton();
|
||||
|
||||
private:
|
||||
QLabel *mIcon, *mMessage;
|
||||
ElidedLabel *mAppName;
|
||||
QProgressBar *mProgress;
|
||||
QPushButton *mBtnDelete,
|
||||
*mBtnActions; // Actions include Retry Pause Install etc, one status at a time
|
||||
SpkLoading *mLoading;
|
||||
|
||||
QHBoxLayout *mLayMsgs, *mLayMain;
|
||||
QVBoxLayout *mLayInfo;
|
||||
|
||||
// Download status data
|
||||
qint64 mTotalBytes, mDownloadedBytes;
|
||||
QTime mLastReportTime;
|
||||
QString mReadableTotalSize;
|
||||
|
||||
QString mFilePath;
|
||||
|
||||
DownloadEntryStatus mStatus;
|
||||
|
||||
signals:
|
||||
void Action(EntryAction);
|
||||
};
|
||||
@@ -1,4 +0,0 @@
|
||||
#ifndef SPKFILLWIDGET_H
|
||||
#define SPKFILLWIDGET_H
|
||||
|
||||
#endif // SPKFILLWIDGET_H
|
||||
@@ -1,19 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtWidgets/QLineEdit>
|
||||
|
||||
class SpkFocusLineEdit final : public QLineEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SpkFocusLineEdit(QWidget *parent = nullptr) : QLineEdit(parent) {}
|
||||
|
||||
protected:
|
||||
void focusInEvent(QFocusEvent *e) override { emit focusGained(); }
|
||||
void focusOutEvent(QFocusEvent *e) override { emit focusLost(); }
|
||||
|
||||
signals:
|
||||
void focusGained();
|
||||
void focusLost();
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
#ifndef SPKICONBUTTON_H
|
||||
#define SPKICONBUTTON_H
|
||||
|
||||
#include <QPushButton>
|
||||
#include "spkui_general.h"
|
||||
|
||||
class SpkIconButton : public QPushButton
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SpkIconButton(QWidget *parent = nullptr);
|
||||
~SpkIconButton() {};
|
||||
|
||||
void SetIcon(QIcon, QSize);
|
||||
void SetIcon(QPixmap);
|
||||
void SetIconSize(QSize);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *) override;
|
||||
|
||||
private:
|
||||
static enum { Dark, Light } sCurrentTheme;
|
||||
QPixmap mPmapPaintedIcon;
|
||||
QSize mPmapSize;
|
||||
|
||||
static constexpr int IconMargin = 8; // shall we make it changable?
|
||||
};
|
||||
|
||||
#endif // SPKICONBUTTON_H
|
||||
@@ -1,61 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QPainter>
|
||||
#include <QScrollArea>
|
||||
#include "spkwindow.h"
|
||||
|
||||
class ImgView : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ImgView(QWidget *parent = nullptr) : QWidget(parent) { mPixmap = nullptr; }
|
||||
void SetPixmap(QPixmap *p) { mPixmap = p; if(p) setFixedSize(p->size()); update(); }
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e)
|
||||
{
|
||||
QPainter p(this);
|
||||
if(mPixmap)
|
||||
p.drawPixmap(0, 0, *mPixmap);
|
||||
p.end();
|
||||
e->accept();
|
||||
}
|
||||
|
||||
private:
|
||||
QPixmap *mPixmap;
|
||||
};
|
||||
|
||||
class SpkImgViewer : public SpkWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SpkImgViewer(QWidget *parent = nullptr);
|
||||
void ShowWithImage(int idx);
|
||||
void SetImageTotal(int a) { mTotalImg = a; }
|
||||
|
||||
public slots:
|
||||
void Clear();
|
||||
void SetPixmap(int idx, QPixmap *img);
|
||||
|
||||
private slots:
|
||||
void SwitchToImage(int idx);
|
||||
|
||||
protected:
|
||||
bool event(QEvent*) override;
|
||||
|
||||
private:
|
||||
void ResizeToFitImageSize(QSize);
|
||||
|
||||
private:
|
||||
QPushButton *mBtnPrev, *mBtnNext;
|
||||
QScrollArea *mImgArea;
|
||||
QLabel *mImgIndict;
|
||||
QMap<int, QPixmap*> mImgMap;
|
||||
int mCurrentImg, mTotalImg;
|
||||
QPixmap mIconLoading;
|
||||
|
||||
ImgView *mImgShow;
|
||||
};
|
||||
@@ -1,25 +0,0 @@
|
||||
#ifndef SPKJSONAPICONSUMER_H
|
||||
#define SPKJSONAPICONSUMER_H
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
|
||||
class SpkJsonApiConsumer: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SpkJsonApiConsumer();
|
||||
|
||||
private:
|
||||
QNetworkAccessManager mNet;
|
||||
|
||||
public slots:
|
||||
void RequestUrl(QUrl);
|
||||
|
||||
signals:
|
||||
void RequestFinish(QJsonDocument, int);
|
||||
};
|
||||
|
||||
#endif // SPKJSONAPICONSUMER_H
|
||||
@@ -1,34 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QFrame>
|
||||
#include <QTimeLine>
|
||||
|
||||
class SpkLoading : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SpkLoading(QWidget *parent = nullptr);
|
||||
virtual void paintEvent(QPaintEvent *e) override;
|
||||
virtual void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
private:
|
||||
QTimeLine *mAnimTimer;
|
||||
QList<int> mSizeList;
|
||||
int mUserHeight = 0;
|
||||
int dw, dh;
|
||||
double dx, dy;
|
||||
|
||||
public slots:
|
||||
void start() { mAnimTimer->start(); }
|
||||
void stop() { mAnimTimer->stop(); }
|
||||
void Begin() { start(); setVisible(true); }
|
||||
void End() { stop(); setVisible(false); }
|
||||
void setHeight(int h) { mUserHeight = h; }
|
||||
void reset();
|
||||
|
||||
private slots:
|
||||
void timer(int s);
|
||||
void loop();
|
||||
};
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
|
||||
/**
|
||||
* @brief Simple logging for Spark Store
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#pragma push_macro("signals")
|
||||
#undef signals
|
||||
#include <libnotify/notify.h>
|
||||
#define signals DUMMY
|
||||
#pragma pop_macro("signals")
|
||||
#include <QString>
|
||||
#include <QStringListModel>
|
||||
#include <QTextStream>
|
||||
#include <QFile>
|
||||
|
||||
class SpkLogger
|
||||
{
|
||||
QStringListModel mLogData;
|
||||
QString mLogPath;
|
||||
QFile mLogFile;
|
||||
QTextStream mLogWriter;
|
||||
static SpkLogger *Instance;
|
||||
void Initialize(QString suggestPath = "");
|
||||
bool NotifyViable = false;
|
||||
|
||||
public:
|
||||
SpkLogger(QString suggestPath = "");
|
||||
~SpkLogger();
|
||||
static SpkLogger *GetInstance() { return Instance; };
|
||||
void Log(QString message);
|
||||
void Warning(QString message);
|
||||
void Error(QString message, bool pop = false);
|
||||
void Critical(QString message);
|
||||
void Notify(QString);
|
||||
};
|
||||
|
||||
#define sLog(X) SpkLogger::GetInstance()->Log(X)
|
||||
#define sWarn(X) SpkLogger::GetInstance()->Warning(X)
|
||||
#define sErr(X) SpkLogger::GetInstance()->Error(X)
|
||||
#define sErrPop(X) SpkLogger::GetInstance()->Error(X,true)
|
||||
#define sCritical(X) SpkLogger::GetInstance()->Critical(X)
|
||||
#define sNotify(X) SpkLogger::GetInstance()->Notify(X)
|
||||
@@ -1,236 +0,0 @@
|
||||
//
|
||||
// Created by rigoligo on 2021/5/9.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "spkwindow.h"
|
||||
#include <vector>
|
||||
#include <QTextEdit>
|
||||
#include <QStackedWidget>
|
||||
#include <QButtonGroup>
|
||||
#include <QJsonObject>
|
||||
#include "spksidebartree.h" // In place of #include <QTreeWidget>
|
||||
#include <QPointer>
|
||||
#include <QTimeLine>
|
||||
#include <QQueue>
|
||||
#include "spkfocuslineedit.h"
|
||||
#include "spkiconbutton.h"
|
||||
#include "page/spkpageuitest.h"
|
||||
#include "page/spkpagehome.h"
|
||||
#include "page/spkpageapplist.h"
|
||||
#include "page/spkpageappdetails.h"
|
||||
#include "page/spkpagedownloads.h"
|
||||
#include "page/spkpagesettings.h"
|
||||
|
||||
class QNetworkReply;
|
||||
|
||||
namespace SpkUi
|
||||
{
|
||||
enum SpkStackedPages
|
||||
{
|
||||
PgInvalid = -1,
|
||||
PgHomepage,
|
||||
PgAppList,
|
||||
PgAppDetails,
|
||||
PgDownloads,
|
||||
PgSettings,
|
||||
PgQssTest // Must be at last
|
||||
};
|
||||
|
||||
const std::vector<SpkStackedPages> ResourceContexts
|
||||
{
|
||||
PgAppList
|
||||
};
|
||||
|
||||
class SpkSidebarSelector : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
QPushButton *mLastCheckedBtn;
|
||||
QTreeWidgetItem *mLastSelectedItem;
|
||||
QTreeWidget *mCategoryWidget;
|
||||
QVector<QTreeWidgetItem *> mUnusableItems; // Unselectable top level items; never changes
|
||||
|
||||
QTreeWidgetItem* mLastCategoryItem;
|
||||
int mLastCategoryPage;
|
||||
|
||||
public:
|
||||
SpkSidebarSelector(QObject *parent = nullptr) : QObject(parent)
|
||||
{
|
||||
mLastCheckedBtn = nullptr;
|
||||
mLastSelectedItem = nullptr;
|
||||
}
|
||||
// Tree item can either represent a page or a category, data of special roles
|
||||
// help identify them; Buttons instead can only represent a page
|
||||
constexpr static int RoleItemIsCategory = Qt::UserRole + 1;
|
||||
constexpr static int RoleItemCategoryPageId= Qt::UserRole + 2;
|
||||
void BindPageSwitcherButton(QAbstractButton* w)
|
||||
{
|
||||
connect(w, &QAbstractButton::toggled,
|
||||
this, &SpkSidebarSelector::ButtonToggled);
|
||||
connect(w, &QAbstractButton::pressed,
|
||||
this, &SpkSidebarSelector::ButtonPressed);
|
||||
}
|
||||
void BindCategoryWidget(QTreeWidget* w)
|
||||
{
|
||||
mCategoryWidget = w;
|
||||
connect(w, &QTreeWidget::itemPressed, this,
|
||||
&SpkSidebarSelector::TreeItemSelected);
|
||||
}
|
||||
void AddUnusableItem(QTreeWidgetItem *i) { mUnusableItems.append(i); }
|
||||
void GoBack()
|
||||
{
|
||||
emit SwitchToCategory(mLastCategoryPage, 0);
|
||||
mCategoryWidget->currentItem()->setSelected(false);
|
||||
mLastCategoryItem->setSelected(true);
|
||||
}
|
||||
|
||||
private slots:
|
||||
// We assume the objects in interest all have the correct properties
|
||||
void ButtonToggled(bool aBtnState)
|
||||
{
|
||||
auto b = qobject_cast<QPushButton*>(sender());
|
||||
if(mLastCheckedBtn)
|
||||
{
|
||||
if(mLastCheckedBtn != b)
|
||||
{
|
||||
mLastCheckedBtn->setChecked(false);
|
||||
mLastCheckedBtn = nullptr;
|
||||
}
|
||||
}
|
||||
else if(mLastSelectedItem)
|
||||
{
|
||||
mLastSelectedItem->setSelected(false);
|
||||
mLastSelectedItem = nullptr;
|
||||
}
|
||||
mLastCheckedBtn = b;
|
||||
auto id = b->property("spk_pageno").toInt();
|
||||
emit SwitchToPage(static_cast<SpkStackedPages>(id));
|
||||
}
|
||||
void ButtonPressed()
|
||||
{ // Prevent a selected button from being deselected by clicking on it
|
||||
auto b = qobject_cast<QPushButton*>(sender());
|
||||
if(mLastCheckedBtn == b)
|
||||
b->setChecked(false);
|
||||
}
|
||||
void TreeItemSelected(QTreeWidgetItem *item, int column)
|
||||
{
|
||||
if(mUnusableItems.contains(item))
|
||||
{
|
||||
UnusableItemSelected(item); return;
|
||||
}
|
||||
if(mLastCheckedBtn)
|
||||
{
|
||||
mLastCheckedBtn->setChecked(false);
|
||||
mLastCheckedBtn = nullptr;
|
||||
}
|
||||
mLastSelectedItem = item;
|
||||
auto id = item->data(column, RoleItemCategoryPageId).toInt();
|
||||
if(item->data(column, RoleItemIsCategory).toBool())
|
||||
emit SwitchToCategory(id, 0), mLastCategoryPage = id, mLastCategoryItem = item;
|
||||
else
|
||||
emit SwitchToPage(static_cast<SpkStackedPages>(id));
|
||||
}
|
||||
void UnusableItemSelected(QTreeWidgetItem *i)
|
||||
{
|
||||
i->setSelected(false);
|
||||
if(mLastSelectedItem)
|
||||
{
|
||||
mLastSelectedItem->setSelected(true);
|
||||
}
|
||||
else if(mLastCheckedBtn)
|
||||
{
|
||||
mLastCheckedBtn->setChecked(true);
|
||||
}
|
||||
}
|
||||
|
||||
signals:
|
||||
void SwitchToCategory(int aCategoryId, int aPage);
|
||||
void SwitchToPage(SpkStackedPages aPageId);
|
||||
};
|
||||
|
||||
class SpkMainWidget : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SpkMainWidget(QWidget *parent = nullptr);
|
||||
|
||||
QHBoxLayout *HorizontalDivide;
|
||||
|
||||
QStackedWidget *Pager;
|
||||
|
||||
// Category widget is for switching pages
|
||||
SpkIconButton *BtnSettings, *BtnFeedback, *BtnLogs, *BtnDayNight, *BtnBack;
|
||||
SpkSidebarTree *CategoryWidget;
|
||||
QMap<int, QTreeWidgetItem> *CategoryItemMap;
|
||||
SpkSidebarSelector *SidebarMgr;
|
||||
|
||||
QTreeWidgetItem *HomepageItem,
|
||||
*CategoryParentItem,
|
||||
*AppDetailsItem,
|
||||
*DownloadsItem,
|
||||
*UiTestItem;
|
||||
|
||||
// Title bar search bar
|
||||
SpkFocusLineEdit *SearchEdit;
|
||||
QAction *ActClearSearchBar, *ActSearchIcon;
|
||||
QTimeLine *SearchBarAnim;
|
||||
|
||||
//Pages
|
||||
SpkPageUiTest *PageQssTest;
|
||||
|
||||
SpkPageHome *PageHome;
|
||||
SpkPageAppList *PageAppList;
|
||||
SpkPageAppDetails *PageAppDetails;
|
||||
SpkPageDownloads *PageDownloads;
|
||||
SpkPageSettings *PageSettings;
|
||||
};
|
||||
}
|
||||
|
||||
class SpkMainWindow : public SpkWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
SpkUi::SpkMainWidget *ui;
|
||||
|
||||
public:
|
||||
SpkMainWindow(QWidget *parent = nullptr);
|
||||
|
||||
void PopulateCategories(QJsonArray);
|
||||
|
||||
private:
|
||||
void Initialize();
|
||||
|
||||
private:
|
||||
QPointer<QNetworkReply> mCategoryGetReply,
|
||||
mCategoryAppListGetReply,
|
||||
mAppDetailsGetReply;
|
||||
SpkUi::SpkStackedPages mCurrentPage = SpkUi::PgInvalid;
|
||||
QList<QPair<SpkIconButton*, QString>> mThemedUiIconReferences;
|
||||
|
||||
public slots:
|
||||
void ReloadThemedUiIcons();
|
||||
void RefreshCategoryData();
|
||||
|
||||
private slots:
|
||||
void SwitchDayNightTheme();
|
||||
|
||||
void SwitchToPage(SpkUi::SpkStackedPages page);
|
||||
|
||||
void CategoryDataReceived();
|
||||
// Enter a category (and switch pages)
|
||||
void EnterCategoryList(int aCategoryId, int aPage);
|
||||
void CategoryListDataReceived();
|
||||
// Search a keyword (and switch pages)
|
||||
void SearchKeyword(QString aKeyword, int aPage);
|
||||
void SearchDataReceived();
|
||||
// Enter the details page of an application (and switch pages)
|
||||
void EnterAppDetails(int aAppId);
|
||||
void AppDetailsDataReceived();
|
||||
|
||||
private:
|
||||
void PopulateAppList(QJsonObject appData, QString &&keyword);
|
||||
void PopulateAppDetails(QJsonObject appDetails);
|
||||
};
|
||||
@@ -1,20 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <QStyle>
|
||||
#include <QMessageBox>
|
||||
#include "spkdialog.h"
|
||||
|
||||
class SpkMsgBox : public SpkDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SpkMsgBox(QWidget *parent = nullptr);
|
||||
static int StaticExec(QString msg, QString title, QMessageBox::Icon = QMessageBox::NoIcon,
|
||||
QMessageBox::StandardButtons = QMessageBox::Ok, QString extra = "",
|
||||
bool expanded = false);
|
||||
private:
|
||||
static void AddButtons(SpkMsgBox *me, QMessageBox::StandardButtons b);
|
||||
QList<QMessageBox::StandardButton> mButtonList;
|
||||
static constexpr QSize IconSize {48, 48};
|
||||
static constexpr int Margin = 10;
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QLabel>
|
||||
|
||||
class SpkNotifyDot : public QLabel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SpkNotifyDot(QWidget *parent = nullptr);
|
||||
~SpkNotifyDot() {}
|
||||
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent *) override;
|
||||
// virtual int widthForHeight(int h) override;
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QLabel>
|
||||
#include <QWidget>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPropertyAnimation>
|
||||
#include <QSequentialAnimationGroup>
|
||||
|
||||
class SpkMainWindow;
|
||||
|
||||
namespace SpkUi
|
||||
{
|
||||
class SpkPopup : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SpkPopup(QWidget *parent, int aMillis = 3000);
|
||||
|
||||
public slots:
|
||||
void Show(QString aText);
|
||||
|
||||
private:
|
||||
QPoint MoveOffset;
|
||||
QLabel *mText;
|
||||
QHBoxLayout *mBox;
|
||||
QPropertyAnimation *mAnimFadeIn, *mAnimFadeOut;
|
||||
QSequentialAnimationGroup *mAnim;
|
||||
};
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <QColor>
|
||||
|
||||
namespace SpkUi
|
||||
{
|
||||
QColor ColorTextOnBackground(QColor);
|
||||
|
||||
namespace Qss
|
||||
{
|
||||
enum ColorSetIndex
|
||||
{
|
||||
GlobalBgnd = 0,
|
||||
ControlsBgnd,
|
||||
ControlsBgndHighlighted,
|
||||
SelectionBgnd, AccentColor = SelectionBgnd,
|
||||
SelectionBgndHighlighted, AccentColorHighlighted = SelectionBgndHighlighted,
|
||||
LightCtrlsGradLight,
|
||||
LightCtrlsGradDark,
|
||||
LightCtrlsGradDarker,
|
||||
LightCtrlsDisabledBackground,
|
||||
DarkCtrlsGradLight,
|
||||
DarkCtrlsGradDark,
|
||||
DarkCtrlsGradDarker,
|
||||
DarkCtrlsDisabledBackground,
|
||||
TextOnSelection, TextOnAccentColor = TextOnSelection,
|
||||
TextOnGlobalBgnd,
|
||||
TextOnControlsBgnd,
|
||||
TextLighter,
|
||||
TextEvenLighter,
|
||||
TextDisabled,
|
||||
GlossyEdge,
|
||||
ShadesEdge,
|
||||
ScrollBarNorm,
|
||||
ScrollBarHover,
|
||||
DivideLine,
|
||||
};
|
||||
|
||||
extern const std::list<ColorSetIndex> AccentColorExceptions;
|
||||
|
||||
extern const std::map<ColorSetIndex, const char *> ColorSet2Token;
|
||||
|
||||
extern const std::map<ColorSetIndex, QColor>
|
||||
DarkColorSet, LightColorSet;
|
||||
|
||||
using ColorSet = std::map<Qss::ColorSetIndex, QColor>;
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QQueue>
|
||||
#include <QSemaphore>
|
||||
#include <QMap>
|
||||
#include <QNetworkReply>
|
||||
#include <QVariant>
|
||||
|
||||
struct ResourceResult;
|
||||
class SpkResourceContext;
|
||||
class SpkPageBase;
|
||||
|
||||
class SpkResource : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum class ResourceType { HomeImage, AppIcon, TagIcon, AppScreenshot, };
|
||||
enum class ResourceStatus
|
||||
{
|
||||
Ready, ///< The resource is ready to be read now and the file link is included
|
||||
Deferred, ///< The resource is not in cache or outdated, and is being downloaded
|
||||
Failed, ///< The requested resource can not be downloaded and thus can not be loaded.
|
||||
};
|
||||
|
||||
private:
|
||||
struct ResourceTask
|
||||
{
|
||||
QString pkgName, path;
|
||||
ResourceType type;
|
||||
QVariant info;
|
||||
int id;
|
||||
};
|
||||
|
||||
static const QMap<ResourceType, QString> ResourceName;
|
||||
|
||||
public:
|
||||
SpkResource(QObject *parent = nullptr);
|
||||
ResourceResult
|
||||
RequestResource(const int aId, const QString &aPkgName, ResourceType aType, const QString &aPath,
|
||||
const QVariant &aInfo = 0);
|
||||
void PurgeCachedResource(const QString &aPkgName, SpkResource::ResourceType aType,
|
||||
const QVariant &aInfo);
|
||||
|
||||
inline QString GetCachePath(const ResourceTask &task);
|
||||
|
||||
ResourceResult CacheLookup(QString pkgName, ResourceType type, QVariant info);
|
||||
|
||||
/**
|
||||
* @brief When the resource context was changed, the new context needs to acquire the resource
|
||||
* manager, so the resource manager can download resource for the new context.
|
||||
*
|
||||
* A resource context, in Spark Store, is likely to be a "page" of the UI. AppList is
|
||||
* a page, Homepage is a page, AppDetails is a page. But each category is not a separated
|
||||
* context; they're all from AppList page.
|
||||
* @param dest Pass a SpkResourceContext as the resource acquisition destination. Signals will
|
||||
* be connected in this function internally. When a resource was downloaded, this
|
||||
* object will be notified.
|
||||
* @param clearQueue determines if the awaiting tasks needs to be cleared.
|
||||
* @param stopOngoing determines if ongoing tasks needs to be terminated.
|
||||
*/
|
||||
void Acquire(SpkPageBase *dest, bool stopOngoing, bool clearQueue = true);
|
||||
|
||||
public:
|
||||
static SpkResource* Instance;
|
||||
const int mMaximumConcurrent; ///< Maximum number of concurrent resource downloads
|
||||
const QString mCacheDirectory;///< Where caches were stored
|
||||
|
||||
private slots:
|
||||
void ResourceDownloaded();
|
||||
void TryBeginAwaitingTasks();
|
||||
|
||||
private:
|
||||
ResourceResult LocateCachedResource(const ResourceTask &task);
|
||||
|
||||
signals:
|
||||
void AcquisitionFinish(int id, ResourceResult result);
|
||||
|
||||
private:
|
||||
// Operations to mAwaitingRequests and mWorkingRequests must be all made synchronously.
|
||||
// When connecting signal/slot pairs regarding operations to them, use QueuedConnection.
|
||||
QQueue<ResourceTask> mAwaitingRequests;
|
||||
QSemaphore *mRequestSemaphore;
|
||||
QMap<QNetworkReply*, int> mWorkingRequests;
|
||||
};
|
||||
|
||||
|
||||
struct ResourceResult
|
||||
{
|
||||
SpkResource::ResourceStatus status;
|
||||
QByteArray data;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(ResourceResult);
|
||||
|
||||
/**
|
||||
* @brief SpkResourceContext is meant to be used by connecting signals from it. An object inheriting
|
||||
* it would be theoretically a resource context. A resource context can acquire a SpkResource
|
||||
* management object for downloading resources. More details at SpkResource::Acquire.
|
||||
*/
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QTreeWidget>
|
||||
|
||||
namespace SpkUi
|
||||
{
|
||||
class SpkSidebarTree : public QTreeWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SpkSidebarTree(QWidget* parent = nullptr);
|
||||
protected:
|
||||
void mouseMoveEvent(QMouseEvent *) override;
|
||||
void mousePressEvent(QMouseEvent *) override;
|
||||
};
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QString>
|
||||
#include <QSettings>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
|
||||
#include "spklogging.h"
|
||||
#include "spkresource.h"
|
||||
#include "spkconfig.h"
|
||||
|
||||
class SpkMainWindow;
|
||||
|
||||
/**
|
||||
* @brief SpkStore class is the core of the store client side program, it is constructed first and
|
||||
* handling all processing after the launch. All client side data should be held by it,
|
||||
* including preferences class, category names, request URLs, downloads status, packaging
|
||||
* backend interfaces and so on.
|
||||
*/
|
||||
class SpkStore : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static SpkStore *Instance;
|
||||
SpkConfig *mCfg;
|
||||
SpkStore(bool aCli, QString &aLogPath);
|
||||
~SpkStore();
|
||||
|
||||
SpkMainWindow* GetRootWindow() { return mMainWindow; }
|
||||
|
||||
void SetApiRequestUrl(QString aUrlStr) { mApiRequestUrl = aUrlStr; }
|
||||
QString GetApiRequestUrl() { return mApiRequestUrl; }
|
||||
QNetworkReply *SendApiRequest(QString path, QJsonDocument param = QJsonDocument());
|
||||
QNetworkReply *SendResourceRequest(QString path); ///< WARNING: Only intended for SpkResource!
|
||||
QNetworkReply *SendDownloadRequest(QUrl file, qint64 fromByte = -1, qint64 toByte = -1);
|
||||
|
||||
QNetworkReply *SendCustomHeadRequest(QNetworkRequest);
|
||||
|
||||
private:
|
||||
SpkLogger *mLogger;
|
||||
SpkMainWindow *mMainWindow = nullptr;
|
||||
SpkResource *mResMgr = nullptr;
|
||||
QNetworkAccessManager *mNetMgr = nullptr;
|
||||
QString mDistroName,
|
||||
mApiRequestUrl,
|
||||
mResourceRequestUrl,
|
||||
mUserAgentStr,
|
||||
mConfigPath;
|
||||
};
|
||||
@@ -1,27 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtWidgets>
|
||||
#include <QVector>
|
||||
|
||||
/**
|
||||
* @brief SpkStretchLayout is meant solely for use with app list, where each layout item is
|
||||
* considered the same size.
|
||||
*/
|
||||
class SpkStretchLayout : public QLayout
|
||||
{
|
||||
public:
|
||||
SpkStretchLayout(QWidget *parent = nullptr);
|
||||
~SpkStretchLayout();
|
||||
|
||||
void addItem(QLayoutItem *item) override;
|
||||
QSize sizeHint() const override;
|
||||
QSize minimumSize() const override;
|
||||
int count() const override;
|
||||
QLayoutItem* itemAt(int) const override;
|
||||
QLayoutItem* takeAt(int) override;
|
||||
void setGeometry(const QRect &rect) override;
|
||||
|
||||
private:
|
||||
QVector<QLayoutItem*> mItems;
|
||||
};
|
||||
@@ -1,71 +0,0 @@
|
||||
//
|
||||
// Created by rigoligo on 2021/5/8.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPixmap>
|
||||
#include <QPainter>
|
||||
#include <QBrush>
|
||||
#include <QPushButton>
|
||||
#include <QMainWindow>
|
||||
|
||||
namespace SpkUi
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
class SpkWindow;
|
||||
|
||||
class SpkTitleBarDefaultButton : public QPushButton
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SpkTitleBarDefaultButton(QWidget* parent = nullptr);
|
||||
enum OperationButton { Minimize = 1, MaximizeRestore = 2, Close = 4, Restore = 3 };
|
||||
void SetRole(OperationButton);
|
||||
constexpr static int ButtonWidth = 60;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
private:
|
||||
OperationButton Role;
|
||||
void PaintSymbol(QPainter &);
|
||||
};
|
||||
|
||||
class SpkTitleBar : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
friend class SpkWindow;
|
||||
public:
|
||||
SpkTitleBar(QWidget *parent = nullptr);
|
||||
~SpkTitleBar();
|
||||
static constexpr int Height = 48;
|
||||
using OperationButton = SpkTitleBarDefaultButton::OperationButton;
|
||||
void SetOperationButton(OperationButton);
|
||||
|
||||
void SetIcon(QPixmap p) { mIcon->setPixmap(p); }
|
||||
void SetTitle(QString t) { mTitle->setText(t); }
|
||||
QString GetTitle() { return mTitle->text(); }
|
||||
void SetUseIcon(bool t) { mIcon->setVisible(t); }
|
||||
void SetLinkedWindow(SpkWindow *w) { mLinkedWindow = w; }
|
||||
|
||||
QHBoxLayout *GetUserSpace() { return mUserSpace; }
|
||||
protected:
|
||||
bool event(QEvent*) override;
|
||||
|
||||
private:
|
||||
QLabel *mIcon;
|
||||
QLabel *mTitle;
|
||||
SpkWindow *mLinkedWindow;
|
||||
QHBoxLayout *mMainLayout, *mUserSpace, *mBtnGroup;
|
||||
SpkTitleBarDefaultButton *mBtnMin, *mBtnMaxRestore, *mBtnClose;
|
||||
|
||||
private slots:
|
||||
void CloseWindow();
|
||||
void MinimizeWindow();
|
||||
void MaximizeRestoreWindow();
|
||||
};
|
||||
@@ -1,81 +0,0 @@
|
||||
//
|
||||
// Created by rigoligo on 2021/5/8.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <QString>
|
||||
#include <QSize>
|
||||
#include <QColor>
|
||||
#include <map>
|
||||
|
||||
#include "spkqsshelper.h"
|
||||
#include "dtk/spkdtkplugin.h"
|
||||
|
||||
namespace SpkUi
|
||||
{
|
||||
|
||||
enum SpkUiStyle { Invalid, Light, Dark };
|
||||
enum SpkButtonStyle { Normal = 0, Recommend, Warn };
|
||||
|
||||
class SpkPopup;
|
||||
|
||||
constexpr int StackTraceArraySize = 64;
|
||||
constexpr const char * const StoreIconName = "spark-store";
|
||||
|
||||
class UiMetaObject : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
static UiMetaObject *sGlobalInstance;
|
||||
public:
|
||||
UiMetaObject() {}
|
||||
public slots:
|
||||
void SetAccentColor(QColor);
|
||||
void SetDarkLightTheme(bool isDark);
|
||||
signals:
|
||||
void SetThemeButtonVisible(bool);
|
||||
};
|
||||
|
||||
extern UiMetaObject SpkUiMetaObject;
|
||||
extern SpkUiStyle CurrentStyle;
|
||||
extern QString StylesheetBase, CurrentStylesheet;
|
||||
extern QColor ColorLine, ColorBack,
|
||||
ColorBtnMaskUnselected, ///< SpkIconButton icon mask colors, unselected & selected
|
||||
ColorBtnMaskSelected;
|
||||
extern QSize PrimaryScreenSize;
|
||||
extern SpkDtkPlugin *DtkPlugin;
|
||||
extern QStyle *OldSystemStyle;
|
||||
extern std::map<Qss::ColorSetIndex, QColor> CurrentColorSet;
|
||||
|
||||
extern SpkPopup *Popup;
|
||||
|
||||
namespace States
|
||||
{
|
||||
extern bool IsDDE, IsUsingDtkPlugin;
|
||||
|
||||
extern bool DoRespondAutoTheme;
|
||||
extern int LightDarkMode; ///< Tied to settings UI value
|
||||
|
||||
bool ThemeConfigCallback();
|
||||
}
|
||||
|
||||
namespace Priv
|
||||
{
|
||||
extern bool CrashHandlerActivated;
|
||||
using namespace SpkUi::Qss;
|
||||
}
|
||||
|
||||
void Initialize();
|
||||
void GuessAppropriateTheme();
|
||||
void PrepareForDeepinDesktop();
|
||||
bool CheckIsDeepinDesktop();
|
||||
QString StylesheetFromColors(Qss::ColorSet);
|
||||
|
||||
QIcon GetThemedIcon(QString);
|
||||
|
||||
void CrashSignalHandler(int);
|
||||
|
||||
void SetGlobalStyle(const SpkUiStyle, const bool aPreserveAccentColor);
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user