Compare commits
2715 Commits
v4.9.1-331
...
feature-is
| Author | SHA1 | Date | |
|---|---|---|---|
| 8c0773aab2 | |||
| e596de766a | |||
| 12c3605db8 | |||
| ea51827ed6 | |||
| ff4a78ae93 | |||
| 4201d0abd3 | |||
| 3a0daea1fb | |||
| 19ff2a1fb7 | |||
| 2efd0e8bc9 | |||
| 17e4923c98 | |||
| 1a2c90cfb0 | |||
| 6dca8cf33c | |||
| 322774fc78 | |||
| 8128aa603c | |||
| 06c084a1ec | |||
| b05fb22e42 | |||
| 2ab9b175e9 | |||
| 930fc88183 | |||
| e8dec7d101 | |||
| 28fcd20186 | |||
| f37b3a9729 | |||
| d8483686d2 | |||
| cb67b4f01e | |||
| 236ecb9f4f | |||
| 1e9f17bba5 | |||
| 877335f47b | |||
| 676b81b649 | |||
| f95365c6ba | |||
| 97022f19f6 | |||
| 9f60dd7c55 | |||
| 0124fa4d8e | |||
| e3eef66884 | |||
| 56395bc6fa | |||
| 7f2fd57d43 | |||
| fb6d96e79d | |||
| 369edbe04e | |||
| 2a56165424 | |||
| 48b8c46cdf | |||
| 6b33a0a2ff | |||
| b38d90b107 | |||
| 896f43246b | |||
| b5e3d3a03e | |||
| 65fc3e6304 | |||
| 3f895d2cc3 | |||
| 58cebe900e | |||
| ecf003bd84 | |||
| 7c2dae7125 | |||
| 8451a776dd | |||
| 2cb91a7917 | |||
| 4d9b53420f | |||
| 82300e4b4e | |||
| 5e9dc881d5 | |||
| 1a1ed4a159 | |||
| b9d6dfc83a | |||
| fbc1ccf886 | |||
| f33b699723 | |||
| a970db9ca1 | |||
| 28d983dc00 | |||
| 24193a6456 | |||
| bb264496cc | |||
| 11b75a9c52 | |||
| eebc531707 | |||
| 5f5dc8e50f | |||
| 017188a409 | |||
| f23ac762e2 | |||
| 829991571e | |||
| af01bd6990 | |||
| 1150be4f52 | |||
| c685df4fd7 | |||
| f8d372207e | |||
| 83358fab7d | |||
| 6ac1465329 | |||
| 596b5603cf | |||
| e0cd733d63 | |||
| 1d53a12082 | |||
| 7f12dc09a0 | |||
| 7254db3c0e | |||
| 5de5d07bca | |||
| 3442602ff8 | |||
| a57e4caa22 | |||
| 05006d91b5 | |||
| cfd67f3160 | |||
| a66c6daa82 | |||
| 73818acb9f | |||
| ebbbc618b9 | |||
| 5a560869d3 | |||
| 81c3381d94 | |||
| f0b7cdda32 | |||
| 72c5c844fc | |||
| e405be9deb | |||
| 752f79ad65 | |||
| e377a52e74 | |||
| 91c343a02b | |||
| 1fbc834597 | |||
| 9251ade73c | |||
| d759ec2d66 | |||
| 22053f5c7f | |||
| ab968673e1 | |||
| bec06b63c7 | |||
| 8efe5ec460 | |||
| 025e72101f | |||
| bd1887baad | |||
| 082e9b376a | |||
| 5014eda3f2 | |||
| 1b4852ae0c | |||
| 52a23f5bde | |||
| baae314d85 | |||
| 85372416c0 | |||
| 6d8908fe57 | |||
| 4d0d9c0b48 | |||
| a68782203b | |||
| 2fcfaf2ccd | |||
| d58a6df56a | |||
| 2f8a783565 | |||
| 9234a2f4ee | |||
| 662dd88be7 | |||
| ba64292b76 | |||
| 6fd43dd61b | |||
| 4ce7eee8eb | |||
| e3c2711b64 | |||
| e00df4a066 | |||
| 9764c2ce1a | |||
| f588c2d981 | |||
| e5dad8a8ce | |||
| 3818160a5e | |||
| 2367a0bf8a | |||
| b2e728331a | |||
| 7af3233152 | |||
| 243ad6afb1 | |||
| 0c3a063d86 | |||
| 558aa9a09e | |||
| 33c9a2e90b | |||
| e618a0d5fd | |||
| ccc97a93da | |||
| 3e16f59dc5 | |||
| c9993de3ca | |||
| e3c140e5fd | |||
| b2f6d111a7 | |||
| ea03e7a73f | |||
| c08f268b04 | |||
| f6423cb7ff | |||
| 89f00d7412 | |||
| 68061d96ed | |||
| 388c11b173 | |||
| ced7202d04 | |||
| 07c7d37d3d | |||
| 030c10c6cc | |||
| 16162a6944 | |||
| 5b9879e8a0 | |||
| 99446c7b74 | |||
| 077b865b81 | |||
| e1a95a241a | |||
| 50e15fa79a | |||
| 933c3c4fce | |||
| 2a79c9cddd | |||
| 7d6fb3e815 | |||
| 1c95a6b968 | |||
| 23c7a741cc | |||
| 46bdc4e4f7 | |||
| f41836615d | |||
| d883b29cde | |||
| d36055276d | |||
| e0c1d8169d | |||
| c18945113c | |||
| 6ec3d21994 | |||
| add6b2bc5e | |||
| 936c793ddf | |||
| bb08a845fc | |||
| a36c2085ef | |||
| d7e0de88d7 | |||
| 931213dc82 | |||
| 11c7959b38 | |||
| 4989debca5 | |||
| 082a5fbff8 | |||
| 396bfbf52d | |||
| c4ad84d0c6 | |||
| b2dc318257 | |||
| d28595afdd | |||
| c2cd7b6f8a | |||
| da997ad544 | |||
| f374f105ce | |||
| 48459c84e1 | |||
| 8f72f80788 | |||
| fef66248ea | |||
| d3e499696f | |||
| 4631d4daeb | |||
| 9bdf69e9a6 | |||
| 861b8312e1 | |||
| c4763ea342 | |||
| ff0dcfd7e1 | |||
| 6c558a1a17 | |||
| e0870b875f | |||
| dae502bf55 | |||
| 7e26003698 | |||
| 7a5e27cffa | |||
| 0711d72f6d | |||
| 07331efffb | |||
| 585acb9bae | |||
| 13e9ba4f48 | |||
| 9434d7f9ba | |||
| 11643b9be0 | |||
| 2bec88c130 | |||
| ef9fd9d256 | |||
| 580e86c148 | |||
| 9ff97dde77 | |||
| 207b650c34 | |||
| 1ce7cd8ee3 | |||
| b015d76004 | |||
| 5f622d894d | |||
| faffbbfa87 | |||
| d494957880 | |||
| c37b299ab7 | |||
| 41331d23a0 | |||
| 5e3a38f52d | |||
| 21c8f4cf62 | |||
| fb08bc59be | |||
| 680590e6c2 | |||
| ee169b55c5 | |||
| d3caa5d66c | |||
| c195be5137 | |||
| 40ce144fee | |||
| ba2fd87b21 | |||
| 0e385e193f | |||
| 341eabee27 | |||
| 091948cdd1 | |||
| a2d439e207 | |||
| b2a1ce54a3 | |||
| 1d96e1f92d | |||
| 42fd666ba0 | |||
| 2aeaecfaf3 | |||
| 44d039658e | |||
| 90a8cce831 | |||
| 9bf019530d | |||
| fd933f9d59 | |||
| 176dc4fe02 | |||
| 739413f450 | |||
| 1b5a62e018 | |||
| 6bf74b4e03 | |||
| 537e59759b | |||
| 13f937dc0e | |||
| e3f0c2bb11 | |||
| 2eabc52aa7 | |||
| cf8615c6c3 | |||
| ab7bcc2b14 | |||
| 99b0010784 | |||
| 4af170d4fa | |||
| c45d4b5e19 | |||
| 9fca1f1551 | |||
| b8662e24a0 | |||
| ad1bee4b56 | |||
| 69597a83a4 | |||
| 45a0f6fa1f | |||
| 18ee571604 | |||
| d50615633f | |||
| 7e8702363c | |||
| f02032dd47 | |||
| f486b3aba9 | |||
| 9afa8ad61b | |||
| 63f315e294 | |||
| 9debcdf55b | |||
| 130cb68b83 | |||
| 4895bf694b | |||
| 414aaeb5ea | |||
| b0d1204341 | |||
| 9d76bcc06e | |||
| 9e79b0d37e | |||
| 44c1f26f88 | |||
| 4be0ea9a96 | |||
| 61d16a9b50 | |||
| 848b41ea76 | |||
| 2bd3990404 | |||
| 552da837c1 | |||
| 192b1db9c9 | |||
| 0d06701e0d | |||
| 943956c1b7 | |||
| 5a47e4f87b | |||
| 731cdab9df | |||
| f714beadab | |||
| d9d7e713ba | |||
| 249b5ac876 | |||
| 14d961ed07 | |||
| 3315686440 | |||
| bea3cdeacb | |||
| 1d10028353 | |||
| ee6f53ac92 | |||
| cdfda0d175 | |||
| c6dbd167c9 | |||
| b404bb91f9 | |||
| a2488fe0c7 | |||
| 7602e27ac5 | |||
| 6d21a5e8ae | |||
| 77a1ae68ce | |||
| ccbacf6d37 | |||
| d32ab37358 | |||
| 2f14607b03 | |||
| be599a24fd | |||
| c7ab3339f8 | |||
| 33c408d7e5 | |||
| 774f97261f | |||
| 55e7193149 | |||
| 76dedfbbc8 | |||
| bfe6849ad2 | |||
| b23e5ea441 | |||
| d17bb2ac83 | |||
| 70cc9bbcb6 | |||
| 7ed1a37801 | |||
| c30a2cca6d | |||
| 2c8dbf2554 | |||
| 6eb37b7e52 | |||
| 9a55cc297a | |||
| 2bbe148971 | |||
| 986d41d0c3 | |||
| 07a72bce77 | |||
| 8384464066 | |||
| 1e96f3e11b | |||
| 21f99df976 | |||
| cb087fb5fb | |||
| db03b55850 | |||
| 457f050948 | |||
| f4afda913e | |||
| 2300695607 | |||
| 32c318cc61 | |||
| 7fd5a37b4c | |||
| a805e56a7c | |||
| 7679c750cf | |||
| 5440a1faf5 | |||
| ce840cf33e | |||
| 82fc7d01fc | |||
| 37a2c5171d | |||
| b72f751dc0 | |||
| fa740bacb3 | |||
| 22e92cdaf6 | |||
| ac72abe105 | |||
| aaa2c6330e | |||
| c338bf4f00 | |||
| aec874b3e0 | |||
| dc3f3240c6 | |||
| a3ddf54afc | |||
| d840fab316 | |||
| 125701534d | |||
| be85ba6c47 | |||
| bcba6c4230 | |||
| 453ca0ceea | |||
| dc4e345ea8 | |||
| 946bd39fb6 | |||
| 83610a98f4 | |||
| e21d8a5ac5 | |||
| 3b2f5c6749 | |||
| 43c840cd94 | |||
| 9f7b1acef9 | |||
| 08ac765e9c | |||
| 15a3624e55 | |||
| ce16ad471b | |||
| c20a9e86d0 | |||
| 8e068684e0 | |||
| 31d8a442a3 | |||
| f534216009 | |||
| 2a808e3ac9 | |||
| 42f5cbe9a4 | |||
| d1e87d552d | |||
| fa457fa337 | |||
| 5dd0734aad | |||
| fa2c86c3f1 | |||
| 1753224cc4 | |||
| e3cece6654 | |||
| f01e79d303 | |||
| 5d89a2c26d | |||
| 2ff948dab1 | |||
| ebe560bc2b | |||
| 7dd0bdfd73 | |||
| af3797afc7 | |||
| 0821f00584 | |||
| 163a1a7f1f | |||
| 02b9d15134 | |||
| 4ab2a23840 | |||
| 2f35f07ba0 | |||
| 76cfda2df1 | |||
| fc705578b7 | |||
| c6c544f699 | |||
| ec96fc3258 | |||
| bfa0b7bd11 | |||
| 26fc068d29 | |||
| a035418ff9 | |||
| c40b1f5391 | |||
| 848d3f27bd | |||
| 676011eef3 | |||
| 3319fd29de | |||
| d3233c379f | |||
| eb7c5d6285 | |||
| b32bb19051 | |||
| 5a7001dd66 | |||
| bdeb0c79eb | |||
| bb29702db8 | |||
| 4138f2861c | |||
| 33050a7c94 | |||
| 4fef613390 | |||
| 15565281a9 | |||
| 39d3c4d3c8 | |||
| 443c8d7eaf | |||
| 0195af422c | |||
| 7d05d42e14 | |||
| 322da11319 | |||
| b46da2751b | |||
| 4999ba6563 | |||
| 5b3aec8e19 | |||
| 6cc2f3af26 | |||
| 3a4b3326e7 | |||
| 51c75947c9 | |||
| 19bb89b6f1 | |||
| 6e2ec70434 | |||
| 793f2f241a | |||
| 72f3d4a379 | |||
| 6b6a7dd81e | |||
| ffa4257eb4 | |||
| 22c06286c2 | |||
| 1d600f370a | |||
| ac3788541b | |||
| 015418b56a | |||
| 9c066431b4 | |||
| 3f2b59aecf | |||
| 1c3d78dc17 | |||
| 9fc9f0362f | |||
| ee131da96b | |||
| 843a2f8831 | |||
| cfb48c07ff | |||
| 3952139324 | |||
| d9665a8464 | |||
| b4d44d6e0a | |||
| bba8261d97 | |||
| 134df71aba | |||
| 0752813c09 | |||
| 28744ce9ce | |||
| 1aadf7bd38 | |||
| 4a7e0a8b4d | |||
| 9780aa532a | |||
| 2920ca4975 | |||
| c20f92f2cc | |||
| 9c2c4562aa | |||
| 96d10703c7 | |||
| b58baf565c | |||
| 1a3f0f87d5 | |||
| 9ce4ff54ba | |||
| a6605e6044 | |||
| 61f77a6fcc | |||
| d39755efe6 | |||
| ddf7d6f94d | |||
| 17ad25aff3 | |||
| b169ce66b4 | |||
| c0e34b3edb | |||
| 7936cb2b9f | |||
| 2bf662ee27 | |||
| a0c1a14987 | |||
| ab01fac150 | |||
| 2ce35ab8a5 | |||
| 50db76ce70 | |||
| 30cb1b8f87 | |||
| 470256411d | |||
| 364f089d75 | |||
| fc0c710172 | |||
| 18314347de | |||
| 87b9ff7054 | |||
| a4c7aa6338 | |||
| 8d6628404c | |||
| e383abf942 | |||
| d0c9c0f2f5 | |||
| f2ebc7796f | |||
| 6e6b107a80 | |||
| 4d29ff8752 | |||
| 56226b8620 | |||
| 240d3ea304 | |||
| e9ca19fa41 | |||
| 821d21a2e1 | |||
| 9009567226 | |||
| 6506012d78 | |||
| cc4b685a28 | |||
| 5d21f4e29f | |||
| e84973f0e6 | |||
| a997f77584 | |||
| b70fb261d4 | |||
| cbef1095d6 | |||
| e3f6d64fa9 | |||
| 6f5f72194a | |||
| 8ff396e05b | |||
| 6fa4bf75bf | |||
| 9c11f7f70e | |||
| c8cd753022 | |||
| 12d94c7d0a | |||
| d1159c30d1 | |||
| 8b241ec569 | |||
| 07f68f050b | |||
| f8c61b5d53 | |||
| 791bf000ef | |||
| 515a34ecf9 | |||
| 3e74b39b45 | |||
| c3eba42b17 | |||
| 13ab6f7b38 | |||
| 7ee9913964 | |||
| 96f0c03ff2 | |||
| 7c3f91c296 | |||
| cd9d0b5456 | |||
| cb4b83ddb4 | |||
| 449836cbd0 | |||
| a028639138 | |||
| c34e5f0a3d | |||
| 06f008d577 | |||
| 08a7491fa7 | |||
| faa9d50426 | |||
| 493a444990 | |||
| 596cc4ca15 | |||
| a14ea13dd7 | |||
| 0cfce764ff | |||
| 6c0f7f8cb3 | |||
| 4ce17aa6a3 | |||
| c58db04155 | |||
| c47ab8fc41 | |||
| 6c88782635 | |||
| 1ae905b0b4 | |||
| d0dc009906 | |||
| 99ffde9b67 | |||
| 3d56da3b6f | |||
| dc3ae1d36d | |||
| 4e9d5357c8 | |||
| a1d182a82c | |||
| 6efe9328b1 | |||
| e8645cd717 | |||
| 7792574f20 | |||
| 54131d507b | |||
| 5609a95382 | |||
| 3ab3229580 | |||
| 8d1f300241 | |||
| d00f50bcf8 | |||
| 624fb934e4 | |||
| 965b6b3f66 | |||
| f98726fa18 | |||
| 495070a14e | |||
| e8b00cc87f | |||
| 6823f27ff3 | |||
| c0b561cb78 | |||
| d02bdf9a8a | |||
| 7029c170a4 | |||
| 6afe9b2f3c | |||
| 54c9850014 | |||
| 3123045a91 | |||
| 16614ac2d1 | |||
| 74fda1fc17 | |||
| 563d9123c8 | |||
| 8af97a44c8 | |||
| 75e032b1f9 | |||
| 7786a1b2a6 | |||
| abd854ac3b | |||
| 96d60fefd4 | |||
| 681c26a6a3 | |||
| ef72119a48 | |||
| 051371b0d8 | |||
| 2d5420efec | |||
| 59cc581645 | |||
| 140012e000 | |||
| dd29cd586f | |||
| cbc65e4ccd | |||
| 5f337e3905 | |||
| 20eb18d3f0 | |||
| e6191e8c37 | |||
| 47b0361401 | |||
| d4a9f2ab41 | |||
| 8088627de3 | |||
| 1042ed675f | |||
| cad0233509 | |||
| bbf20c20a2 | |||
| 5e662ef5fe | |||
| 01830c7e81 | |||
| dd2116a12b | |||
| 89ead6b348 | |||
| 5f014f6f6b | |||
| 772d5de3d9 | |||
| 8f55051748 | |||
| e8553116b6 | |||
| b16fcb6725 | |||
| e42fb2ab66 | |||
| 32574ba33a | |||
| 1a734c32a4 | |||
| 764e6bb6fb | |||
| d695eefbe8 | |||
| b0491f48d6 | |||
| 15885fa6b0 | |||
| 00f90d3617 | |||
| 47beb3eeb2 | |||
| e41b6e4430 | |||
| f72095efc1 | |||
| 163ffd9308 | |||
| 762c43bd6f | |||
| 0660e132aa | |||
| aa0f27c61b | |||
| adb6691818 | |||
| b0f2d3f068 | |||
| a25cd0a07f | |||
| 1fc43ca588 | |||
| c1fd2e48db | |||
| 3ed5795205 | |||
| 2be268b2e6 | |||
| 8f5aee3a8c | |||
| f11f391940 | |||
| ad12b3f9ef | |||
| 7bf56cc342 | |||
| 176d4dd940 | |||
| 8756144018 | |||
| dfba5cdf99 | |||
| 3deb83ac8d | |||
| e7c4ffdd8a | |||
| 05747c2ecf | |||
| 3241ff9935 | |||
| 6e40349f20 | |||
| 0675eab81a | |||
| 8c9b1371dc | |||
| e6daee0faf | |||
| 45d8e5a869 | |||
| f4d16ff8f9 | |||
| 28266cd06d | |||
| 1c0b8b1382 | |||
| 35506c75f5 | |||
| 919db31ec3 | |||
| f716712f14 | |||
| 30a110e83b | |||
| c62dd66ad7 | |||
| ff876a55ba | |||
| c084f786f9 | |||
| 5e36bd7955 | |||
| 8b00b1bb2a | |||
| 923bdc1639 | |||
| 36e99a4a7e | |||
| e0f5a668ab | |||
| 6f01610d10 | |||
| b94c1eedfa | |||
| 2747857db3 | |||
| 0b1991e34d | |||
| 78d5d4b39f | |||
| 83199b6a4e | |||
| 0b51155177 | |||
| 32f583825a | |||
| 14e2784ab8 | |||
| d2b2f5e306 | |||
| d78de995b2 | |||
| ad4ca04db3 | |||
| 36e246fd30 | |||
| 59e913c529 | |||
| 040de6d458 | |||
| 66d0dba9c6 | |||
| 877490ce01 | |||
| cf12312d97 | |||
| 1e7edd9e85 | |||
| 3bd4427348 | |||
| 18013fe582 | |||
| ebb22d8d13 | |||
| 20161e6ca1 | |||
| 68d32ae429 | |||
| 5a377913bb | |||
| 8e5ceb1e0e | |||
| 034db094e1 | |||
| 541ebe8a29 | |||
| 8114e2a74a | |||
| 27350c5c70 | |||
| 2c3a395b50 | |||
| 983bbfc309 | |||
| d4a651ce63 | |||
| c091a47900 | |||
| a488608969 | |||
| e715a46285 | |||
| f9a2d56acc | |||
| dc8280c025 | |||
| 4e53b1fb91 | |||
| 0af479e441 | |||
| 559164ebce | |||
| 9f694085fd | |||
| b5c897170b | |||
| 72926f5046 | |||
| ee21dbc643 | |||
| 0f9b3c94f0 | |||
| 36704af531 | |||
| 6ae44c34d1 | |||
| dce756e53f | |||
| c4035d319e | |||
| f37200f902 | |||
| 3dc65fb415 | |||
| c646251b34 | |||
| eb1def1768 | |||
| 27471cbf61 | |||
| e59e1c1e65 | |||
| 1eeec1c89b | |||
| 90e947b65d | |||
| a96fe9144a | |||
| 4d06707fab | |||
| ab202abe0a | |||
| 56c1dbb6cb | |||
| 83afd7448f | |||
| 477ffa0c33 | |||
| 57668ec97d | |||
| 26b0f33f1c | |||
| 8e0dcd74e5 | |||
| 88842de6c7 | |||
| b0647bf3a9 | |||
| 7837318390 | |||
| c7143a6f89 | |||
| 97219323d3 | |||
| 417633b623 | |||
| 2f35e6ac56 | |||
| 331e4fc410 | |||
| 25768d8cae | |||
| 9d00e53b73 | |||
| 3ef9a38342 | |||
| 898f72a218 | |||
| 49091b7a72 | |||
| 670f840be1 | |||
| 92cab5ae6a | |||
| 614a57580c | |||
| ba763e9d9c | |||
| 928bb54f27 | |||
| db1da76ff6 | |||
| 425fcf0554 | |||
| 89c2a58914 | |||
| 850b80688a | |||
| 60d5f1244e | |||
| 979081dd7b | |||
| 9348f324d0 | |||
| 0b2148b105 | |||
| 427e219677 | |||
| d0abf6c536 | |||
| efbaa821a1 | |||
| 72d96dae47 | |||
| 9f53652a00 | |||
| 7c8670d82c | |||
| fb26e77c78 | |||
| 75e7b6620d | |||
| cfd9e61ad2 | |||
| 7d922f9620 | |||
| 05bd26605b | |||
| a91af5035d | |||
| e5de70af66 | |||
| 3f7996f523 | |||
| 78b0c2e1cd | |||
| b0047717bf | |||
| 4f1a18479e | |||
| 3df078bbd6 | |||
| d841dc635a | |||
| ea0633e903 | |||
| cc34fc3a29 | |||
| 3144c49764 | |||
| 45cc25e873 | |||
| 0fba6239ce | |||
| 9eb1bc5f4d | |||
| 56e5fb6a40 | |||
| 4b343e0185 | |||
| 4bcc0bc961 | |||
| 952a56508a | |||
| 47583a1837 | |||
| 09a357c1c2 | |||
| 73c5da28d3 | |||
| 9f7514079a | |||
| 8c1f8dd5ec | |||
| 93ce3fcfc8 | |||
| 5e11211b4c | |||
| a12199f847 | |||
| 64a70c5ab3 | |||
| 27a7474c92 | |||
| eba6b4b660 | |||
| 1ea147d43d | |||
| 084169db8f | |||
| eb91e53a7b | |||
| 29b31d64e7 | |||
| d5a2b9f705 | |||
| b34134d9ed | |||
| 8d0719f642 | |||
| 22a09f2775 | |||
| ead2f04bd3 | |||
| bed6b9190f | |||
| d95519252d | |||
| aa21a8b9af | |||
| d099181247 | |||
| 622accea9a | |||
| 00627842a6 | |||
| 198d3d7159 | |||
| c6352aa901 | |||
| f15abb14e2 | |||
| e3c2d9509a | |||
| 93515bdc17 | |||
| 56ca7631ad | |||
| bde31622b4 | |||
| 00825e7d8e | |||
| fb5bbeada6 | |||
| 6a8757d152 | |||
| f9c32c3bb7 | |||
| 5ca0e26775 | |||
| b87138bf58 | |||
| 89563a17ea | |||
| 931903490a | |||
| 4fc2e2a0f0 | |||
| a0180b78d7 | |||
| ddbf2a9fba | |||
| 84fe77c6ac | |||
| 74455c40a1 | |||
| 9a106534fb | |||
| eed764b16e | |||
| 3a652b4d4f | |||
| 3c18ed9a31 | |||
| f02621d564 | |||
| 443f7b29c9 | |||
| b926af3b67 | |||
| f288688951 | |||
| 8b78054a05 | |||
| 90e802c03b | |||
| 16c091d77a | |||
| abb76e1d4d | |||
| 0e8cb56b2b | |||
| db51af9493 | |||
| 650734ee9f | |||
| a7cd598bba | |||
| 5cff7337d6 | |||
| d592b1104e | |||
| 4d1411e5a1 | |||
| 0afefdffb6 | |||
| fdbdd1bd02 | |||
| 7bef39e71a | |||
| 7e237d963b | |||
| b7d1a989ce | |||
| 30a3cb6b35 | |||
| 924a3e6698 | |||
| 587237ab51 | |||
| 79f04baae2 | |||
| 8df30d586b | |||
| db536c7a9b | |||
| 221447d6d2 | |||
| 7995f14050 | |||
| b340397716 | |||
| 83d0f14c6a | |||
| 4de770ede8 | |||
| 084ba2208a | |||
| ae3da941eb | |||
| f9bcb1c559 | |||
| 97a37ef4ed | |||
| 0706096792 | |||
| 005ec81929 | |||
| 7671e0b4e1 | |||
| 7daee24e10 | |||
| 1bd2b462c3 | |||
| 8fb2b1c829 | |||
| 1ce24661ad | |||
| 33fa255fd4 | |||
| 64371f3b9a | |||
| 8e00b1c67e | |||
| 0b56e19da6 | |||
| 0ea7edb60e | |||
| 84b876394d | |||
| 3fb031c329 | |||
| f3f51c5344 | |||
| e4267336b8 | |||
| 4885abbb32 | |||
| e46afac397 | |||
| fdf2c80667 | |||
| f994b03d06 | |||
| fd59e3b838 | |||
| c7d5dbb59c | |||
| 120e98a81f | |||
| 8964ce704c | |||
| 15f2fe8e63 | |||
| 3500da75fa | |||
| 26f45d343b | |||
| 1582f449bd | |||
| a195ea9889 | |||
| 0712dfc3be | |||
| 56946a1212 | |||
| d9fcdbb7c4 | |||
| 521e8fead8 | |||
| a8fa9e50cc | |||
| b7d3eb308b | |||
| 2c712da2b9 | |||
| dfffaf0f15 | |||
| 054061a4f7 | |||
| ed28614abb | |||
| 30f2cfd32d | |||
| d12a1037a2 | |||
| 1ded43174a | |||
| e21769eea8 | |||
| 1c4ca0e1bc | |||
| dbd3530019 | |||
| 38d1646fc0 | |||
| 4a9a955841 | |||
| 71d5207ecd | |||
| d45538d1f9 | |||
| 44e5b218e3 | |||
| 0e0689a90e | |||
| 670d0100c8 | |||
| cf2de0449e | |||
| ec9797e932 | |||
| 04f2312e03 | |||
| e57d15d650 | |||
| c99b5d9940 | |||
| 056400d4d1 | |||
| 26cbdeaf2d | |||
| 6a5f7f8284 | |||
| 7f68763047 | |||
| 6a1503d8c9 | |||
| c05dfebf1b | |||
| 6401711f7e | |||
| f272e486f8 | |||
| b815a17747 | |||
| dec1deada9 | |||
| aa580c27cc | |||
| 375b1e4b4a | |||
| f9ebb5342c | |||
| 7b0514c055 | |||
| 909e7f33a8 | |||
| 677511b119 | |||
| 26a2605cd7 | |||
| b02f650a34 | |||
| b661337133 | |||
| d73e246538 | |||
| e1d82e7fbd | |||
| 4263f53315 | |||
| f235959372 | |||
| 7bc6655b99 | |||
| 7ecc227df5 | |||
| 3046d33f91 | |||
| a32829fd0d | |||
| 4819bf3ddf | |||
| c2e02d356d | |||
| 94cc44c277 | |||
| 116702f7f0 | |||
| dafaeef184 | |||
| a9917c9201 | |||
| c0b61822c0 | |||
| cb54a0e780 | |||
| 0d44d4e54a | |||
| 3db6d1288d | |||
| a16a16cbdf | |||
| 1bb240c964 | |||
| a1be8352f0 | |||
| 5ef4f1d14c | |||
| 6330e004ba | |||
| 44bed82f08 | |||
| 0decb62237 | |||
| e9b170503b | |||
| ccd6a866dc | |||
| 1ae37710ca | |||
| 202c546922 | |||
| d2f5d35403 | |||
| 44c2219753 | |||
| cdedea5002 | |||
| 88c4ebe5a0 | |||
| c627bfb994 | |||
| 10cbcdd768 | |||
| 5e7b0dd169 | |||
| 8ae7ef421c | |||
| 96b92d9212 | |||
| e6f9beeace | |||
| f4f4807ce8 | |||
| f1d52fdc80 | |||
| 1002e4b808 | |||
| 2d651572d0 | |||
| 5af3894ae3 | |||
| 2d5a363215 | |||
| 7afbfb30a2 | |||
| a15dd256f0 | |||
| 090a567887 | |||
| e55faee9fe | |||
| 362e34be8a | |||
| 9d4c6f660a | |||
| bf1e5586b0 | |||
| bad10158bd | |||
| 21fa841e3a | |||
| 5cc58e2182 | |||
| fb4e38e50f | |||
| fd836137a5 | |||
| 9628af4168 | |||
| e59b4b42cf | |||
| 64ae5d02fb | |||
| 029a12c481 | |||
| 3fc4d9276d | |||
| 531e11748d | |||
| b122e460cc | |||
| 8f99db1841 | |||
| 7bd779b8e3 | |||
| e5cffac98a | |||
| 3b29fcbef7 | |||
| 9f60a2ba86 | |||
| 8df7b3d9ee | |||
| e2040f9a2d | |||
| 8a8184a4a9 | |||
| 373cec9ff2 | |||
| 2938e843f0 | |||
| eaba77b3a7 | |||
| e39cd494b5 | |||
| f70b721441 | |||
| 877acf54f4 | |||
| a31d7a06f7 | |||
| f52937830b | |||
| b5202cc931 | |||
| dd2bfbc53f | |||
| d2f3cdadf6 | |||
| 73a88f9099 | |||
| a86c957872 | |||
| 45588a2580 | |||
| 3b55269319 | |||
| 01966a87ec | |||
| b4a8e5c68d | |||
| aeb7842299 | |||
| e0bcf947bf | |||
| 30bf685962 | |||
| 1e6fa023dc | |||
| b5920fc409 | |||
| 16ceb7115e | |||
| 279ed66270 | |||
| 9bfa8a33c8 | |||
| 99bd4da08a | |||
| 4824814981 | |||
| 10237d2fde | |||
| c1b236080e | |||
| 83d16a16b8 | |||
| 52ccffb97a | |||
| 9ed9e22df4 | |||
| 5aa29782cc | |||
| 82fcde1245 | |||
| eab945acfc | |||
| 8ed57cbfb8 | |||
| d3ed6d750b | |||
| 963e8da89c | |||
| bb4878eab4 | |||
| 53d8444c85 | |||
| 7db009a3cd | |||
| 4932fc2d7b | |||
| ca55ac02b7 | |||
| c535ffb2e0 | |||
| 9c6eb22d9d | |||
| 9ec6ec0281 | |||
| 327441e62b | |||
| ae3f07a3ee | |||
| f967e1f283 | |||
| ba1308c568 | |||
| 3144e3b007 | |||
| ec1c5713ad | |||
| 15adc93340 | |||
| c9b27f6ebe | |||
| cff7f7d2e2 | |||
| cb5d0c4840 | |||
| dea6abe399 | |||
| 20c792d4fa | |||
| b8cbd5a0fb | |||
| 0a34f23e62 | |||
| 7413b4e4ac | |||
| d2025c32c9 | |||
| 5c5dd35409 | |||
| b509e9046e | |||
| 46e99434c9 | |||
| b6ff94aed3 | |||
| 25e0bd19bc | |||
| fe5b398fad | |||
| 417ed1401e | |||
| 48698f06cd | |||
| b70a7eaf8b | |||
| ad86d7bbcc | |||
| a2eb550099 | |||
| e736855a4a | |||
| 0b49f531ac | |||
| c36f4d9abf | |||
| db72b0a5c9 | |||
| b19d21fc39 | |||
| 2d172d70ad | |||
| 7f419a2ce7 | |||
| cc434771c0 | |||
| f5a9502261 | |||
| c48d970b0a | |||
| 9a53c7a84e | |||
| ce17ae2d2b | |||
| d97f65e9b3 | |||
| 33af47b01b | |||
| 9f1f3a2d66 | |||
| 4c9609ba52 | |||
| 270203266f | |||
| edc326ff3c | |||
| 0856b8a2ab | |||
| 8f95517dd7 | |||
| c828f3f479 | |||
| b90d026a74 | |||
| 819beb779c | |||
| de31dcaf0b | |||
| 587c217b7c | |||
| b03e86f903 | |||
| ea80942937 | |||
| 06153cbf58 | |||
| 0b94f777a2 | |||
| 3d6917cd5d | |||
| e4300ab315 | |||
| ed80533198 | |||
| 4b5c741ff9 | |||
| a93b49eb76 | |||
| 9fb25b80ea | |||
| 5c64deb874 | |||
| 33cb09e201 | |||
| 032a9750e2 | |||
| ff6fcd038e | |||
| cc3908b416 | |||
| 50a7527e7c | |||
| 75e085b80a | |||
| 39eecf0920 | |||
| 7a89ef3e74 | |||
| 10b696f78d | |||
| 0e9f267117 | |||
| 02bb977cc0 | |||
| c4a89b9302 | |||
| cde9401b36 | |||
| edcb4a949e | |||
| 4e0516e43f | |||
| d702cafc4f | |||
| 6cd9076dff | |||
| a5c113e527 | |||
| 048bdbc367 | |||
| 1e287f56e2 | |||
| 2aacab80a6 | |||
| f9d7255556 | |||
| 2b2cf1ca8f | |||
| c651a97bbb | |||
| b54f1d125e | |||
| ead711446d | |||
| b19f0ac69c | |||
| 25a325f7f7 | |||
| 8be52f7bdd | |||
| 3cb1cd3ba6 | |||
| b68a9a43de | |||
| 0f80f5bc03 | |||
| 647ef1d8d3 | |||
| e9ac9aab7f | |||
| 6c6a7f0677 | |||
| 56dc30845a | |||
| da14711bbc | |||
| 33fe057a5f | |||
| a052f981c5 | |||
| 5042bddec7 | |||
| 0803e61828 | |||
| 119f304e2f | |||
| 3db6f93b73 | |||
| 3f74d8efc9 | |||
| 15aabc4db7 | |||
| 3ed3a8d47a | |||
| 3719f5e1cd | |||
| 957fca8960 | |||
| 0066d2eb7b | |||
| cbae38b41d | |||
| 021886c3cb | |||
| 6d62dd7fd1 | |||
| 20d28525cf | |||
| a406127cda | |||
| 3301b30ec2 | |||
| f761715ebd | |||
| 1f0216662a | |||
| f483f1effc | |||
| cf5b0bcd41 | |||
| 4e51830c58 | |||
| 830a45e6d2 | |||
| 24c32b7a4b | |||
| 7e30f1702d | |||
| 68ae4bf1b2 | |||
| 0b757f24d1 | |||
| 99d0525c0a | |||
| 4f3ec7aa18 | |||
| bd228459fa | |||
| c9227c20a2 | |||
| 5270bc3ed7 | |||
| e1de3dc873 | |||
| 9303f534d9 | |||
| 629a694279 | |||
| 0ef0ed7c50 | |||
| 48d335ad67 | |||
| 231434caeb | |||
| 220fd340ce | |||
| 5badb44e3e | |||
| 82d405c14c | |||
| 2157dcd51a | |||
| 872d9d89c5 | |||
| dae4543a82 | |||
| 60204d9ab2 | |||
| 0c86965260 | |||
| d0ad110d9e | |||
| 5cd88cdb7f | |||
| 60acd1bac4 | |||
| 990efacb89 | |||
| 7076a6acaa | |||
| acc4d6d8ab | |||
| 0a3ae4379d | |||
| 8197f161c0 | |||
| 0cd5f0d640 | |||
| 790093b585 | |||
| 46093c065d | |||
| 9cc1a0dd4e | |||
| 72a5d2881a | |||
| 7eabb1098c | |||
| 7a295a5d05 | |||
| da26247d30 | |||
| c797779598 | |||
| f66bf2398c | |||
| 010ce39e20 | |||
| 9320059a76 | |||
| 3003a310a0 | |||
| 91af5e6fe6 | |||
| d02dfbdaf7 | |||
| c3e06cc1ff | |||
| 3e86e368d8 | |||
| df231d1530 | |||
| 006f71def7 | |||
| 047dc9a7ae | |||
| 05abf00994 | |||
| c8278f6364 | |||
| 8cd951c669 | |||
| c43700e4d6 | |||
| fa2174319e | |||
| 4d6a71c8be | |||
| c866f16157 | |||
| b99e579ccd | |||
| 01eb074df1 | |||
| f6473b0e5e | |||
| e244797e7d | |||
| f267908122 | |||
| 6128e364e6 | |||
| 32a4fda9bc | |||
| 792ce39792 | |||
| 94b80b3f8b | |||
| 0e49985edf | |||
| 164f508cbc | |||
| cdfda4d963 | |||
| c3b850972f | |||
| 89f8aebefe | |||
| 52eca3b1ab | |||
| 0e26943d25 | |||
| 8286b0137f | |||
| 0a8bef8ac3 | |||
| a8fa4cf872 | |||
| 775f454e38 | |||
| b7de326a21 | |||
| 5b0d2e8294 | |||
| ec34de4675 | |||
| 0f6aa5ca9f | |||
| b0cdd1029e | |||
| e554e9ca5f | |||
| ff879454c1 | |||
| 7d3baaa501 | |||
| 5a57a58f0a | |||
| e01bfb4676 | |||
| 3617004de2 | |||
| de8234868a | |||
| 3d31d9a435 | |||
| 9220f13c9e | |||
| 10a3ed7f15 | |||
| 680ec6e285 | |||
| d99fbe5292 | |||
| 554eb671b2 | |||
| 9f2e46d876 | |||
| d2efb8391c | |||
| ac04cc4525 | |||
| 03855609c1 | |||
| 2408af31d9 | |||
| fc2dcbd4b0 | |||
| 3012bf6a46 | |||
| e07529846c | |||
| 8805763b1d | |||
| 5fa578c9ed | |||
| 5056dddf26 | |||
| 010c41c3c9 | |||
| bb7cea3dee | |||
| d7a81d2268 | |||
| 9b9aa8c060 | |||
| ee445c0819 | |||
| 0060312d52 | |||
| 3a4f4eaf24 | |||
| afa8c776b9 | |||
| 60cfee7ce3 | |||
| e418f5d3ea | |||
| 80f30b82b6 | |||
| 58999418ab | |||
| f4e90aa9da | |||
| 1308737382 | |||
| c1b1b2a6ce | |||
| 82ec3569dc | |||
| 3dd2b5df49 | |||
| 34ac01cde8 | |||
| c09efbfa78 | |||
| 054f6200f3 | |||
| dabe88b703 | |||
| 35dee07537 | |||
| 67e44d378c | |||
| 09d9fc446e | |||
| 1971e3bb81 | |||
| b560cdfa6e | |||
| 0bfdedfae8 | |||
| 5cd424a680 | |||
| 012103e706 | |||
| 2ad067b80d | |||
| 2f551db4c7 | |||
| 343aa77c86 | |||
| b7bbf8688f | |||
| 67a98023c6 | |||
| f0c6486855 | |||
| 201884643f | |||
| 410ad346e6 | |||
| 782bb3a825 | |||
| e77b21719c | |||
| fffdd596d2 | |||
| 6e2b6cc397 | |||
| 97ac478c8d | |||
| 1b655f27d1 | |||
| 9760aa23d7 | |||
| 6656676636 | |||
| 32549fc16f | |||
| 55d83d12bb | |||
| fd1e7f7f4c | |||
| 0fc5a16f80 | |||
| 4992845195 | |||
| e9db55bcb6 | |||
| 11056df05e | |||
| ffd04b6f60 | |||
| abdbe601b4 | |||
| bca7e2e4cf | |||
| fcdd78d668 | |||
| 09f1bdb915 | |||
| 8e5168005e | |||
| c210c3b286 | |||
| 9020022fdc | |||
| b13aede1d3 | |||
| cca1f76b85 | |||
| f667ef562e | |||
| 3565214e38 | |||
| 8f11ad7d6c | |||
| 4612f7452f | |||
| 2850789b29 | |||
| bf3dbb623d | |||
| 9cb7cc8c07 | |||
| c7cfb7d7b7 | |||
| 018959aa03 | |||
| e64f87bc0c | |||
| 891958c4d9 | |||
| f921ff6f4d | |||
| 8a0809498a | |||
| 447e3f4421 | |||
| e2172a6fe4 | |||
| ccf3e43dc1 | |||
| 218091e1be | |||
| ee1eafe5a1 | |||
| 79e95a8146 | |||
| 3d05bad997 | |||
| 82f7efdc59 | |||
| 25bc499245 | |||
| 09011ac18b | |||
| 42a958a9cc | |||
| 77e1df1bb0 | |||
| d77533a421 | |||
| e47e1d6747 | |||
| 2922878163 | |||
| 4608891a88 | |||
| 8a6e0f45c7 | |||
| e30f3269e8 | |||
| 439710d5f3 | |||
| de68d5e3f2 | |||
| 4643197fb4 | |||
| c1c63d82af | |||
| b78eb5a268 | |||
| f9361ab134 | |||
| efb6a07a13 | |||
| 6b0bacc018 | |||
| c368148bfc | |||
| d43f7240b8 | |||
| 9f2f0734ff | |||
| 5d54fbde39 | |||
| 93bfbe9c36 | |||
| 5e9e5c1892 | |||
| 8c607ae05a | |||
| ee3c431ef6 | |||
| 804f9ee111 | |||
| d343519e19 | |||
| ce43cb6226 | |||
| 08b281c428 | |||
| 6b3079343e | |||
| d4baa0b4d8 | |||
| 70b411a946 | |||
| c7d670d50c | |||
| 0e3189404e | |||
| d95b2eccaf | |||
| 1d7903ad02 | |||
| 31bae10c28 | |||
| 3081d99e12 | |||
| ac8525f4e1 | |||
| f921ee35fe | |||
| 3c9f44bda0 | |||
| 381b4f4e3b | |||
| 7defa40be5 | |||
| 02a0a9aaee | |||
| 4f4097a7a9 | |||
| 098639042b | |||
| 3a9bc99f07 | |||
| 37e1a18349 | |||
| 3aa387a72a | |||
| 52cfa3def9 | |||
| 506b3effdc | |||
| 9da9f118c9 | |||
| 86e5995c8a | |||
| cb2603d057 | |||
| e6d70f23fa | |||
| 22427d0fa5 | |||
| 9459e7ca07 | |||
| fab7dffed0 | |||
| 61f6e595f2 | |||
| 22f4c97314 | |||
| 6d7dbed929 | |||
| 22f7021ab4 | |||
| 075359ef5e | |||
| dacb7e3dd6 | |||
| 267e9f3ccc | |||
| 178865af03 | |||
| f8864b8303 | |||
| 94c31916cf | |||
| b9b82ec3d2 | |||
| ed400b7ee0 | |||
| fb653b66d1 | |||
| e92253eeb6 | |||
| 3c0f8be6ca | |||
| 46ea2f9862 | |||
| e8626221b0 | |||
| 09d7ffbf0a | |||
| 791aa46586 | |||
| e0f9416a1f | |||
| 0b4acba116 | |||
| aa9df23d18 | |||
| e3e44f0b19 | |||
| 1bbea7bd75 | |||
| 31daffa123 | |||
| e91c32c5e7 | |||
| 15bb6a722d | |||
| 16a187f7d0 | |||
| aaddcbc67a | |||
| 5476dd443c | |||
| 3ab52cadd5 | |||
| 6f7374c479 | |||
| 7e296ae7ab | |||
| f5a985b221 | |||
| 72e061b344 | |||
| a08e6d5ad8 | |||
| f719ec10a7 | |||
| b680d723b1 | |||
| 0cf410c768 | |||
| be84693610 | |||
| 047b80e0d8 | |||
| 3c255a7119 | |||
| d9c5c7ffc4 | |||
| a61b621ceb | |||
| 90ca311205 | |||
| e466d1feeb | |||
| e594703f8f | |||
| cd98550183 | |||
| 60dbb7e11a | |||
| e6cbcd385a | |||
| e1f9c4984d | |||
| 039ee400ff | |||
| d376f7291c | |||
| 76402b7bcf | |||
| c2cbfad51f | |||
| 9848c3d07e | |||
| 84a2d9cdba | |||
| f2438f80e0 | |||
| 824d8897aa | |||
| 2c432348fe | |||
| b764eb472c | |||
| 1d4333ffe4 | |||
| 337bbe7ec3 | |||
| fd482f32f0 | |||
| 755e4f24ff | |||
| 9d27eaef7d | |||
| b0d4021212 | |||
| 2f1137b97b | |||
| 78541a56f8 | |||
| 7d9a0d3308 | |||
| 0c6ace909e | |||
| 8afba620f8 | |||
| 5bef19fac2 | |||
| beb1c95a2b | |||
| ec5865fa69 | |||
| 4bd2d0aff7 | |||
| ca73e267d8 | |||
| 628b91eed8 | |||
| 878deba341 | |||
| 1376a787dd | |||
| 9c56b67dcc | |||
| f4e7c9acc5 | |||
| 0a94a27331 | |||
| 21230d17fb | |||
| b12d9528c1 | |||
| 2127356240 | |||
| ce677b13a0 | |||
| 62d6ea002d | |||
| e0aa84c877 | |||
| 25f4c027bf | |||
| 10d7bc56b1 | |||
| 59006ad921 | |||
| a821915a1a | |||
| 4a91d0db53 | |||
| 984fca183f | |||
| fc1710f3b9 | |||
| 56f817bb7a | |||
| 70a939b2b6 | |||
| c7f7804b52 | |||
| d3494774a3 | |||
| 1b976106e4 | |||
| 10a81255a6 | |||
| 4eaa55cf78 | |||
| 0e3ab3c3a7 | |||
| 948588b874 | |||
| 095139079e | |||
| 42c553b9d3 | |||
| aedd766d7d | |||
| 228ab0ca40 | |||
| fdcb7cbbf7 | |||
| 933f46e250 | |||
| 2282787bd7 | |||
| c4d3698a9b | |||
| 80cc86a791 | |||
| 3646672849 | |||
| 9a4c8f1f06 | |||
| 4eba721461 | |||
| eeafcde6e9 | |||
| 0255fdbe33 | |||
| ce303b37b7 | |||
| 84cd49478a | |||
| 0ed92483f6 | |||
| 83f22c2874 | |||
| c4f6d00540 | |||
| 6af60df87c | |||
| d4ffa6116d | |||
| dab2d40ba4 | |||
| f45f29aa43 | |||
| f793469dce | |||
| 06ced1c0d2 | |||
| 0ea396fa35 | |||
| 1714b01b34 | |||
| ced132c07f | |||
| 500e069139 | |||
| 2bf896aa3f | |||
| 9168cfc928 | |||
| 0bbffb20cd | |||
| 18a28254fb | |||
| 415626ef58 | |||
| e9ad25dc36 | |||
| 92215163bf | |||
| b3ffe61376 | |||
| 8e6048883a | |||
| 532e40efc3 | |||
| b775083437 | |||
| e4b4270731 | |||
| bf0f551768 | |||
| 213ccd86c0 | |||
| fc5de50f61 | |||
| b896af2a15 | |||
| 93ba447192 | |||
| dd8cc3c744 | |||
| 064b041d28 | |||
| a131aca047 | |||
| ad9b39a94a | |||
| c3cf93eaee | |||
| b83f98e90c | |||
| 5e4c451ccd | |||
| ab5e0136a7 | |||
| 89ca11bb81 | |||
| f220b2fd43 | |||
| 28d99cbe38 | |||
| 9c2130562b | |||
| d242aca942 | |||
| a341dcf0b7 | |||
| 8a1c7ed5a0 | |||
| 1e0a3e9881 | |||
| d76d430672 | |||
| 32034473ac | |||
| 383d349b3a | |||
| e036f2e602 | |||
| c73b70b7e7 | |||
| d105f2a175 | |||
| cf1dc4e4f1 | |||
| 1d9a877f59 | |||
| 772226fb1a | |||
| fe62dee207 | |||
| 37309918dd | |||
| 7f8e853657 | |||
| 006a8a523e | |||
| 8e497122f2 | |||
| 33d5353f75 | |||
| 6da3d46d71 | |||
| a26e61ae4b | |||
| c3d347bffe | |||
| 39cc7e98a8 | |||
| 2a4e500893 | |||
| d6e0cfd644 | |||
| dbbcd29303 | |||
| f3a5f28236 | |||
| bfae7143b1 | |||
| 3ce733ab67 | |||
| d6f75d6dd0 | |||
| 6f3ba952ab | |||
| 4203fdfb72 | |||
| fd9abc7619 | |||
| 53a9f408e7 | |||
| 4eba49b625 | |||
| e3476f9956 | |||
| aedb08ce5d | |||
| 9feb4e774a | |||
| 9515676876 | |||
| e250f69d6b | |||
| 4d4d2c91e2 | |||
| 1283ec94de | |||
| 27f14ac914 | |||
| 4565819dd8 | |||
| fa5207855e | |||
| 7f586a042b | |||
| 1adad849e0 | |||
| 56b2983252 | |||
| 8b5e0edb88 | |||
| be17d3fc97 | |||
| e898b8a7a4 | |||
| 831c698f8d | |||
| 76b8988597 | |||
| 34b46a6143 | |||
| 422cc5d396 | |||
| a048e00489 | |||
| 7dde4eca55 | |||
| e7af8840fd | |||
| 903276e5ed | |||
| 43bdfc0605 | |||
| 3c2332d6f4 | |||
| e222f504f6 | |||
| 86707ccc7d | |||
| ed8c1a6b6c | |||
| 8179715f5b | |||
| 3ea293612d | |||
| 545bb6b47d | |||
| 0b40894cda | |||
| e6246314fd | |||
| 2c23f03cc4 | |||
| 91b9502d0b | |||
| 5bbe039e9f | |||
| 8be8fbee19 | |||
| 2e5361f844 | |||
| f4ecf28808 | |||
| 5dd88e30f8 | |||
| 0095c82edb | |||
| b8260cada6 | |||
| 39ec77faae | |||
| 5d4434eebd | |||
| 553ab70d78 | |||
| 23bffe7c5e | |||
| babc41a0cb | |||
| a272033834 | |||
| 82ebdd3908 | |||
| 30cac9f86e | |||
| 6f19a2b668 | |||
| 9235c19475 | |||
| 79d9d05775 | |||
| 2b816a5914 | |||
| 7d163f454e | |||
| b44b676a59 | |||
| c71429750c | |||
| a8c273f68a | |||
| 2588999270 | |||
| 99f7bd9192 | |||
| 70419e412e | |||
| df3df01327 | |||
| 4bdc051d34 | |||
| 575dab06f6 | |||
| 78cc7b116a | |||
| 6ebc4f1f43 | |||
| 82bb0e26ec | |||
| 6c4030c965 | |||
| ba6d3746ab | |||
| 03faa42bab | |||
| 151a4fd2bc | |||
| 3d8c4038a6 | |||
| 1e0265f6ff | |||
| 19871d2bed | |||
| 3da57acf12 | |||
| f6b5e5ecc7 | |||
| 8f471b76eb | |||
| 8218aa004b | |||
| 741a4c1640 | |||
| 63e9f02cda | |||
| 8ed3f759b4 | |||
| 616abbe04c | |||
| 8ea3511451 | |||
| 52475e83e9 | |||
| c573fc3b8f | |||
| bc23240003 | |||
| f92490406e | |||
| 9ab5b67ae7 | |||
| adaffbac77 | |||
| 3c9150adbc | |||
| 884e5b3095 | |||
| 5bafb565a2 | |||
| c750e3a50c | |||
| 917ed615f9 | |||
| 19399824c2 | |||
| 998cfb9233 | |||
| ea86b09444 | |||
| b399e6284c | |||
| adcc6fa5ef | |||
| da3fe16ac0 | |||
| 5f2695f4fb | |||
| 8408091b33 | |||
| 8de2ba1c14 | |||
| 41680a3440 | |||
| 320c44815e | |||
| f4fb26ffa9 | |||
| 39ba62e5bd | |||
| a2a28d801c | |||
| 491c94e536 | |||
| 78a805a6a2 | |||
| 86f6c66f97 | |||
| 674ebbfe65 | |||
| 48d964b957 | |||
| e08ba51951 | |||
| 1c1c271195 | |||
| 9a0d49741d | |||
| 91c07dad2c | |||
| bfb2130517 | |||
| 1942cf8ce9 | |||
| 3f5b5ac2ed | |||
| 7ab424f107 | |||
| 8403db9c0e | |||
| 2139c19b40 | |||
| 34d332129b | |||
| 19617c7e26 | |||
| 1ca9472eee | |||
| 798503cf26 | |||
| fb251f95ce | |||
| 44b69e3d06 | |||
| b44caf693b | |||
| 21c456e1d0 | |||
| aeb41616d9 | |||
| 92b4658123 | |||
| 95c9afa550 | |||
| 0d28fc15e9 | |||
| f5ff23ff3a | |||
| 1b838b473c | |||
| f0c6e437a9 | |||
| 95a955c51e | |||
| f3fe3990c8 | |||
| 8690559646 | |||
| 3e71115443 | |||
| 5534e6f1a7 | |||
| ffe98bfac0 | |||
| 946503d469 | |||
| 381ce29ae9 | |||
| 67bfcc82fa | |||
| 65e07959a5 | |||
| a91195d829 | |||
| 3d75d8507c | |||
| 2ec43d4ff2 | |||
| 7c55f71bb5 | |||
| 99ac44de9e | |||
| 9df38387f2 | |||
| e870dc9fd7 | |||
| d7faf04a2e | |||
| f0e325cd2e | |||
| c64e0da8c7 | |||
| e2140f501f | |||
| 020c8d4456 | |||
| 401c0bfdfe | |||
| 33c411befa | |||
| 041619ed0d | |||
| ad6114a44b | |||
| d61008349a | |||
| 39cfa01f5a | |||
| 924f83dacf | |||
| 68db40c4c8 | |||
| b53a793e1c | |||
| 1097300211 | |||
| 1052663db0 | |||
| e3f0311cc7 | |||
| f0af5787c3 | |||
| 4ed1da1777 | |||
| 6cca81c4bb | |||
| 047c45db9a | |||
| 689fec168f | |||
| cff7f4a9f5 | |||
| fcb8a60722 | |||
| f2ad9b2235 | |||
| 49067706b7 | |||
| 098f02f0aa | |||
| 772aa7ca03 | |||
| 4e78162d7f | |||
| 017600f90e | |||
| 86d1749989 | |||
| 32bc1a4a6f | |||
| 58b37f8922 | |||
| 135b55b204 | |||
| 1f025f3556 | |||
| 54bf1af524 | |||
| 11cae2c56f | |||
| 7075f3bcc1 | |||
| 5df2a1c2f5 | |||
| 831ca71a58 | |||
| bb854161f5 | |||
| a98d6125da | |||
| b178961b9b | |||
| 9c6664aed2 | |||
| 1d254248d9 | |||
| 844c028b7b | |||
| cf320fa01b | |||
| 739b729654 | |||
| 48729b298f | |||
| df2d5a93a0 | |||
| 328d200a78 | |||
| a5f5bd8828 | |||
| 760aa6f8f6 | |||
| d6a341337a | |||
| 82d79028de | |||
| 92eece6289 | |||
| edd8b86144 | |||
| 5d5c8dfddb | |||
| 1dc2e661d1 | |||
| feb46a5887 | |||
| 4086fcdb30 | |||
| 8dd8d21e85 | |||
| 42a4210290 | |||
| 9a1266d9d9 | |||
| 2915042719 | |||
| b4730589bf | |||
| 001cbfcdb6 | |||
| 44dab8246f | |||
| be5cbf0ca0 | |||
| fa2fb66f44 | |||
| 9982ebea9e | |||
| 2b30cc1f41 | |||
| 96a19eb5ee | |||
| 85276d462f | |||
| 44aebc39ea | |||
| 52294ebb3a | |||
| 623156bdb5 | |||
| 6bac5d79a9 | |||
| 293fc635e1 | |||
| 0f0dc6dd9b | |||
| 46de8f5f9e | |||
| ed6b2960cc | |||
| f3ef7930f3 | |||
| 5ecb3d5378 | |||
| 1d4fe89900 | |||
| 3f3b19f2cf | |||
| af1ac4e888 | |||
| 1478b59479 | |||
| 335cde94fe | |||
| dd1f399425 | |||
| 3e8923f34a | |||
| 612fc8f444 | |||
| 0cbc104092 | |||
| 41f7e3a05a | |||
| 25ce3ccdc9 | |||
| 82a60413e1 | |||
| 2b4126fa71 | |||
| 52a7ab7b3c | |||
| 9b8ce918d8 | |||
| 57081f4003 | |||
| 5df0d85004 | |||
| 63b88383a4 | |||
| 7564a0a771 | |||
| 36bc35a7e3 | |||
| 1c55ab8f86 | |||
| 9a1f3b0fe3 | |||
| 438b55c08b | |||
| 12fcb98412 | |||
| 33030cf550 | |||
| 9a7acef9a3 | |||
| 61f92e544b | |||
| 57d6cc7d0e | |||
| 919ace95b9 | |||
| ec1af285af | |||
| 6b4c02e965 | |||
| 913bcdeeb2 | |||
| e40857d24b | |||
| d3fab1aa73 | |||
| d32698ca91 | |||
| 7832276560 | |||
| 2fca73dfe8 | |||
| 0f194a80bb | |||
| e0cdf42d26 | |||
| c501248408 | |||
| a559df99ec | |||
| 1cdd7ed6ef | |||
| 7e3bd14db4 | |||
| ab08a725ca | |||
| 1977c80038 | |||
| d9d8eaa611 | |||
| e0dcb70fcd | |||
| bb60f7f22a | |||
| 70821c73c1 | |||
| 1560234105 | |||
| 59f74ebb9e | |||
| d3e21251d9 | |||
| aedd996c3f | |||
| a589b77de5 | |||
| 86330c74b5 | |||
| 54a77555cc | |||
| 30ae815717 | |||
| 1eb1b6a956 | |||
| f46b303a67 | |||
| a1ecb784e2 | |||
| 142e04fa60 | |||
| 540d6cd1e4 | |||
| b078f38e62 | |||
| a2e5415b5c | |||
| 9aae1c5476 | |||
| e73b431378 | |||
| 0fe60f52e2 | |||
| 6957ca54f0 | |||
| 31de4089ad | |||
| d73a4704c8 | |||
| 2f5f52471e | |||
| 97f82d70f5 | |||
| c355bc2b79 | |||
| a011b5a947 | |||
| efdf02158c | |||
| 4ca302f5fc | |||
| e669df00b4 | |||
| 19e6f1e7b7 | |||
| 025d237be0 | |||
| 2eb5fb7526 | |||
| 3818e17976 | |||
| 1f43b8b220 | |||
| 10003fe49d | |||
| 80a8cadaae | |||
| 88098a8255 | |||
| 66a543146a | |||
| 3aafc3fcbe | |||
| 050da95a8f | |||
| 40b7b09de4 | |||
| 16091f759c | |||
| f65664b885 | |||
| 3eef9c465a | |||
| a1b4c726dd | |||
| 5e2752569b | |||
| 65a823698a | |||
| fdfad0edf1 | |||
| dcadb529c7 | |||
| 37460ceac2 | |||
| 994397ec35 | |||
| 9354ff9af8 | |||
| 2811e21911 | |||
| 746f81e45b | |||
| 69f1887926 | |||
| 6dfded50d6 | |||
| 5e01ecf0a2 | |||
| a1be42a135 | |||
| 5bdd655715 | |||
| c32e9bd0fc | |||
| 2e2985cb90 | |||
| f4a5dd47fc | |||
| 81873bd898 | |||
| d6604ff2c9 | |||
| 298b7af692 | |||
| 433df3bebd | |||
| 84dba2036c | |||
| 924ef2a727 | |||
| 5a2b997693 | |||
| ebb87962ac | |||
| 075eb1a21b | |||
| b9554d11a8 | |||
| b910075c4c | |||
| 1966e844bd | |||
| e760a63181 | |||
| bfa236f802 | |||
| 7f64b51582 | |||
| 4324126660 | |||
| a8c54de47d | |||
| 562b3e9d3b | |||
| 679c6da972 | |||
| 793adb9a03 | |||
| 23c62f1092 | |||
| 70acea8e92 | |||
| 516d8d8044 | |||
| ed2b41bc55 | |||
| 5351ffd6b6 | |||
| aaffbb376c | |||
| ac852c0484 | |||
| 4bd93ad958 | |||
| 5f131848e7 | |||
| 4915f99412 | |||
| 92841346cd | |||
| b0e8db6e0e | |||
| d533e0ceab | |||
| 672b697209 | |||
| c9bef1fb1a | |||
| 454e8bb934 | |||
| e587d0daaa | |||
| fcc23ddfc2 | |||
| c541805bed | |||
| 2c38c8fd91 | |||
| 15385cf78c | |||
| 6df3a8ec51 | |||
| bca9c6d96f | |||
| 26feccc28b | |||
| a1fc7d2e48 | |||
| 0b42b10e41 | |||
| 0a0912dbab | |||
| 5e3ff2de31 | |||
| 55db52f8f0 | |||
| 2888ab56cd | |||
| 1edc20f665 | |||
| 72c818b17b | |||
| 7393dc83f5 | |||
| 6043553a39 | |||
| 87461b52ce | |||
| df807d746f | |||
| 9e7a519806 | |||
| 6ee4af82ad | |||
| 75c8a4597c | |||
| de274f0954 | |||
| 82195950b3 | |||
| 806b3ac77e | |||
| ae95bd1db8 | |||
| 62ffefb92f | |||
| ca190c6d57 | |||
| 1c739a6269 | |||
| f5386cd3c1 | |||
| 65aab99639 | |||
| 7540659396 | |||
| bbb7904477 | |||
| 056985531b | |||
| 730739077b | |||
| 6c82184d1d | |||
| d3b6f6a1e4 | |||
| d35550900b | |||
| dfc16e38eb | |||
| 08bd5f3081 | |||
| 7d98fde53a | |||
| 486e9ae0c5 | |||
| d51587aa66 | |||
| 1fabcc756d | |||
| ee3fc058e1 | |||
| e66e9e1ba8 | |||
| 1cb4bea73c | |||
| b3a491e723 | |||
| b583aafa25 | |||
| 9709c6cbf0 | |||
| ca81eb2ecb | |||
| 910d886f65 | |||
| 376411c0cf | |||
| ad019eff69 | |||
| 3712e67594 | |||
| c98084ec39 | |||
| 5a851ea99d | |||
| 849cdb234c | |||
| 9f9313b5e7 | |||
| 1888d8cfc7 | |||
| 393b747f0e | |||
| d8f9a7ed7f | |||
| 7be4541f89 | |||
| 97e87a9f32 | |||
| 2d84309f04 | |||
| f2ed7f8b72 | |||
| c839d535d8 | |||
| 623e155c75 | |||
| b20a74de00 | |||
| 090b5fe04f | |||
| b7dca9b652 | |||
| c9402dec4e | |||
| 6dc097f60f | |||
| 636a826583 | |||
| 5c313ab7ac | |||
| 4aacc425a9 | |||
| c7db544684 | |||
| c7833bae11 | |||
| 3d777781b8 | |||
| f2501eeb3b | |||
| b72f9819d7 | |||
| 5f134fad33 | |||
| 21cec51fad | |||
| 048d3aa361 | |||
| 8871d12fa8 | |||
| 67f931f9c8 | |||
| 2fe9d6c3e1 | |||
| a662d5b90c | |||
| c30ec4bd87 | |||
| ee0a3a9d05 | |||
| 094a8abfe2 | |||
| e1c39e90a9 | |||
| aca3f2d2fc | |||
| 05d95259e2 | |||
| c278359909 | |||
| b5d8d40462 | |||
| c1b7c380da | |||
| e4f0ba0495 | |||
| ccd4a479a9 | |||
| 92941bcc38 | |||
| 6b55875547 | |||
| a0947a84d9 | |||
| fca0e03180 | |||
| 3dad7d8850 | |||
| bc18301dc1 | |||
| 1ebe8eba4e | |||
| 3ec3388b08 | |||
| 71c2e8eb6b | |||
| 009aa9f73e | |||
| 14e38bc738 | |||
| 74ffd80b10 | |||
| cb7a04ff09 | |||
| 96640ad91e | |||
| 3791dfd558 | |||
| 91017caac4 | |||
| 5d8720687a | |||
| 75b1234376 | |||
| 1e866a9eab | |||
| 80e58080c4 | |||
| 394036a0d0 | |||
| 2f2355f36e | |||
| e711e30c21 | |||
| e3d32057ee | |||
| e42c4e595e | |||
| 73d71e5dac | |||
| d6cad14e7b | |||
| 9beaf93595 | |||
| 074610a9f0 | |||
| 7881edaf21 | |||
| f2643308f9 | |||
| 1168be9a92 | |||
| c34d6141bc | |||
| e1f62e3a3a | |||
| 1d067dbaa2 | |||
| f1b6e742d9 | |||
| 149448c04c | |||
| e388a60d43 | |||
| ea49ef2691 | |||
| 741b2c23d2 | |||
| dca3542cec | |||
| 4a37af4ce4 | |||
| a2e907faeb | |||
| 7e33243fbb | |||
| 2b0abb1740 | |||
| 60e4f2a378 | |||
| a4603213b9 | |||
| da9ea61fbf | |||
| 4ceef741ea | |||
| d323fc07f9 | |||
| 2356e175f9 | |||
| 7a9c0ed8f2 | |||
| d406cf3fcb | |||
| 9741cac1cf | |||
| 456519e06c | |||
| bad6b495b1 | |||
| 638e0c988f | |||
| 40aaabad7d | |||
| 46cf8cfbdc | |||
| 2226bcf515 | |||
| 27ceb7b042 | |||
| c2226f8452 | |||
| 38dcdaf8e3 | |||
| 2a440e91fa | |||
| 2cecb9a14c | |||
| 241f976866 | |||
| 560c270723 | |||
| 5159957722 | |||
| cfb851c23e | |||
| e45218de17 | |||
| 0ff34bd3f7 | |||
| 6bc7a9f504 | |||
| 7ea53f305d | |||
| 4a04f6bb0f | |||
| 633b7df021 | |||
| 4ddaccd3f4 | |||
| 389c20b6bf | |||
| 20149b6041 | |||
| 2f6af6c18e | |||
| b764a43abe | |||
| c3fb8b9c89 | |||
| d574b09dfa | |||
| 7fd7197909 | |||
| 58178d2871 | |||
| 880838c263 | |||
| c196d5cdf5 | |||
| c370edaa72 | |||
| 0640aee554 | |||
| 8a5f11e6bd | |||
| 92b6ebcb08 | |||
| 758c331af5 | |||
| 17e5c0535d | |||
| 66fee84b49 | |||
| bbe0350f2c | |||
| b31fe4b94a | |||
| 11b414fd29 | |||
| 1a35b5ded0 | |||
| 4245c1511e | |||
| 989c3706dd | |||
| 49500768db | |||
| 65becdac85 | |||
| 125c78fccd | |||
| 58c576b950 | |||
| b08aa46992 | |||
| c77f0cf817 | |||
| bb0378c216 | |||
| f2e7a64e99 | |||
| 759cacf933 | |||
| 0b213253ce | |||
| f0ab333892 | |||
| 7516db3a60 | |||
| 29cd798ca8 | |||
| 40cb902baf | |||
| 15bbcf3eae | |||
| f508e103c1 | |||
| 94fa36125d | |||
| 1c754a6dd0 | |||
| 609e4a49b8 | |||
| 98710c9542 | |||
| 0e2f5fdf53 | |||
| e9ed5530d5 | |||
| 113f1d3ed8 | |||
| 3fc60a57b6 | |||
| d14e09187e | |||
| bf90131841 | |||
| 40b7a16b21 | |||
| 882d7273a1 | |||
| 6cfeddf3d4 | |||
| a06e6c581d | |||
| bd8bda40ec | |||
| efd81a4e0c | |||
| 493e08ce2c | |||
| 1906451060 | |||
| f865e95ae1 | |||
| 480e18b79a | |||
| 6436bc6191 | |||
| 7ec7eb29e4 | |||
| 5deb744ba3 | |||
| e908939560 | |||
| e02708bb0e | |||
| 4826c35a70 | |||
| c51f185438 | |||
| 65bd15b573 | |||
| 5283254c1a | |||
| 15458df982 | |||
| eb2228fb17 | |||
| 0e27e8ee3b | |||
| 17455efe82 | |||
| e2c80cb416 | |||
| a48b4db550 | |||
| 1d66637b11 | |||
| 3e7e98d555 | |||
| 60e542923c | |||
| e737d16f0f | |||
| a04219518b | |||
| ce2c6bed0a | |||
| 84a08493e3 | |||
| 3d411fa49c | |||
| c0a0c90a49 | |||
| a67d41296e | |||
| 25a95ddba0 | |||
| fac255a27c | |||
| 0811c8dc15 | |||
| 7537963a8e | |||
| 36f8b1de0b | |||
| 1d9e1bc9d8 | |||
| bb9fd24068 | |||
| 9c044ae98b | |||
| 9807883d65 | |||
| 04e410615d | |||
| eda1eea2de | |||
| c1f6ef35f2 | |||
| b61ce1e42a | |||
| 62e60f4309 | |||
| c6f544136f | |||
| d588315759 | |||
| b1fef73c54 | |||
| c4fc31c963 | |||
| 85b0d0eef4 | |||
| 812eb842e2 | |||
| 783cb95f24 | |||
| 63b7f294c4 | |||
| 80c95b0f11 | |||
| 5969fa2ca5 | |||
| 0187608918 | |||
| f7b155d3b4 | |||
| 82656a7187 | |||
| 9993824d93 | |||
| e2fa4990bd | |||
| 6753d04817 | |||
| 9679c75f0a | |||
| c203fa5b9d | |||
| 98531376d9 | |||
| 86edc8b919 | |||
| 7903751d85 | |||
| 2620a29a2b | |||
| 5cc40c09dc | |||
| 5c02d37852 | |||
| 2e5d445d65 | |||
| 456822f56f | |||
| c8bae7d89b | |||
| a5aceb3d1f | |||
| 578ed5d1f1 | |||
| 3ef7343309 | |||
| 2c98c38721 | |||
| 4f28c54591 | |||
| 06b5b885e9 | |||
| 612cc2ca9b | |||
| 18f7b695e5 | |||
| f29e2fe1de | |||
| 799c22093f | |||
| 2496c1d96e | |||
| 8ee76af30f | |||
| 2f35442558 | |||
| 81fa6a6233 | |||
| e5778d5b5f | |||
| f69d607ecb | |||
| 79fc2e1f93 | |||
| 6dfdbb9ee8 | |||
| 5d8f7b3f8d | |||
| cd4601a9c9 | |||
| 462a011401 | |||
| 31d55dae14 | |||
| 8dc9731299 | |||
| 66c19c644e | |||
| 2b617e2697 | |||
| 3a60a497e1 | |||
| a9337aee63 | |||
| c80cd47ccc | |||
| d9c2371488 | |||
| 096d19751a | |||
| ef70119090 | |||
| 95dba71bb9 | |||
| ec37c7a6f8 | |||
| dcc9352301 | |||
| c509c6bb38 | |||
| 4784d689f8 | |||
| 8903a075be | |||
| 48d6e91b0e | |||
| 30865239d2 | |||
| 8b7cd92ae8 | |||
| 69f336553e | |||
| ed82f96ae3 | |||
| 8f02016a76 | |||
| c06f397d12 | |||
| 912b7280cd | |||
| 50f7dd2c63 | |||
| 23469543c7 | |||
| 2d3f70dd12 | |||
| f57d19e797 | |||
| 8c529f0724 | |||
| 1583f1957a | |||
| 676ccb133f | |||
| 489b8143a1 | |||
| c4cf3efa21 | |||
| 871cfd638d | |||
| 1f3ae1c687 | |||
| 59eb101a48 | |||
| b3b8b6ba29 | |||
| 42baaa8950 | |||
| 61ad70d3b8 | |||
| 04252e3b91 | |||
| b40543d7b5 | |||
| 903fa49b71 | |||
| 03ae2699c6 | |||
| 8ecc4078bb | |||
| ebaf4f02f0 | |||
| e85437379a | |||
| 2e9642019b | |||
| 5a77522a04 | |||
| e5512604fa | |||
| 146a46f8be | |||
| 91f33f06d3 | |||
| 59da7b6ba6 | |||
| 0a1ad238f8 | |||
| 302e6c145c | |||
| a6bbf0dfc7 | |||
| 9c3d22964c | |||
| ab60ed8473 | |||
| 9a00e70cc4 | |||
| 35954f52c5 | |||
| e13d80d063 | |||
| 73ed15689d | |||
| 65d949bade | |||
| 33d0d01051 | |||
| 9998ed0a14 | |||
| 85a8a17acb | |||
| 4032cb8abe | |||
| fc2e87063e | |||
| a63b809642 | |||
| c30048c268 | |||
| 956d5a39be | |||
| 76fd1ab7e3 | |||
| 2c4c954c64 | |||
| aef4da961d | |||
| 31e00bb681 | |||
| 369fdd24ef | |||
| 2a57994c7f | |||
| 6f84b14277 | |||
| 10ed05c8ef | |||
| 799bd1042f | |||
| 6f9acab2d2 | |||
| 387d8eb5af | |||
| c813c5d5ef | |||
| 1c6df6741f | |||
| b54ab5f824 | |||
| 37fdf6c18e | |||
| 2685de9b3e | |||
| c049100f5f | |||
| 711d1f9d65 | |||
| 5d7453afec | |||
| e4acf466ba | |||
| 2d66cbd29c | |||
| 8786f7d500 | |||
| 3d40d7a819 | |||
| 6f7862a0f2 | |||
| 58c6211d54 | |||
| d10b187a1f | |||
| 1ebf34c83a | |||
| 01e2a3c708 | |||
| c9b97552d4 | |||
| 428f39aa86 | |||
| 5fecb723bc | |||
| 0168b0d93a | |||
| 895fa510fe | |||
| 0aae59a1ba | |||
| 574a2b4dc7 | |||
| acae608966 | |||
| 6ca6c34f92 | |||
| 16724a2d2e | |||
| 8b50cc561a | |||
| 1ec1d482c4 | |||
| 869b9d507b | |||
| 514fe66347 | |||
| 657c91a5ef | |||
| 82354a1156 | |||
| b7619f0c93 | |||
| 598a3ad0b6 | |||
| bf0be93dc9 | |||
| 90a676f778 | |||
| a675e4bbe3 | |||
| 5eee8c6785 | |||
| 3c54e4313c | |||
| 67c4b76de9 | |||
| 34fd08d06a | |||
| d08b95021d | |||
| 8517a2aef1 | |||
| cbe90141f1 | |||
| fd43bc9426 | |||
| 34a143b632 | |||
| d96e02eca0 | |||
| 398b1ae58b | |||
| 0749205bef | |||
| 54ec115fee | |||
| ebe7b84dc8 | |||
| 332abe66f5 | |||
| 9dccbfbd51 | |||
| 23a8c9e6aa | |||
| 1e4408ac6e | |||
| 05ece9c999 | |||
| 216905e455 | |||
| a1bd88dad8 | |||
| 16c66c707f | |||
| 50cdea2b03 | |||
| 95b0fda15a | |||
| 9c99273f81 | |||
| 8d9d36a5df | |||
| b22d168e97 | |||
| 1fee166e3b | |||
| 7c098c29b2 | |||
| ffc9dc46e2 | |||
| c491a4084c | |||
| 0f076a03c5 | |||
| 3345ab2044 | |||
| 5874bdd311 | |||
| 4669211196 | |||
| 4879e7f0aa | |||
| f5283d386b | |||
| 602333f923 | |||
| e9810c129e | |||
| c503f15df9 | |||
| cba1012bbd | |||
| 646493ae61 | |||
| b649089ab0 | |||
| e97fd9023e | |||
| 478dd658ab | |||
| b313feac01 | |||
| c04b82549e | |||
| 842e62f909 | |||
| 51c6de0506 | |||
| d350f65c1f | |||
| aaf8e28abc | |||
| 7cb921e969 | |||
| 3a4b41058d | |||
| 26308d1852 | |||
| af54932309 | |||
| 83799048ed | |||
| ce410ad2a0 | |||
| 933c40458f | |||
| 6ae7578281 | |||
| 72b804e26e | |||
| 7e58cdc59e | |||
| d782ea90b6 | |||
| efffd752f5 | |||
| 47f3f45fe6 | |||
| b4e12e2ec3 | |||
| 2d331f6294 | |||
| feb4137f84 | |||
| 6a2c4a2967 | |||
| 68fc5532ff | |||
| 43ae479271 | |||
| 7a3ea4d939 | |||
| 1bcb343355 | |||
| 1b7a601cee | |||
| 8bc9544dc2 | |||
| e586e65e44 | |||
| 8096da5f50 | |||
| 91868fda15 | |||
| a71e8824ce | |||
| 6cbc354921 | |||
| 79e2077a3d | |||
| 6ea3ed067d | |||
| 84fe33becc | |||
| 276f53fead | |||
| 0789cc6fdf | |||
| 3a563b7bd0 | |||
| 9b8ba0c3e6 | |||
| 258f054161 | |||
| 258c8db0f9 | |||
| 741d0b11af | |||
| 9267896b50 | |||
| 85c0bd69c1 | |||
| 2436507b7b | |||
| 1b68b07e53 | |||
| c4ba28de1a | |||
| 8daa55c16a | |||
| 5e6c6aca13 | |||
| e08ab790ee | |||
| a394901cb4 | |||
| 2aaa7f2795 | |||
| 7b0d2a25c8 | |||
| e3f553a96f | |||
| 809a25e3e2 | |||
| 88041d9b5f | |||
| a11d741f6f | |||
| 1283def6da | |||
| 9c621c31a2 | |||
| 9e3f40723f | |||
| 682bb9a3e7 | |||
| 9f2d164c70 | |||
| bad5130047 | |||
| e3f831e0ca | |||
| a1432452f5 | |||
| b3cc68b7c6 | |||
| cc1f5a269a | |||
| a2892a713a | |||
| c342e22ce4 | |||
| 57dcbab096 | |||
| 5aa4c5bcbc | |||
| 039e1fc957 | |||
| f7b2d10543 | |||
| 38972eca76 | |||
| c2d853d709 | |||
| 239209dbf2 | |||
| ba1f3e20d3 | |||
| 92ac62d949 | |||
| 6499e3b718 | |||
| 5f0d2604ec | |||
| 5f7bb6cb49 | |||
| 7360eef244 | |||
| 52e6feab59 | |||
| 5f44252410 | |||
| 7ae3b1cafb | |||
| 0fb77e79fd | |||
| d4ae878947 | |||
| 37a2e3cc0e | |||
| 30595741cc | |||
| 11f177d572 | |||
| 9e13675ca5 | |||
| 144a0641b6 | |||
| 95266f6f68 | |||
| 9ded647c0d | |||
| f566e4d5c3 | |||
| 5df3efd087 | |||
| 98f4361bf0 | |||
| 000d1e020a | |||
| 93431a7e37 | |||
| d54523cdb6 | |||
| ed468b7c73 | |||
| bad6211bf5 | |||
| 2743d4d0de | |||
| a0f5387917 | |||
| 1abfcfdb51 | |||
| ecc0a75f52 | |||
| c98bf26337 | |||
| 187d07d02d | |||
| c47c23ad21 | |||
| 8d011ae7ef | |||
| 36b58383f7 | |||
| e6ea1738e5 | |||
| 70b7689ac5 | |||
| 40983ecebc | |||
| 47b0a8d1ac | |||
| 1ae63d3010 | |||
| fbe73ce4da | |||
| d46617237f | |||
| 0894957d73 | |||
| 9b9777ae19 | |||
| 7f2145d0ef | |||
| acefbba6bf | |||
| 660a091b7b | |||
| 103078d63e | |||
| 178395f531 | |||
| 8db213d040 | |||
| 5904d3c5c7 | |||
| 1a511ebbad | |||
| ef97e8cc6d | |||
| 814cef6218 | |||
| fd6c4836d4 | |||
| 9df138ed7c | |||
| 7b11b0e99a | |||
| 01034f093a | |||
| 8e28766449 | |||
| d06d0bd15c | |||
| 4fe4a33b80 | |||
| 4a8e91bbff | |||
| b1f6c7d55c | |||
| 727eeac52e | |||
| fb26ec0c13 | |||
| 3e25619bf8 | |||
| e81fa4ff1a | |||
| d7d2bf2667 | |||
| c763a0a9e6 | |||
| 1f34f95e7c | |||
| 2afb99b603 | |||
| 2e09ac033b | |||
| 54747143d1 | |||
| 076c98977d | |||
| b96104fcd9 | |||
| daece9337c | |||
| 3547330e2a | |||
| 4d76fb0159 | |||
| f34a95b36f | |||
| 6e3cb7a196 | |||
| 03f87c46ba | |||
| b052ba1635 | |||
| d1183199cd | |||
| 31fed948f0 | |||
| f1c5b80dc2 | |||
| 86f2aec9ca | |||
| f826dc07c6 | |||
| 34670d08c0 | |||
| 5e5646468e | |||
| a218f13ccb | |||
| 1fc37571df | |||
| 576f06f250 | |||
| 3805cb52f6 | |||
| f8d7377236 | |||
| 354fa13a35 | |||
| 3c533b896b | |||
| 11c6618c0f | |||
| 898bf3e432 | |||
| 0faf408762 | |||
| 1dbabe3cda | |||
| a107a19d95 | |||
| 58ea0bb51d | |||
| 557f22b23b | |||
| f40a192e82 | |||
| 84f3556275 | |||
| cddc2bff2b | |||
| a0b8caa60a | |||
| 22cadc77f0 | |||
| 28fb45f0b8 | |||
| 3d7f8b3f41 | |||
| bba326cfd9 | |||
| f76bb7070a | |||
| a6a3d769bd | |||
| ea5627b3da | |||
| d9807227ec | |||
| 039203408a | |||
| 60b325812e | |||
| 06a43f617b | |||
| 5cc1cfa1a6 | |||
| 35cdd140cc | |||
| 87597dbd1f | |||
| 398f7b6642 | |||
| 85d3412fd8 | |||
| 71b8cbbef3 | |||
| dfc0183a14 | |||
| f0ca0a2ab1 | |||
| c9ffd4e5bd | |||
| d354b07fe2 | |||
| 71a61fdef0 | |||
| 156e52f619 | |||
| 252cb3825b | |||
| 2eded37321 | |||
| 075a7e4e77 | |||
| 0c95f911d1 | |||
| f35baf0e5b | |||
| 49b74c9a37 | |||
| c4240440d1 | |||
| e0205ec060 | |||
| 895024aa09 | |||
| 4d64281c78 | |||
| 95f1692434 | |||
| f1302dd1bb | |||
| fec34f1efa | |||
| def3b55e51 | |||
| 4549f78ede | |||
| 3054b56f4a | |||
| 4cf5e0f2f4 | |||
| 1a18c82f06 | |||
| b8fbb429f1 | |||
| 005229fe8a | |||
| 3a0bbbf3d0 | |||
| 868e6d31b8 | |||
| a687f8d877 | |||
| 3e86a40215 | |||
| 6a68839d0f | |||
| 2140c9eb40 | |||
| 942af39b2d | |||
| a0331f0437 | |||
| 63798c94cf | |||
| 6c2ff6a94f | |||
| 2211f562c7 | |||
| 7a0165375c | |||
| e280ea008a |
555
.editorconfig
Normal file
555
.editorconfig
Normal file
@ -0,0 +1,555 @@
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = false
|
||||
max_line_length = 120
|
||||
tab_width = 4
|
||||
ij_continuation_indent_size = 8
|
||||
ij_formatter_off_tag = @formatter:off
|
||||
ij_formatter_on_tag = @formatter:on
|
||||
ij_formatter_tags_enabled = false
|
||||
ij_smart_tabs = false
|
||||
ij_visual_guides = none
|
||||
ij_wrap_on_typing = false
|
||||
|
||||
[*.java]
|
||||
ij_java_align_consecutive_assignments = false
|
||||
ij_java_align_consecutive_variable_declarations = false
|
||||
ij_java_align_group_field_declarations = false
|
||||
ij_java_align_multiline_annotation_parameters = false
|
||||
ij_java_align_multiline_array_initializer_expression = false
|
||||
ij_java_align_multiline_assignment = false
|
||||
ij_java_align_multiline_binary_operation = false
|
||||
ij_java_align_multiline_chained_methods = false
|
||||
ij_java_align_multiline_extends_list = false
|
||||
ij_java_align_multiline_for = true
|
||||
ij_java_align_multiline_method_parentheses = false
|
||||
ij_java_align_multiline_parameters = true
|
||||
ij_java_align_multiline_parameters_in_calls = false
|
||||
ij_java_align_multiline_parenthesized_expression = false
|
||||
ij_java_align_multiline_records = true
|
||||
ij_java_align_multiline_resources = true
|
||||
ij_java_align_multiline_ternary_operation = false
|
||||
ij_java_align_multiline_text_blocks = false
|
||||
ij_java_align_multiline_throws_list = false
|
||||
ij_java_align_subsequent_simple_methods = false
|
||||
ij_java_align_throws_keyword = false
|
||||
ij_java_align_types_in_multi_catch = true
|
||||
ij_java_annotation_parameter_wrap = off
|
||||
ij_java_array_initializer_new_line_after_left_brace = false
|
||||
ij_java_array_initializer_right_brace_on_new_line = false
|
||||
ij_java_array_initializer_wrap = off
|
||||
ij_java_assert_statement_colon_on_next_line = false
|
||||
ij_java_assert_statement_wrap = off
|
||||
ij_java_assignment_wrap = off
|
||||
ij_java_binary_operation_sign_on_next_line = false
|
||||
ij_java_binary_operation_wrap = off
|
||||
ij_java_blank_lines_after_anonymous_class_header = 0
|
||||
ij_java_blank_lines_after_class_header = 0
|
||||
ij_java_blank_lines_after_imports = 1
|
||||
ij_java_blank_lines_after_package = 1
|
||||
ij_java_blank_lines_around_class = 1
|
||||
ij_java_blank_lines_around_field = 0
|
||||
ij_java_blank_lines_around_field_in_interface = 0
|
||||
ij_java_blank_lines_around_initializer = 1
|
||||
ij_java_blank_lines_around_method = 1
|
||||
ij_java_blank_lines_around_method_in_interface = 1
|
||||
ij_java_blank_lines_before_class_end = 0
|
||||
ij_java_blank_lines_before_imports = 1
|
||||
ij_java_blank_lines_before_method_body = 0
|
||||
ij_java_blank_lines_before_package = 0
|
||||
ij_java_block_brace_style = end_of_line
|
||||
ij_java_block_comment_add_space = false
|
||||
ij_java_block_comment_at_first_column = true
|
||||
ij_java_builder_methods = none
|
||||
ij_java_call_parameters_new_line_after_left_paren = false
|
||||
ij_java_call_parameters_right_paren_on_new_line = false
|
||||
ij_java_call_parameters_wrap = off
|
||||
ij_java_case_statement_on_separate_line = true
|
||||
ij_java_catch_on_new_line = false
|
||||
ij_java_class_annotation_wrap = split_into_lines
|
||||
ij_java_class_brace_style = end_of_line
|
||||
ij_java_class_count_to_use_import_on_demand = 99
|
||||
ij_java_class_names_in_javadoc = 1
|
||||
ij_java_do_not_indent_top_level_class_members = false
|
||||
ij_java_do_not_wrap_after_single_annotation = false
|
||||
ij_java_do_not_wrap_after_single_annotation_in_parameter = false
|
||||
ij_java_do_while_brace_force = never
|
||||
ij_java_doc_add_blank_line_after_description = true
|
||||
ij_java_doc_add_blank_line_after_param_comments = false
|
||||
ij_java_doc_add_blank_line_after_return = false
|
||||
ij_java_doc_add_p_tag_on_empty_lines = true
|
||||
ij_java_doc_align_exception_comments = true
|
||||
ij_java_doc_align_param_comments = true
|
||||
ij_java_doc_do_not_wrap_if_one_line = false
|
||||
ij_java_doc_enable_formatting = true
|
||||
ij_java_doc_enable_leading_asterisks = true
|
||||
ij_java_doc_indent_on_continuation = false
|
||||
ij_java_doc_keep_empty_lines = true
|
||||
ij_java_doc_keep_empty_parameter_tag = true
|
||||
ij_java_doc_keep_empty_return_tag = true
|
||||
ij_java_doc_keep_empty_throws_tag = true
|
||||
ij_java_doc_keep_invalid_tags = true
|
||||
ij_java_doc_param_description_on_new_line = false
|
||||
ij_java_doc_preserve_line_breaks = false
|
||||
ij_java_doc_use_throws_not_exception_tag = true
|
||||
ij_java_else_on_new_line = false
|
||||
ij_java_enum_constants_wrap = off
|
||||
ij_java_extends_keyword_wrap = off
|
||||
ij_java_extends_list_wrap = off
|
||||
ij_java_field_annotation_wrap = split_into_lines
|
||||
ij_java_finally_on_new_line = false
|
||||
ij_java_for_brace_force = never
|
||||
ij_java_for_statement_new_line_after_left_paren = false
|
||||
ij_java_for_statement_right_paren_on_new_line = false
|
||||
ij_java_for_statement_wrap = off
|
||||
ij_java_generate_final_locals = false
|
||||
ij_java_generate_final_parameters = false
|
||||
ij_java_if_brace_force = never
|
||||
ij_java_imports_layout = $android.**,$androidx.**,$com.**,$junit.**,$net.**,$org.**,$java.**,$javax.**,$*,|,android.**,|,androidx.**,|,com.**,|,junit.**,|,net.**,|,org.**,|,java.**,|,javax.**,|,*,|
|
||||
ij_java_indent_case_from_switch = true
|
||||
ij_java_insert_inner_class_imports = false
|
||||
ij_java_insert_override_annotation = true
|
||||
ij_java_keep_blank_lines_before_right_brace = 2
|
||||
ij_java_keep_blank_lines_between_package_declaration_and_header = 2
|
||||
ij_java_keep_blank_lines_in_code = 2
|
||||
ij_java_keep_blank_lines_in_declarations = 2
|
||||
ij_java_keep_builder_methods_indents = false
|
||||
ij_java_keep_control_statement_in_one_line = true
|
||||
ij_java_keep_first_column_comment = true
|
||||
ij_java_keep_indents_on_empty_lines = false
|
||||
ij_java_keep_line_breaks = true
|
||||
ij_java_keep_multiple_expressions_in_one_line = false
|
||||
ij_java_keep_simple_blocks_in_one_line = false
|
||||
ij_java_keep_simple_classes_in_one_line = false
|
||||
ij_java_keep_simple_lambdas_in_one_line = false
|
||||
ij_java_keep_simple_methods_in_one_line = false
|
||||
ij_java_label_indent_absolute = false
|
||||
ij_java_label_indent_size = 0
|
||||
ij_java_lambda_brace_style = end_of_line
|
||||
ij_java_layout_static_imports_separately = true
|
||||
ij_java_line_comment_add_space = false
|
||||
ij_java_line_comment_add_space_on_reformat = false
|
||||
ij_java_line_comment_at_first_column = true
|
||||
ij_java_method_annotation_wrap = split_into_lines
|
||||
ij_java_method_brace_style = end_of_line
|
||||
ij_java_method_call_chain_wrap = off
|
||||
ij_java_method_parameters_new_line_after_left_paren = false
|
||||
ij_java_method_parameters_right_paren_on_new_line = false
|
||||
ij_java_method_parameters_wrap = off
|
||||
ij_java_modifier_list_wrap = false
|
||||
ij_java_multi_catch_types_wrap = normal
|
||||
ij_java_names_count_to_use_import_on_demand = 99
|
||||
ij_java_new_line_after_lparen_in_annotation = false
|
||||
ij_java_new_line_after_lparen_in_record_header = false
|
||||
ij_java_parameter_annotation_wrap = off
|
||||
ij_java_parentheses_expression_new_line_after_left_paren = false
|
||||
ij_java_parentheses_expression_right_paren_on_new_line = false
|
||||
ij_java_place_assignment_sign_on_next_line = false
|
||||
ij_java_prefer_longer_names = true
|
||||
ij_java_prefer_parameters_wrap = false
|
||||
ij_java_record_components_wrap = normal
|
||||
ij_java_repeat_synchronized = true
|
||||
ij_java_replace_instanceof_and_cast = false
|
||||
ij_java_replace_null_check = true
|
||||
ij_java_replace_sum_lambda_with_method_ref = true
|
||||
ij_java_resource_list_new_line_after_left_paren = false
|
||||
ij_java_resource_list_right_paren_on_new_line = false
|
||||
ij_java_resource_list_wrap = off
|
||||
ij_java_rparen_on_new_line_in_annotation = false
|
||||
ij_java_rparen_on_new_line_in_record_header = false
|
||||
ij_java_space_after_closing_angle_bracket_in_type_argument = false
|
||||
ij_java_space_after_colon = true
|
||||
ij_java_space_after_comma = true
|
||||
ij_java_space_after_comma_in_type_arguments = true
|
||||
ij_java_space_after_for_semicolon = true
|
||||
ij_java_space_after_quest = true
|
||||
ij_java_space_after_type_cast = true
|
||||
ij_java_space_before_annotation_array_initializer_left_brace = false
|
||||
ij_java_space_before_annotation_parameter_list = false
|
||||
ij_java_space_before_array_initializer_left_brace = false
|
||||
ij_java_space_before_catch_keyword = true
|
||||
ij_java_space_before_catch_left_brace = true
|
||||
ij_java_space_before_catch_parentheses = true
|
||||
ij_java_space_before_class_left_brace = true
|
||||
ij_java_space_before_colon = true
|
||||
ij_java_space_before_colon_in_foreach = true
|
||||
ij_java_space_before_comma = false
|
||||
ij_java_space_before_do_left_brace = true
|
||||
ij_java_space_before_else_keyword = true
|
||||
ij_java_space_before_else_left_brace = true
|
||||
ij_java_space_before_finally_keyword = true
|
||||
ij_java_space_before_finally_left_brace = true
|
||||
ij_java_space_before_for_left_brace = true
|
||||
ij_java_space_before_for_parentheses = true
|
||||
ij_java_space_before_for_semicolon = false
|
||||
ij_java_space_before_if_left_brace = true
|
||||
ij_java_space_before_if_parentheses = true
|
||||
ij_java_space_before_method_call_parentheses = false
|
||||
ij_java_space_before_method_left_brace = true
|
||||
ij_java_space_before_method_parentheses = false
|
||||
ij_java_space_before_opening_angle_bracket_in_type_parameter = false
|
||||
ij_java_space_before_quest = true
|
||||
ij_java_space_before_switch_left_brace = true
|
||||
ij_java_space_before_switch_parentheses = true
|
||||
ij_java_space_before_synchronized_left_brace = true
|
||||
ij_java_space_before_synchronized_parentheses = true
|
||||
ij_java_space_before_try_left_brace = true
|
||||
ij_java_space_before_try_parentheses = true
|
||||
ij_java_space_before_type_parameter_list = false
|
||||
ij_java_space_before_while_keyword = true
|
||||
ij_java_space_before_while_left_brace = true
|
||||
ij_java_space_before_while_parentheses = true
|
||||
ij_java_space_inside_one_line_enum_braces = false
|
||||
ij_java_space_within_empty_array_initializer_braces = false
|
||||
ij_java_space_within_empty_method_call_parentheses = false
|
||||
ij_java_space_within_empty_method_parentheses = false
|
||||
ij_java_spaces_around_additive_operators = true
|
||||
ij_java_spaces_around_annotation_eq = true
|
||||
ij_java_spaces_around_assignment_operators = true
|
||||
ij_java_spaces_around_bitwise_operators = true
|
||||
ij_java_spaces_around_equality_operators = true
|
||||
ij_java_spaces_around_lambda_arrow = true
|
||||
ij_java_spaces_around_logical_operators = true
|
||||
ij_java_spaces_around_method_ref_dbl_colon = false
|
||||
ij_java_spaces_around_multiplicative_operators = true
|
||||
ij_java_spaces_around_relational_operators = true
|
||||
ij_java_spaces_around_shift_operators = true
|
||||
ij_java_spaces_around_type_bounds_in_type_parameters = true
|
||||
ij_java_spaces_around_unary_operator = false
|
||||
ij_java_spaces_within_angle_brackets = false
|
||||
ij_java_spaces_within_annotation_parentheses = false
|
||||
ij_java_spaces_within_array_initializer_braces = false
|
||||
ij_java_spaces_within_braces = false
|
||||
ij_java_spaces_within_brackets = false
|
||||
ij_java_spaces_within_cast_parentheses = false
|
||||
ij_java_spaces_within_catch_parentheses = false
|
||||
ij_java_spaces_within_for_parentheses = false
|
||||
ij_java_spaces_within_if_parentheses = false
|
||||
ij_java_spaces_within_method_call_parentheses = false
|
||||
ij_java_spaces_within_method_parentheses = false
|
||||
ij_java_spaces_within_parentheses = false
|
||||
ij_java_spaces_within_record_header = false
|
||||
ij_java_spaces_within_switch_parentheses = false
|
||||
ij_java_spaces_within_synchronized_parentheses = false
|
||||
ij_java_spaces_within_try_parentheses = false
|
||||
ij_java_spaces_within_while_parentheses = false
|
||||
ij_java_special_else_if_treatment = true
|
||||
ij_java_subclass_name_suffix = Impl
|
||||
ij_java_ternary_operation_signs_on_next_line = false
|
||||
ij_java_ternary_operation_wrap = off
|
||||
ij_java_test_name_suffix = Test
|
||||
ij_java_throws_keyword_wrap = off
|
||||
ij_java_throws_list_wrap = off
|
||||
ij_java_use_external_annotations = false
|
||||
ij_java_use_fq_class_names = false
|
||||
ij_java_use_relative_indents = false
|
||||
ij_java_use_single_class_imports = true
|
||||
ij_java_variable_annotation_wrap = off
|
||||
ij_java_visibility = public
|
||||
ij_java_while_brace_force = never
|
||||
ij_java_while_on_new_line = false
|
||||
ij_java_wrap_comments = false
|
||||
ij_java_wrap_first_method_in_call_chain = false
|
||||
ij_java_wrap_long_lines = false
|
||||
|
||||
[.editorconfig]
|
||||
ij_editorconfig_align_group_field_declarations = false
|
||||
ij_editorconfig_space_after_colon = false
|
||||
ij_editorconfig_space_after_comma = true
|
||||
ij_editorconfig_space_before_colon = false
|
||||
ij_editorconfig_space_before_comma = false
|
||||
ij_editorconfig_spaces_around_assignment_operators = true
|
||||
|
||||
[{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.rng,*.tld,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul}]
|
||||
ij_continuation_indent_size = 4
|
||||
ij_xml_align_attributes = false
|
||||
ij_xml_align_text = false
|
||||
ij_xml_attribute_wrap = normal
|
||||
ij_xml_block_comment_add_space = false
|
||||
ij_xml_block_comment_at_first_column = true
|
||||
ij_xml_keep_blank_lines = 2
|
||||
ij_xml_keep_indents_on_empty_lines = false
|
||||
ij_xml_keep_line_breaks = false
|
||||
ij_xml_keep_line_breaks_in_text = true
|
||||
ij_xml_keep_whitespaces = false
|
||||
ij_xml_keep_whitespaces_around_cdata = preserve
|
||||
ij_xml_keep_whitespaces_inside_cdata = false
|
||||
ij_xml_line_comment_at_first_column = true
|
||||
ij_xml_space_after_tag_name = false
|
||||
ij_xml_space_around_equals_in_attribute = false
|
||||
ij_xml_space_inside_empty_tag = true
|
||||
ij_xml_text_wrap = normal
|
||||
ij_xml_use_custom_settings = true
|
||||
|
||||
[{*.gant,*.groovy,*.gy}]
|
||||
ij_groovy_align_group_field_declarations = false
|
||||
ij_groovy_align_multiline_array_initializer_expression = false
|
||||
ij_groovy_align_multiline_assignment = false
|
||||
ij_groovy_align_multiline_binary_operation = false
|
||||
ij_groovy_align_multiline_chained_methods = false
|
||||
ij_groovy_align_multiline_extends_list = false
|
||||
ij_groovy_align_multiline_for = true
|
||||
ij_groovy_align_multiline_list_or_map = true
|
||||
ij_groovy_align_multiline_method_parentheses = false
|
||||
ij_groovy_align_multiline_parameters = true
|
||||
ij_groovy_align_multiline_parameters_in_calls = false
|
||||
ij_groovy_align_multiline_resources = true
|
||||
ij_groovy_align_multiline_ternary_operation = false
|
||||
ij_groovy_align_multiline_throws_list = false
|
||||
ij_groovy_align_named_args_in_map = true
|
||||
ij_groovy_align_throws_keyword = false
|
||||
ij_groovy_array_initializer_new_line_after_left_brace = false
|
||||
ij_groovy_array_initializer_right_brace_on_new_line = false
|
||||
ij_groovy_array_initializer_wrap = off
|
||||
ij_groovy_assert_statement_wrap = off
|
||||
ij_groovy_assignment_wrap = off
|
||||
ij_groovy_binary_operation_wrap = off
|
||||
ij_groovy_blank_lines_after_class_header = 0
|
||||
ij_groovy_blank_lines_after_imports = 1
|
||||
ij_groovy_blank_lines_after_package = 1
|
||||
ij_groovy_blank_lines_around_class = 1
|
||||
ij_groovy_blank_lines_around_field = 0
|
||||
ij_groovy_blank_lines_around_field_in_interface = 0
|
||||
ij_groovy_blank_lines_around_method = 1
|
||||
ij_groovy_blank_lines_around_method_in_interface = 1
|
||||
ij_groovy_blank_lines_before_imports = 1
|
||||
ij_groovy_blank_lines_before_method_body = 0
|
||||
ij_groovy_blank_lines_before_package = 0
|
||||
ij_groovy_block_brace_style = end_of_line
|
||||
ij_groovy_block_comment_add_space = false
|
||||
ij_groovy_block_comment_at_first_column = true
|
||||
ij_groovy_call_parameters_new_line_after_left_paren = false
|
||||
ij_groovy_call_parameters_right_paren_on_new_line = false
|
||||
ij_groovy_call_parameters_wrap = off
|
||||
ij_groovy_catch_on_new_line = false
|
||||
ij_groovy_class_annotation_wrap = split_into_lines
|
||||
ij_groovy_class_brace_style = end_of_line
|
||||
ij_groovy_class_count_to_use_import_on_demand = 5
|
||||
ij_groovy_do_while_brace_force = never
|
||||
ij_groovy_else_on_new_line = false
|
||||
ij_groovy_enable_groovydoc_formatting = true
|
||||
ij_groovy_enum_constants_wrap = off
|
||||
ij_groovy_extends_keyword_wrap = off
|
||||
ij_groovy_extends_list_wrap = off
|
||||
ij_groovy_field_annotation_wrap = split_into_lines
|
||||
ij_groovy_finally_on_new_line = false
|
||||
ij_groovy_for_brace_force = never
|
||||
ij_groovy_for_statement_new_line_after_left_paren = false
|
||||
ij_groovy_for_statement_right_paren_on_new_line = false
|
||||
ij_groovy_for_statement_wrap = off
|
||||
ij_groovy_if_brace_force = never
|
||||
ij_groovy_import_annotation_wrap = 2
|
||||
ij_groovy_imports_layout = *,|,javax.**,java.**,|,$*
|
||||
ij_groovy_indent_case_from_switch = true
|
||||
ij_groovy_indent_label_blocks = true
|
||||
ij_groovy_insert_inner_class_imports = false
|
||||
ij_groovy_keep_blank_lines_before_right_brace = 2
|
||||
ij_groovy_keep_blank_lines_in_code = 2
|
||||
ij_groovy_keep_blank_lines_in_declarations = 2
|
||||
ij_groovy_keep_control_statement_in_one_line = true
|
||||
ij_groovy_keep_first_column_comment = true
|
||||
ij_groovy_keep_indents_on_empty_lines = false
|
||||
ij_groovy_keep_line_breaks = true
|
||||
ij_groovy_keep_multiple_expressions_in_one_line = false
|
||||
ij_groovy_keep_simple_blocks_in_one_line = false
|
||||
ij_groovy_keep_simple_classes_in_one_line = true
|
||||
ij_groovy_keep_simple_lambdas_in_one_line = true
|
||||
ij_groovy_keep_simple_methods_in_one_line = true
|
||||
ij_groovy_label_indent_absolute = false
|
||||
ij_groovy_label_indent_size = 0
|
||||
ij_groovy_lambda_brace_style = end_of_line
|
||||
ij_groovy_layout_static_imports_separately = true
|
||||
ij_groovy_line_comment_add_space = false
|
||||
ij_groovy_line_comment_add_space_on_reformat = false
|
||||
ij_groovy_line_comment_at_first_column = true
|
||||
ij_groovy_method_annotation_wrap = split_into_lines
|
||||
ij_groovy_method_brace_style = end_of_line
|
||||
ij_groovy_method_call_chain_wrap = off
|
||||
ij_groovy_method_parameters_new_line_after_left_paren = false
|
||||
ij_groovy_method_parameters_right_paren_on_new_line = false
|
||||
ij_groovy_method_parameters_wrap = off
|
||||
ij_groovy_modifier_list_wrap = false
|
||||
ij_groovy_names_count_to_use_import_on_demand = 3
|
||||
ij_groovy_packages_to_use_import_on_demand = java.awt.*,javax.swing.*
|
||||
ij_groovy_parameter_annotation_wrap = off
|
||||
ij_groovy_parentheses_expression_new_line_after_left_paren = false
|
||||
ij_groovy_parentheses_expression_right_paren_on_new_line = false
|
||||
ij_groovy_prefer_parameters_wrap = false
|
||||
ij_groovy_resource_list_new_line_after_left_paren = false
|
||||
ij_groovy_resource_list_right_paren_on_new_line = false
|
||||
ij_groovy_resource_list_wrap = off
|
||||
ij_groovy_space_after_assert_separator = true
|
||||
ij_groovy_space_after_colon = true
|
||||
ij_groovy_space_after_comma = true
|
||||
ij_groovy_space_after_comma_in_type_arguments = true
|
||||
ij_groovy_space_after_for_semicolon = true
|
||||
ij_groovy_space_after_quest = true
|
||||
ij_groovy_space_after_type_cast = true
|
||||
ij_groovy_space_before_annotation_parameter_list = false
|
||||
ij_groovy_space_before_array_initializer_left_brace = false
|
||||
ij_groovy_space_before_assert_separator = false
|
||||
ij_groovy_space_before_catch_keyword = true
|
||||
ij_groovy_space_before_catch_left_brace = true
|
||||
ij_groovy_space_before_catch_parentheses = true
|
||||
ij_groovy_space_before_class_left_brace = true
|
||||
ij_groovy_space_before_closure_left_brace = true
|
||||
ij_groovy_space_before_colon = true
|
||||
ij_groovy_space_before_comma = false
|
||||
ij_groovy_space_before_do_left_brace = true
|
||||
ij_groovy_space_before_else_keyword = true
|
||||
ij_groovy_space_before_else_left_brace = true
|
||||
ij_groovy_space_before_finally_keyword = true
|
||||
ij_groovy_space_before_finally_left_brace = true
|
||||
ij_groovy_space_before_for_left_brace = true
|
||||
ij_groovy_space_before_for_parentheses = true
|
||||
ij_groovy_space_before_for_semicolon = false
|
||||
ij_groovy_space_before_if_left_brace = true
|
||||
ij_groovy_space_before_if_parentheses = true
|
||||
ij_groovy_space_before_method_call_parentheses = false
|
||||
ij_groovy_space_before_method_left_brace = true
|
||||
ij_groovy_space_before_method_parentheses = false
|
||||
ij_groovy_space_before_quest = true
|
||||
ij_groovy_space_before_record_parentheses = false
|
||||
ij_groovy_space_before_switch_left_brace = true
|
||||
ij_groovy_space_before_switch_parentheses = true
|
||||
ij_groovy_space_before_synchronized_left_brace = true
|
||||
ij_groovy_space_before_synchronized_parentheses = true
|
||||
ij_groovy_space_before_try_left_brace = true
|
||||
ij_groovy_space_before_try_parentheses = true
|
||||
ij_groovy_space_before_while_keyword = true
|
||||
ij_groovy_space_before_while_left_brace = true
|
||||
ij_groovy_space_before_while_parentheses = true
|
||||
ij_groovy_space_in_named_argument = true
|
||||
ij_groovy_space_in_named_argument_before_colon = false
|
||||
ij_groovy_space_within_empty_array_initializer_braces = false
|
||||
ij_groovy_space_within_empty_method_call_parentheses = false
|
||||
ij_groovy_spaces_around_additive_operators = true
|
||||
ij_groovy_spaces_around_assignment_operators = true
|
||||
ij_groovy_spaces_around_bitwise_operators = true
|
||||
ij_groovy_spaces_around_equality_operators = true
|
||||
ij_groovy_spaces_around_lambda_arrow = true
|
||||
ij_groovy_spaces_around_logical_operators = true
|
||||
ij_groovy_spaces_around_multiplicative_operators = true
|
||||
ij_groovy_spaces_around_regex_operators = true
|
||||
ij_groovy_spaces_around_relational_operators = true
|
||||
ij_groovy_spaces_around_shift_operators = true
|
||||
ij_groovy_spaces_within_annotation_parentheses = false
|
||||
ij_groovy_spaces_within_array_initializer_braces = false
|
||||
ij_groovy_spaces_within_braces = true
|
||||
ij_groovy_spaces_within_brackets = false
|
||||
ij_groovy_spaces_within_cast_parentheses = false
|
||||
ij_groovy_spaces_within_catch_parentheses = false
|
||||
ij_groovy_spaces_within_for_parentheses = false
|
||||
ij_groovy_spaces_within_gstring_injection_braces = false
|
||||
ij_groovy_spaces_within_if_parentheses = false
|
||||
ij_groovy_spaces_within_list_or_map = false
|
||||
ij_groovy_spaces_within_method_call_parentheses = false
|
||||
ij_groovy_spaces_within_method_parentheses = false
|
||||
ij_groovy_spaces_within_parentheses = false
|
||||
ij_groovy_spaces_within_switch_parentheses = false
|
||||
ij_groovy_spaces_within_synchronized_parentheses = false
|
||||
ij_groovy_spaces_within_try_parentheses = false
|
||||
ij_groovy_spaces_within_tuple_expression = false
|
||||
ij_groovy_spaces_within_while_parentheses = false
|
||||
ij_groovy_special_else_if_treatment = true
|
||||
ij_groovy_ternary_operation_wrap = off
|
||||
ij_groovy_throws_keyword_wrap = off
|
||||
ij_groovy_throws_list_wrap = off
|
||||
ij_groovy_use_flying_geese_braces = false
|
||||
ij_groovy_use_fq_class_names = false
|
||||
ij_groovy_use_fq_class_names_in_javadoc = true
|
||||
ij_groovy_use_relative_indents = false
|
||||
ij_groovy_use_single_class_imports = true
|
||||
ij_groovy_variable_annotation_wrap = off
|
||||
ij_groovy_while_brace_force = never
|
||||
ij_groovy_while_on_new_line = false
|
||||
ij_groovy_wrap_chain_calls_after_dot = false
|
||||
ij_groovy_wrap_long_lines = false
|
||||
|
||||
[{*.kt,*.kts,*.main.kts}]
|
||||
ij_kotlin_align_in_columns_case_branch = false
|
||||
ij_kotlin_align_multiline_binary_operation = false
|
||||
ij_kotlin_align_multiline_extends_list = false
|
||||
ij_kotlin_align_multiline_method_parentheses = false
|
||||
ij_kotlin_align_multiline_parameters = true
|
||||
ij_kotlin_align_multiline_parameters_in_calls = false
|
||||
ij_kotlin_allow_trailing_comma = false
|
||||
ij_kotlin_allow_trailing_comma_on_call_site = false
|
||||
ij_kotlin_assignment_wrap = normal
|
||||
ij_kotlin_blank_lines_after_class_header = 0
|
||||
ij_kotlin_blank_lines_around_block_when_branches = 0
|
||||
ij_kotlin_blank_lines_before_declaration_with_comment_or_annotation_on_separate_line = 1
|
||||
ij_kotlin_block_comment_add_space = false
|
||||
ij_kotlin_block_comment_at_first_column = true
|
||||
ij_kotlin_call_parameters_new_line_after_left_paren = true
|
||||
ij_kotlin_call_parameters_right_paren_on_new_line = true
|
||||
ij_kotlin_call_parameters_wrap = on_every_item
|
||||
ij_kotlin_catch_on_new_line = false
|
||||
ij_kotlin_class_annotation_wrap = split_into_lines
|
||||
ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL
|
||||
ij_kotlin_continuation_indent_for_chained_calls = false
|
||||
ij_kotlin_continuation_indent_for_expression_bodies = false
|
||||
ij_kotlin_continuation_indent_in_argument_lists = false
|
||||
ij_kotlin_continuation_indent_in_elvis = false
|
||||
ij_kotlin_continuation_indent_in_if_conditions = false
|
||||
ij_kotlin_continuation_indent_in_parameter_lists = false
|
||||
ij_kotlin_continuation_indent_in_supertype_lists = false
|
||||
ij_kotlin_else_on_new_line = false
|
||||
ij_kotlin_enum_constants_wrap = off
|
||||
ij_kotlin_extends_list_wrap = normal
|
||||
ij_kotlin_field_annotation_wrap = split_into_lines
|
||||
ij_kotlin_finally_on_new_line = false
|
||||
ij_kotlin_if_rparen_on_new_line = true
|
||||
ij_kotlin_import_nested_classes = false
|
||||
ij_kotlin_imports_layout = *,java.**,javax.**,kotlin.**,^
|
||||
ij_kotlin_insert_whitespaces_in_simple_one_line_method = true
|
||||
ij_kotlin_keep_blank_lines_before_right_brace = 2
|
||||
ij_kotlin_keep_blank_lines_in_code = 2
|
||||
ij_kotlin_keep_blank_lines_in_declarations = 2
|
||||
ij_kotlin_keep_first_column_comment = true
|
||||
ij_kotlin_keep_indents_on_empty_lines = false
|
||||
ij_kotlin_keep_line_breaks = true
|
||||
ij_kotlin_lbrace_on_next_line = false
|
||||
ij_kotlin_line_comment_add_space = false
|
||||
ij_kotlin_line_comment_add_space_on_reformat = false
|
||||
ij_kotlin_line_comment_at_first_column = true
|
||||
ij_kotlin_method_annotation_wrap = split_into_lines
|
||||
ij_kotlin_method_call_chain_wrap = normal
|
||||
ij_kotlin_method_parameters_new_line_after_left_paren = true
|
||||
ij_kotlin_method_parameters_right_paren_on_new_line = true
|
||||
ij_kotlin_method_parameters_wrap = on_every_item
|
||||
ij_kotlin_name_count_to_use_star_import = 5
|
||||
ij_kotlin_name_count_to_use_star_import_for_members = 3
|
||||
ij_kotlin_packages_to_use_import_on_demand = java.util.*,kotlinx.android.synthetic.**,io.ktor.**
|
||||
ij_kotlin_parameter_annotation_wrap = off
|
||||
ij_kotlin_space_after_comma = true
|
||||
ij_kotlin_space_after_extend_colon = true
|
||||
ij_kotlin_space_after_type_colon = true
|
||||
ij_kotlin_space_before_catch_parentheses = true
|
||||
ij_kotlin_space_before_comma = false
|
||||
ij_kotlin_space_before_extend_colon = true
|
||||
ij_kotlin_space_before_for_parentheses = true
|
||||
ij_kotlin_space_before_if_parentheses = true
|
||||
ij_kotlin_space_before_lambda_arrow = true
|
||||
ij_kotlin_space_before_type_colon = false
|
||||
ij_kotlin_space_before_when_parentheses = true
|
||||
ij_kotlin_space_before_while_parentheses = true
|
||||
ij_kotlin_spaces_around_additive_operators = true
|
||||
ij_kotlin_spaces_around_assignment_operators = true
|
||||
ij_kotlin_spaces_around_equality_operators = true
|
||||
ij_kotlin_spaces_around_function_type_arrow = true
|
||||
ij_kotlin_spaces_around_logical_operators = true
|
||||
ij_kotlin_spaces_around_multiplicative_operators = true
|
||||
ij_kotlin_spaces_around_range = false
|
||||
ij_kotlin_spaces_around_relational_operators = true
|
||||
ij_kotlin_spaces_around_unary_operator = false
|
||||
ij_kotlin_spaces_around_when_arrow = true
|
||||
ij_kotlin_use_custom_formatting_for_modifiers = true
|
||||
ij_kotlin_variable_annotation_wrap = off
|
||||
ij_kotlin_while_on_new_line = false
|
||||
ij_kotlin_wrap_elvis_expressions = 1
|
||||
ij_kotlin_wrap_expression_body_functions = 1
|
||||
ij_kotlin_wrap_first_method_in_call_chain = false
|
||||
43
.gitlab-ci.yml
Normal file
43
.gitlab-ci.yml
Normal file
@ -0,0 +1,43 @@
|
||||
stages:
|
||||
- analysis
|
||||
- sendmail
|
||||
|
||||
## 代码检查
|
||||
sonarqube_analysis:
|
||||
tags:
|
||||
- offline-test
|
||||
stage: analysis
|
||||
image: sonarsource/sonar-scanner-cli:latest
|
||||
dependencies: [] #禁止传递来的artifact
|
||||
script:
|
||||
## 获取项目的一级组和二级组和项目名作为projectKey,例如projectKey=platform-backend-eci-monitor
|
||||
- group=`echo $CI_PROJECT_PATH | sed 's#/#-#g'`
|
||||
- sonar-scanner
|
||||
-Dsonar.host.url=http://sonarqube-server.sonarqube:9000/
|
||||
-Dsonar.login=be43de7264ce4c4766eb0c020373c3e74e6df257
|
||||
-Dsonar.jacoco.reportPaths=target/jacoco.exec
|
||||
-Dsonar.projectKey=$group
|
||||
-Dsonar.projectName=$CI_PROJECT_PATH
|
||||
-Dsonar.sourceEncoding=UTF-8
|
||||
-Dsonar.exclusions=**/vendor/**,**/errcode/**
|
||||
-Dsonar.gitlab.project_id=$CI_PROJECT_ID
|
||||
-Dsonar.gitlab.commit_sha=$CI_COMMIT_SHA
|
||||
-Dsonar.gitlab.ref_name=$CI_COMMIT_REF_NAME
|
||||
-Dsonar.gitlab.ci_merge_request_iid=$CI_MERGE_REQUEST_IID
|
||||
-Dsonar.gitlab.merge_request_discussion=true
|
||||
-Dsonar.java.binaries=. # 如果不使用Maven或Gradle进行分析,则必须手动提供测试二进制文件
|
||||
only:
|
||||
- dev
|
||||
|
||||
## 发送简易检测结果报告
|
||||
send_sonar_report:
|
||||
tags:
|
||||
- offline-test
|
||||
stage: sendmail
|
||||
image: hub.shanqu.cc/library/docker:latest
|
||||
dependencies: [] #禁止传递来的artifact
|
||||
script:
|
||||
- group=`echo $CI_PROJECT_PATH | sed 's#/#-#g'`
|
||||
- docker run -e PROJECTKEY=$group -e EMAIL=$GITLAB_USER_EMAIL --name send-email --rm hub.shanqu.cc/platform/send-sonar-report:latest
|
||||
only:
|
||||
- dev
|
||||
8
.gitmodules
vendored
8
.gitmodules
vendored
@ -1,4 +1,10 @@
|
||||
[submodule "libraries/LGLibrary"]
|
||||
path = libraries/LGLibrary
|
||||
url = git@git.ghzs.com:android/common-library.git
|
||||
url = git@git.shanqu.cc:android/common-library.git
|
||||
branch = master
|
||||
[submodule "vspace-bridge"]
|
||||
path = vspace-bridge
|
||||
url = git@git.shanqu.cc:cwzs/android/vspace-bridge.git
|
||||
[submodule "module_common/src/debug/assets/assistant-android-mock"]
|
||||
path = module_common/src/debug/assets/assistant-android-mock
|
||||
url = git@git.shanqu.cc:halo/android/assistant-android-mock.git
|
||||
|
||||
95
README.md
95
README.md
@ -1,69 +1,66 @@
|
||||
# 光环助手Android客户端
|
||||
|
||||
### APK打包配置
|
||||
### 概述
|
||||
|
||||
* 使用[ApkChannelPackage](https://github.com/ltlovezh/ApkChannelPackage)的方案
|
||||
* 打包命令,视情况使用:
|
||||
光环助手Android客户端目前使用 Kotlin 作为主要开发语言,以 MVVM 作为参考架构模式进行开发
|
||||
|
||||
> 打包Tinker基准包:`./scripts/tinker_release_base.sh`
|
||||
### 约束
|
||||
|
||||
> 以Tinker基准包打渠道包:`./scripts/tinker_release_channel.sh`
|
||||
为编写易读易维护且较健壮的代码,可参考以下约束
|
||||
|
||||
> 以Tinker基准包打补丁包:`./scripts/tinker_release_patch.sh`
|
||||
1. 尽量将逻辑代码放置于 ViewModel 中,View 中只执行 UI 操作
|
||||
2. 尽量使 View 在被销毁之后仍能恢复状态,处理方式可参考 [保存界面状态](https://developer.android.com/topic/libraries/architecture/saving-states)
|
||||
3. 尽量参考原有文件结构及命名规范,即以 大模块 - 小模块 的形式生成包关系
|
||||
4. 遵循最小改动原则,在提交代码前务必先检查变动的代码,尽量以可控的变动规模来构成一个 commit ,以便日后追踪问题
|
||||
5. Commit message 提交规范可参考 [Conventional Commits](https://www.conventionalcommits.org/zh-hans/v1.0.0/)
|
||||
6. 代码规范可参考 [AOSP Java 风格](https://source.android.com/setup/contribute/code-style)
|
||||
7. 尽量使用 Kotlin 来写新文件
|
||||
8. 不要使用 DataBinding
|
||||
9. Commit 前请确保不带入非项目必须文件,可手动修改 [.gitignore](https://stackoverflow.com/questions/8527597/how-do-i-ignore-files-in-a-directory-in-git) 文件忽略
|
||||
10. 优先使用 ViewBinding 获取 View 对象
|
||||
11. No AsyncTask!
|
||||
|
||||
### 混淆配置
|
||||
### 公用部分
|
||||
|
||||
* 配置文件:Android默认配置+proguard-rules.txt等
|
||||
* 参考libraries下每个项目独立的配置文件`proguard-project.txt`
|
||||
本项目使用 LiveData 实现了一个简单通用的基础列表分页功能,具体可见 `ListFragment`, `ListViewModel` 等类,理想情况下只需少量代码即可新建一个简单分页列表
|
||||
|
||||
### apk大小优化
|
||||
### 首次拉取项目代码
|
||||
|
||||
* 限制resConfig资源集
|
||||
* 开启ShrinkResources
|
||||
* 开启混淆,使用minifyEnabled(仅在release开启)
|
||||
* pngquant对png压缩、png/jpg->webp(未尝试)
|
||||
`git clone -b dev git@git.shanqu.cc:halo/android/assistant-android.git --recursive`
|
||||
|
||||
### git 版本管理
|
||||
|
||||
本项目使用简化版的 git flow 来管理分支,细节请看 [光环安卓简单 git 规范](https://git.ghzs.com/halo/android/assistant-android/-/wikis/%E5%85%89%E7%8E%AF%E5%AE%89%E5%8D%93%E7%AE%80%E5%8D%95-git-%E8%A7%84%E8%8C%83)
|
||||
|
||||
### API 环境配置
|
||||
|
||||
本项目使用 Build Variants 来切换 API 环境
|
||||
|
||||
* internal 为测试环境
|
||||
* publish 为正式环境
|
||||
|
||||
### 图片资源配置
|
||||
|
||||
* 新增图片资源时,默认只添加最高规格的 xxxhdpi 文件
|
||||
* 新增图片资源时,需要将其转换为 .webp 格式 (包括含透明图层的图片,默认质量为90%) (转换后体积变大的文件除外)
|
||||
|
||||
### 第三方appkey等配置
|
||||
|
||||
* 修改`gradle.properties`文件将各种key填入其中,实现统一管理
|
||||
* 通过gradle文件内的resValue/buildConfigField/manifestPlaceHolder方式实现编译期间修改,具体情况请参考``./build.gradle``和``./app/build.gradle``配置
|
||||
* 修改 `gradle.properties` 文件将各种key填入其中,实现统一管理
|
||||
* 通过 gradle 文件内的 resValue/buildConfigField/manifestPlaceHolder 方式实现编译期间修改,具体情况请参考 ``./build.gradle`` 和 ``./app/build.gradle`` 配置
|
||||
|
||||
### 拉取代码步骤
|
||||
### 混淆配置
|
||||
|
||||
1. 拉取主项目代码: `git clone -b dev git@gitlab.ghzhushou.com:halo/assistant-android.git`
|
||||
2. 初始化公用类库: `bash ./scripts/submodules_init.sh`
|
||||
* 本项目使用了微信的 [AndResGuard](https://github.com/shwenzhang/AndResGuard) 作为资源混淆压缩方案,新增需要使用 `getIdentifier` 获取的资源文件时需要添加至白名单
|
||||
* 本项目默认使用 R8 作为混淆工具,往 proguard-rules.txt 添加 proguard 新配置项时请检查可用性(如语法等)
|
||||
|
||||
### submodule管理方式(只拉取master)
|
||||
### APK打包配置
|
||||
|
||||
* 提交代码,需要cd到submodule文件夹去做修改
|
||||
* 更新远端代码,`bash ./scripts/submodules_update.sh`
|
||||
> 打内部测试包:`./scripts/test_build.sh`
|
||||
> 打邮件测试包:`./scripts/jenkins_build.sh`
|
||||
|
||||
### TODO
|
||||
|
||||
* GSON 序列化用统一的一个, GsonUtil fromJson
|
||||
* CleanApkAdapter 转化字符串size工具函数 比如SpeedUtils
|
||||
* getString 解决 字符串hardcode问题
|
||||
* ~~Adapter 里面clicklistener 用接口传参将点击操作委托给controller~~
|
||||
* ~~Adapter ViewHolder的功能,部分重写到ViewHolder类本身~~
|
||||
|
||||
* ~~activity 统一入口未完成(外部入口相关),去除多余activity使用,统一toolbar~~
|
||||
* ~~release / debug compile不同的类库,不需要再做什么开关~~
|
||||
|
||||
* ~~Toolbar分离,有图形按钮/没有图形按钮~~
|
||||
|
||||
### TODO Since 3.1
|
||||
|
||||
- 解决 Utils 工具类引发的内存泄漏问题
|
||||
- 把原有 EventBus 的消息 Type 统一到一个文件内
|
||||
- 将实现细节从 View(Fragment、Activity) 剥离并以 MVVM 结构改造
|
||||
- ~~将 ListViewModel 所对应的 ListRepository 合并到 ListViewModel 中~~
|
||||
- 依照光环助手界面功能以大模块 - 小模块的方式去修改包结构,包内文件建议以包名摘要作为前缀
|
||||
- ~~使用 RxJava 的 Debounce 和 Map 操作优化搜索触发机制 参考资料:[1](https://proandroiddev.com/building-an-autocompleting-edittext-using-rxjava-f69c5c3f5a40),[2](https://medium.com/@kurtisnusbaum/rxandroid-basics-part-2-6e877af352)~~
|
||||
|
||||
- ~~把 ListViewModel 的数据结构类型转换方式换为抽象方法,让继承的类实现,避免出现无响应的问题~~
|
||||
|
||||
- ~~rxjava2 如果接口返回为空 会发生异常:java.lang.NullPointerException: Null is not a valid element (答案编辑) 解决方法->com.gh.gamecenter.retrofit.Response~~
|
||||
- constraintLayout 1.1.2 导致布局出现异常(问题编辑标签选择弹窗)
|
||||
|
||||
- 搞清楚 GameManager 的用途,看能不能去掉
|
||||
- 重构一下 MainActivity
|
||||
* 把原有 EventBus 的消息 Type 统一到一个文件内
|
||||
* 将实现细节从 View(Fragment、Activity) 剥离并以 MVVM 结构改造
|
||||
* 重构 MainActivity
|
||||
|
||||
354
app/build.gradle
354
app/build.gradle
@ -1,21 +1,17 @@
|
||||
// This comment exists for a reason, do not delete
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android' // kotlin
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-parcelize'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
//apply plugin: 'io.sentry.android.gradle'
|
||||
apply plugin: 'AndResGuard'
|
||||
|
||||
import groovy.xml.XmlUtil
|
||||
|
||||
android {
|
||||
|
||||
androidExtensions {
|
||||
experimental = true
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
dataBinding = true
|
||||
viewBinding true
|
||||
dataBinding true
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
@ -30,23 +26,31 @@ android {
|
||||
dexOptions {
|
||||
// jumboMode = true
|
||||
javaMaxHeapSize "4g"
|
||||
preDexLibraries true
|
||||
maxProcessCount 8
|
||||
}
|
||||
|
||||
aaptOptions {
|
||||
additionalParameters "--no-version-vectors"
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
|
||||
multiDexEnabled true
|
||||
javaCompileOptions {
|
||||
annotationProcessorOptions {
|
||||
arguments = [eventBusIndex: 'com.gh.EventBusIndex']
|
||||
}
|
||||
kapt {
|
||||
useBuildCache = true
|
||||
javacOptions {
|
||||
// 增加注解处理器的最大错误次数,默认为 100
|
||||
option("-Xmaxerrs", 500)
|
||||
}
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
multiDexEnabled true
|
||||
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86"
|
||||
// x86 本来是为了模拟器用户使用 RenderScript 用的,但是其实用到 RenderScript 的人本来就不多 (一天不到 100),用模拟器的人就更少了
|
||||
// 加了 x86 反而会导致用户没法使用微博登录,因为微博没有提供 x86 的 SO ...
|
||||
// 还会增大 APK 体积,所以还是去掉吧。数据可见 https://sentry.shanqu.cc/organizations/lightgame/issues/144232/?project=22
|
||||
abiFilters "armeabi-v7a", "arm64-v8a"
|
||||
}
|
||||
|
||||
renderscriptTargetApi 18
|
||||
@ -66,31 +70,13 @@ android {
|
||||
/**
|
||||
* All third-party appid/appkey
|
||||
*/
|
||||
buildConfigField "String", "API_HOST", "\"${API_HOST}\""
|
||||
buildConfigField "String", "NEW_API_HOST", "\"${NEW_API_HOST}\""
|
||||
buildConfigField "String", "VAPI_HOST", "\"${VAPI_HOST}\""
|
||||
buildConfigField "String", "WECHAT_APPID", "\"${WECHAT_APPID}\""
|
||||
buildConfigField "String", "WECHAT_SECRET", "\"${WECHAT_SECRET}\""
|
||||
buildConfigField "String", "TENCENT_APPID", "\"${TENCENT_APPID}\""
|
||||
buildConfigField "String", "WEIBO_APPKEY", "\"${WEIBO_APPKEY}\""
|
||||
buildConfigField "String", "MTA_APPKEY", "\"${MTA_APPKEY}\""
|
||||
buildConfigField "String", "TD_APPID", "\"${TD_APPID}\""
|
||||
buildConfigField "String", "LETO_APPID", "\"${LETO_APPID}\""
|
||||
buildConfigField "String", "TTAD_APPID", "\"${TTAD_APPID}\""
|
||||
buildConfigField "String", "DOUYIN_CLIENTKEY", "\"${DOUYIN_CLIENTKEY}\""
|
||||
buildConfigField "String", "DOUYIN_CLIENTSECRET", "\"${DOUYIN_CLIENTSECRET}\""
|
||||
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${QUICK_LOGIN_APPID}\""
|
||||
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${QUICK_LOGIN_APPKEY}\""
|
||||
|
||||
buildConfigField "String", "MIPUSH_APPID", "\"${MIPUSH_APPID}\""
|
||||
buildConfigField "String", "MIPUSH_APPKEY", "\"${MIPUSH_APPKEY}\""
|
||||
buildConfigField "String", "MEIZUPUSH_APPID", "\"${MEIZUPUSH_APPID}\""
|
||||
buildConfigField "String", "MEIZUPUSH_APPKEY", "\"${MEIZUPUSH_APPKEY}\""
|
||||
|
||||
resValue "string", "huawei_push_appid", "appid=${HUAWEI_PUSH_APPID}"
|
||||
|
||||
/**
|
||||
* Build Time 供区分 jenkins 打包时间用
|
||||
*/
|
||||
buildConfigField "long", "BUILD_TIME", "0"
|
||||
|
||||
}
|
||||
|
||||
// gradle 2.2以上默认同时启用v1和v2(优先用于Android N)
|
||||
@ -105,6 +91,12 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
kapt {
|
||||
arguments {
|
||||
arg("AROUTER_MODULE_NAME", project.name)
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
debuggable true
|
||||
@ -131,74 +123,64 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore useless variant
|
||||
variantFilter { variant ->
|
||||
def names = variant.flavors*.name
|
||||
def isDebugType = variant.buildType.name == "debug"
|
||||
if ((names.contains("tea")) && isDebugType) {
|
||||
setIgnore(true)
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions("env")
|
||||
|
||||
sourceSets {
|
||||
publish {
|
||||
java.srcDirs = ['src/main/java']
|
||||
java.srcDirs = ['src/main/java', "src/default/java"]
|
||||
}
|
||||
internal {
|
||||
java.srcDirs = ['src/main/java']
|
||||
java.srcDirs = ['src/main/java', "src/default/java"]
|
||||
}
|
||||
tea {
|
||||
java.srcDirs = ['src/main/java', 'src/tea/java']
|
||||
}
|
||||
gdt {
|
||||
java.srcDirs = ['src/main/java', 'src/gdt/java']
|
||||
}
|
||||
}
|
||||
|
||||
productFlavors {
|
||||
// publish release host
|
||||
publish {
|
||||
dimension "env"
|
||||
buildConfigField "String", "API_HOST", "\"${API_HOST}\""
|
||||
|
||||
buildConfigField "String", "SENSITIVE_API_HOST", "\"${SENSITIVE_API_HOST}\""
|
||||
|
||||
buildConfigField "String", "UMENG_APPKEY", "\"${UMENG_APPKEY}\""
|
||||
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\""
|
||||
buildConfigField "String", "BUGLY_APPID", "\"${BUGLY_APPID}\""
|
||||
}
|
||||
// internal test dev host
|
||||
internal {
|
||||
dimension "env"
|
||||
versionNameSuffix "-debug"
|
||||
|
||||
buildConfigField "String", "API_HOST", "\"${DEV_API_HOST}\""
|
||||
buildConfigField "String", "DEV_API_HOST", "\"${DEV_API_HOST}\""
|
||||
buildConfigField "String", "NEW_DEV_API_HOST", "\"${NEW_DEV_API_HOST}\""
|
||||
buildConfigField "String", "DEV_VAPI_HOST", "\"${DEV_VAPI_HOST}\""
|
||||
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${DEV_QUICK_LOGIN_APPID}\""
|
||||
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${DEV_QUICK_LOGIN_APPKEY}\""
|
||||
}
|
||||
|
||||
buildConfigField "String", "SENSITIVE_API_HOST", "\"${DEV_API_HOST}\""
|
||||
// publish release host
|
||||
publish {
|
||||
dimension "env"
|
||||
|
||||
buildConfigField "String", "UMENG_APPKEY", "\"${DEV_UMENG_APPKEY}\""
|
||||
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${DEV_UMENG_MESSAGE_SECRET}\""
|
||||
buildConfigField "String", "BUGLY_APPID", "\"${DEV_BUGLY_APPID}\""
|
||||
buildConfigField "String", "DEV_API_HOST", "\"${API_HOST}\""
|
||||
buildConfigField "String", "NEW_DEV_API_HOST", "\"${NEW_API_HOST}\""
|
||||
buildConfigField "String", "DEV_VAPI_HOST", "\"${VAPI_HOST}\""
|
||||
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${QUICK_LOGIN_APPID}\""
|
||||
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${QUICK_LOGIN_APPKEY}\""
|
||||
}
|
||||
|
||||
tea {
|
||||
dimension "env"
|
||||
|
||||
buildConfigField "String", "API_HOST", "\"${API_HOST}\""
|
||||
|
||||
buildConfigField "String", "SENSITIVE_API_HOST", "\"${SENSITIVE_API_HOST}\""
|
||||
|
||||
buildConfigField "String", "UMENG_APPKEY", "\"${UMENG_APPKEY}\""
|
||||
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\""
|
||||
buildConfigField "String", "BUGLY_APPID", "\"${BUGLY_APPID}\""
|
||||
buildConfigField "String", "DEV_API_HOST", "\"${API_HOST}\""
|
||||
buildConfigField "String", "NEW_DEV_API_HOST", "\"${NEW_API_HOST}\""
|
||||
buildConfigField "String", "DEV_VAPI_HOST", "\"${VAPI_HOST}\""
|
||||
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${QUICK_LOGIN_APPID}\""
|
||||
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${QUICK_LOGIN_APPKEY}\""
|
||||
|
||||
manifestPlaceholders.put("APPLOG_SCHEME", "rangersapplog.byAx6uYt".toLowerCase())
|
||||
}
|
||||
|
||||
gdt {
|
||||
dimension "env"
|
||||
|
||||
buildConfigField "String", "API_HOST", "\"${API_HOST}\""
|
||||
|
||||
buildConfigField "String", "SENSITIVE_API_HOST", "\"${SENSITIVE_API_HOST}\""
|
||||
|
||||
buildConfigField "String", "UMENG_APPKEY", "\"${UMENG_APPKEY}\""
|
||||
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\""
|
||||
buildConfigField "String", "BUGLY_APPID", "\"${BUGLY_APPID}\""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -211,148 +193,85 @@ repositories {
|
||||
dependencies {
|
||||
|
||||
implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
|
||||
gdtImplementation fileTree(include: ['*.jar', '*.aar'], dir: 'src/gdt/libs')
|
||||
|
||||
teaImplementation fileTree(include: ['*.jar', '*.aar'], dir: 'src/tea/libs')
|
||||
testImplementation 'junit:junit:4.12'
|
||||
|
||||
debugImplementation "com.squareup.leakcanary:leakcanary-android:${leakcanary}"
|
||||
debugImplementation "com.facebook.stetho:stetho:${stetho}"
|
||||
debugImplementation "com.facebook.stetho:stetho-okhttp3:${stetho}"
|
||||
debugImplementation "com.squareup.okhttp3:logging-interceptor:${okHttp}"
|
||||
debugImplementation "com.gu.android:toolargetool:${toolargetool}"
|
||||
debugImplementation "com.github.nichbar:WhatTheStack:$whatTheStack"
|
||||
debugImplementation "com.squareup.leakcanary:leakcanary-android-process:${leakcanary}"
|
||||
|
||||
// debugImplementation "com.gu.android:toolargetool:${toolargetool}" // 需要使用调试时才启用
|
||||
debugImplementation "com.github.nichbar:WhatTheStack:${whatTheStack}"
|
||||
debugImplementation "io.github.didi.dokit:dokitx:${dokit}"
|
||||
|
||||
|
||||
implementation "androidx.core:core-ktx:${core}"
|
||||
implementation "androidx.fragment:fragment-ktx:${fragment}"
|
||||
implementation "androidx.multidex:multidex:${multiDex}"
|
||||
implementation "androidx.appcompat:appcompat:${appCompat}"
|
||||
implementation "androidx.cardview:cardview:${cardView}"
|
||||
implementation "androidx.fragment:fragment-ktx:${fragment}"
|
||||
|
||||
implementation "androidx.annotation:annotation:${annotation}"
|
||||
implementation "androidx.constraintlayout:constraintlayout:${constraintLayout}"
|
||||
implementation "androidx.recyclerview:recyclerview:${recyclerView}"
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifeCycle"
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifeCycle"
|
||||
implementation "androidx.lifecycle:lifecycle-common-java8:$lifeCycle"
|
||||
implementation "androidx.room:room-runtime:${room}"
|
||||
implementation "androidx.room:room-rxjava2:${room}"
|
||||
implementation "androidx.core:core-ktx:${ktx}"
|
||||
|
||||
implementation "androidx.viewpager2:viewpager2:${viewpager2}"
|
||||
kapt "androidx.room:room-compiler:${room}"
|
||||
|
||||
implementation "com.google.android.material:material:${material}"
|
||||
|
||||
implementation "com.kyleduo.switchbutton:library:${switchButton}"
|
||||
|
||||
implementation "com.facebook.fresco:fresco:${fresco}"
|
||||
implementation "com.facebook.fresco:animated-gif-lite:${fresco}"
|
||||
implementation "com.facebook.fresco:animated-drawable:${fresco}"
|
||||
implementation "com.facebook.fresco:animated-webp:${fresco}"
|
||||
implementation "com.facebook.fresco:webpsupport:${fresco}"
|
||||
|
||||
implementation "com.squareup.okhttp3:okhttp:${okHttp}"
|
||||
|
||||
implementation "com.leon.channel:helper:${apkChannelPackage}"
|
||||
|
||||
implementation "com.squareup.retrofit2:retrofit:${retrofit}"
|
||||
implementation "com.squareup.retrofit2:converter-gson:${retrofit}" // include gson 2.7
|
||||
implementation "com.squareup.retrofit2:adapter-rxjava2:${retrofit}"
|
||||
|
||||
implementation "com.j256.ormlite:ormlite-android:${ormlite}"
|
||||
implementation "com.j256.ormlite:ormlite-core:${ormlite}"
|
||||
|
||||
implementation "com.jakewharton:butterknife:${butterKnife}"
|
||||
kapt "com.jakewharton:butterknife-compiler:${butterKnife}"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:${kotlin_version}"
|
||||
|
||||
implementation "org.greenrobot:eventbus:${eventbus}"
|
||||
kapt "org.greenrobot:eventbus-annotation-processor:${eventbusApt}"
|
||||
|
||||
implementation "io.reactivex.rxjava2:rxjava:${rxJava2}"
|
||||
implementation "io.reactivex.rxjava2:rxandroid:${rxAndroid2}"
|
||||
implementation "com.jakewharton.rxbinding2:rxbinding:${rxBinding2}"
|
||||
|
||||
implementation "com.google.zxing:core:${zxing}"
|
||||
implementation "com.google.zxing:android-core:${zxing}"
|
||||
|
||||
implementation "com.daimajia.swipelayout:library:${swipeLayout}"
|
||||
|
||||
implementation "com.sina.weibo.sdk:core:${weiboSDK}"
|
||||
|
||||
// bugly with tinker support
|
||||
// implementation "com.tencent.bugly:crashreport_upgrade:${buglyTinkerSupport}"
|
||||
|
||||
implementation "com.google.android:flexbox:${flexbox}"
|
||||
|
||||
implementation "pub.devrel:easypermissions:${easypermissions}"
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
|
||||
implementation "com.contrarywind:Android-PickerView:${pickerView}"
|
||||
|
||||
implementation "com.scwang.smartrefresh:SmartRefreshLayout:${smartRefreshLayout}"
|
||||
implementation "net.cachapa.expandablelayout:expandablelayout:${expandableLayout}"
|
||||
|
||||
// 用于比较 versionName 是大于小于或等于
|
||||
implementation "com.g00fy2:versioncompare:${versioncompare}"
|
||||
|
||||
implementation "top.zibin:Luban:${luban}"
|
||||
|
||||
implementation "com.squareup.picasso:picasso:${picasso}"
|
||||
|
||||
// for video streaming
|
||||
implementation("com.shuyu:gsyVideoPlayer-java:$gsyVideo", {
|
||||
implementation("com.github.CarGuo.GSYVideoPlayer:gsyVideoPlayer-java:$gsyVideo", {
|
||||
exclude module: "gsyvideoplayer-androidvideocache"
|
||||
exclude group: "tv.danmaku.ijk.media"
|
||||
})
|
||||
implementation "com.shuyu:GSYVideoPlayer-exo2:$gsyVideo"
|
||||
implementation "com.github.CarGuo.GSYVideoPlayer:gsyVideoPlayer-exo_player2:$gsyVideo"
|
||||
|
||||
implementation "android.arch.work:work-runtime:${workManager}"
|
||||
// implementation "androidx.work:work-runtime:${workManager}"
|
||||
|
||||
implementation "com.llew.huawei:verifier:${verifier}"
|
||||
|
||||
implementation "com.github.tbruyelle:rxpermissions:${rxPermissions}"
|
||||
|
||||
implementation "com.ethanhua:skeleton:${skeleton}"
|
||||
implementation "io.supercharge:shimmerlayout:${shimmerlayout}"
|
||||
implementation "com.tencent.mm.opensdk:wechat-sdk-android-without-mta:${mta}"
|
||||
implementation "com.github.nichbar:AndroidRomChecker:${romChecker}"
|
||||
|
||||
debugImplementation "com.github.nichbar.chucker:library:$chucker"
|
||||
releaseImplementation "com.github.nichbar.chucker:library-no-op:$chucker"
|
||||
teaImplementation "com.bytedance.applog:RangersAppLog-Lite-cn:$bytedanceApplog"
|
||||
// implementation "com.bytedance.ies.ugc.aweme:opensdk-china-external:$bytedanceAweme"
|
||||
// implementation "com.bytedance.ies.ugc.aweme:opensdk-common:$bytedanceAweme"
|
||||
|
||||
implementation "com.aliyun.dpa:oss-android-sdk:${oss}"
|
||||
|
||||
implementation "com.airbnb.android:lottie:$lottie"
|
||||
teaImplementation "com.bytedance.applog:RangersAppLog-Lite-cn:${bytedanceApplog}"
|
||||
|
||||
implementation "net.lingala.zip4j:zip4j:${zip4j}"
|
||||
|
||||
// plugin 需要字符串,故不能用值
|
||||
implementation "io.sentry:sentry-android:3.2.0"
|
||||
implementation "com.github.hsiafan:apk-parser:${apkParser}"
|
||||
implementation "org.nanohttpd:nanohttpd:${nanohttpd}"
|
||||
|
||||
implementation("com.github.piasy:BigImageViewer:$bigImageViewer", {
|
||||
exclude group: 'com.squareup.okhttp3'
|
||||
implementation "com.lg:easyfloat:${easyFloat}"
|
||||
|
||||
implementation "io.github.florent37:shapeofview:${shapeOfView}"
|
||||
|
||||
implementation "com.lg:apksig:${apksig}"
|
||||
|
||||
implementation "com.lg:gid:${gid}"
|
||||
|
||||
compileOnly "com.github.axen1314.lancet:lancet-base:${lancet_version}"
|
||||
kapt "com.alibaba:arouter-compiler:$arouterVersion"
|
||||
|
||||
implementation project(':vspace-bridge:vspace')
|
||||
|
||||
implementation (project(':module_common')) {
|
||||
exclude group: 'androidx.swiperefreshlayout'
|
||||
exclude group: 'com.github.bumptech.glide'
|
||||
exclude group: 'com.facebook.fresco'
|
||||
})
|
||||
implementation "com.github.PhilJay:MPAndroidChart:${chart}"
|
||||
|
||||
implementation "com.github.hsiafan:apk-parser:$apkParser"
|
||||
implementation "org.nanohttpd:nanohttpd:$nanohttpd"
|
||||
|
||||
implementation "com.aliyun.openservices:aliyun-log-android-sdk:$aliyunLog"
|
||||
|
||||
implementation project(':libraries:LGLibrary')
|
||||
// implementation project(':libraries:MTA')
|
||||
implementation project(':libraries:QQShare')
|
||||
// implementation project(':libraries:TalkingData')
|
||||
// implementation project(':libraries:UmengPush')
|
||||
// implementation project(':libraries:WechatShare')
|
||||
// implementation project(':libraries:im')
|
||||
implementation project(':libraries:Matisse')
|
||||
}
|
||||
implementation(project(':module_login')) {
|
||||
exclude group: 'androidx.swiperefreshlayout'
|
||||
}
|
||||
// 默认不接入光能模块,提高编译速度
|
||||
// debugImplementation(project(':module_energy')) {
|
||||
// exclude group: 'androidx.swiperefreshlayout'
|
||||
// }
|
||||
}
|
||||
File propFile = file('sign.properties')
|
||||
if (propFile.exists()) {
|
||||
@ -423,6 +342,8 @@ andResGuard {
|
||||
mergeDuplicatedRes = true
|
||||
whiteList = [
|
||||
"R.drawable.icon",
|
||||
"R.drawable.ic_bar_back",
|
||||
"R.drawable.toolbar_search_icon",
|
||||
"R.drawable.bg_notification_answer_style_1",
|
||||
"R.drawable.bg_notification_answer_style_2",
|
||||
"R.drawable.bg_notification_article_style_1",
|
||||
@ -441,31 +362,58 @@ andResGuard {
|
||||
"R.drawable.bg_notification_reserve_game_style_2",
|
||||
"R.drawable.bg_notification_video_style_1",
|
||||
"R.drawable.bg_notification_video_style_2",
|
||||
"R.drawable.ic_search_no_1",
|
||||
"R.drawable.ic_search_no_2",
|
||||
"R.drawable.ic_search_no_3",
|
||||
"R.drawable.ic_search_no_4",
|
||||
"R.drawable.ic_search_no_5",
|
||||
"R.drawable.ic_search_no_6",
|
||||
"R.drawable.ic_search_no_7",
|
||||
"R.drawable.ic_search_no_8",
|
||||
"R.drawable.ic_search_no_9",
|
||||
"R.drawable.ic_search_no_10",
|
||||
"R.drawable.ic_search_no_11",
|
||||
"R.drawable.ic_search_no_12",
|
||||
"R.drawable.ic_search_no_13",
|
||||
"R.drawable.ic_search_no_14",
|
||||
"R.drawable.ic_search_no_15",
|
||||
"R.drawable.ic_search_no_16",
|
||||
"R.drawable.ic_search_no_17",
|
||||
"R.drawable.ic_search_no_18",
|
||||
"R.drawable.ic_search_no_19",
|
||||
"R.drawable.ic_search_no_20",
|
||||
"R.drawable.login_btn_bg",
|
||||
"R.drawable.ic_quick_login_check",
|
||||
"R.drawable.ic_quick_login_uncheck",
|
||||
"R.anim.anim_auth_in",
|
||||
"R.anim.anim_auth_out",
|
||||
"R.drawable.ic_recommend_activity",
|
||||
"R.drawable.ic_recommend_discount",
|
||||
"R.drawable.ic_recommend_function",
|
||||
"R.drawable.ic_recommend_gift",
|
||||
"R.drawable.ic_recommend_role",
|
||||
"R.drawable.download_button_normal_style",
|
||||
"R.drawable.ic_selector_selected",
|
||||
"R.drawable.ic_selector_default",
|
||||
"R.id.download_speed",
|
||||
"R.id.download_percentage",
|
||||
"R.id.comment",
|
||||
"R.id.vote",
|
||||
"R.id.watermark_hint",
|
||||
"R.id.watermark_sb",
|
||||
"R.id.bottomShareIv",
|
||||
"R.id.bottomShareTv",
|
||||
"R.id.recommendStarPref",
|
||||
"R.id.recommendStar",
|
||||
"R.id.iv_vmode_badge",
|
||||
"R.id.tv_vmode",
|
||||
"R.id.iv_vmode",
|
||||
"R.drawable.help_search_delete",
|
||||
"R.drawable.suggest_type_normal",
|
||||
"R.drawable.suggest_type_crash",
|
||||
"R.drawable.suggest_type_game_question",
|
||||
"R.drawable.suggest_type_game_collect",
|
||||
"R.drawable.suggest_type_function_suggest",
|
||||
"R.drawable.suggest_type_article_collect",
|
||||
"R.drawable.suggest_type_copyright",
|
||||
"R.drawable.help_result_empty",
|
||||
"R.drawable.news_comment_detail_read",
|
||||
"R.drawable.news_comment_detail_comment",
|
||||
"R.drawable.news_comment_detail_share",
|
||||
"R.drawable.ic_libao",
|
||||
"R.drawable.ic_link",
|
||||
"R.drawable.concern_message_icon",
|
||||
"R.drawable.reuse_blank_hint",
|
||||
"R.drawable.ic_concern",
|
||||
"R.drawable.concern_down",
|
||||
"R.drawable.concern_up",
|
||||
"R.drawable.ic_libao_more",
|
||||
"R.drawable.ic_libao_delete",
|
||||
"R.drawable.ic_dialog_close",
|
||||
"R.drawable.occupy2",
|
||||
"R.drawable.kc_checkbox_unselect",
|
||||
"R.drawable.kc_checkbox_select",
|
||||
"R.drawable.ic_type_unselect",
|
||||
"R.drawable.ic_type_selected",
|
||||
"R.drawable.suggest_add_pic_icon",
|
||||
"R.drawable.icon_pic_add",
|
||||
"R.drawable.ask_search_input_delete",
|
||||
"R.drawable.suggest_pic_delete"
|
||||
]
|
||||
compressFilePattern = [
|
||||
"*.png",
|
||||
|
||||
Binary file not shown.
Binary file not shown.
BIN
app/libs/quick_login_android_5.9.4.aar
Executable file
BIN
app/libs/quick_login_android_5.9.4.aar
Executable file
Binary file not shown.
@ -1,271 +0,0 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in C:\Android\sdk/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
#--------- remove logs start ----------------
|
||||
-assumenosideeffects class com.lightgame.config.CommonDebug {
|
||||
private static String getLogTag(...);
|
||||
private static String getMethodName();
|
||||
public static void logMethodName(...);
|
||||
public static void logParams(...);
|
||||
public static void logFields(...);
|
||||
public static void logMethodWithParams(...);
|
||||
}
|
||||
#-assumenosideeffects class com.lightgame.config.CommonDebug {*;}
|
||||
|
||||
#-dontoptimize
|
||||
#--------- remove logs end ----------------
|
||||
|
||||
-keepattributes *Annotation*,Signature,InnerClasses,EnclosingMethod
|
||||
-dontwarn InnerClasses
|
||||
|
||||
# OrmLite uses reflection
|
||||
-keep class com.j256.**
|
||||
-keepclassmembers class com.j256.** { *; }
|
||||
-keep enum com.j256.**
|
||||
-keepclassmembers enum com.j256.** { *; }
|
||||
-keep interface com.j256.**
|
||||
-keepclassmembers interface com.j256.** { *; }
|
||||
-dontwarn com.j256.**
|
||||
|
||||
#okhttp3
|
||||
-dontwarn com.squareup.okhttp3.**
|
||||
-dontwarn okio.**
|
||||
-keep class com.squareup.okhttp3.** { *;}
|
||||
|
||||
# stetho
|
||||
-keep class com.facebook.stetho.** { *; }
|
||||
-dontwarn com.facebook.stetho.**
|
||||
|
||||
# Retrofit 2.2
|
||||
# Platform calls Class.forName on types which do not exist on Android to determine platform.
|
||||
-dontnote retrofit2.Platform
|
||||
# Platform used when running on Java 8 VMs. Will not be used at runtime.
|
||||
-dontwarn retrofit2.Platform$Java8
|
||||
# Retain generic type information for use by reflection by converters and adapters.
|
||||
-keepattributes Signature
|
||||
# Retain declared checked exceptions for use by a Proxy instance.
|
||||
-keepattributes Exceptions
|
||||
|
||||
# Retrofit 2.X
|
||||
## https://square.github.io/retrofit/ ##
|
||||
|
||||
-dontwarn retrofit2.**
|
||||
-keep class retrofit2.** { *; }
|
||||
-keepattributes Signature
|
||||
-keepattributes Exceptions
|
||||
|
||||
-keepclasseswithmembers class * {
|
||||
@retrofit2.http.* <methods>;
|
||||
}
|
||||
|
||||
|
||||
# rxjava
|
||||
-keep class rx.schedulers.Schedulers {
|
||||
public static <methods>;
|
||||
}
|
||||
-keep class rx.schedulers.ImmediateScheduler {
|
||||
public <methods>;
|
||||
}
|
||||
-keep class rx.schedulers.TestScheduler {
|
||||
public <methods>;
|
||||
}
|
||||
-keep class rx.schedulers.Schedulers {
|
||||
public static ** test();
|
||||
}
|
||||
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
|
||||
long producerIndex;
|
||||
long consumerIndex;
|
||||
}
|
||||
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
|
||||
long producerNode;
|
||||
long consumerNode;
|
||||
}
|
||||
-dontwarn rx.internal.util.**
|
||||
|
||||
## AutoScrollViewPager
|
||||
-keep class cn.trinea.android.** { *; }
|
||||
-keepclassmembers class cn.trinea.android.** { *; }
|
||||
-dontwarn cn.trinea.android.**
|
||||
|
||||
## butterknife
|
||||
# Retain generated class which implement Unbinder.
|
||||
#-keep public class * implements butterknife.Unbinder { public <init>(**, android.view.View); }
|
||||
#
|
||||
## Prevent obfuscation of types which use ButterKnife annotations since the simple name
|
||||
## is used to reflectively look up the generated ViewBinding.
|
||||
#-keep class butterknife.*
|
||||
#-keepclasseswithmembernames class * { @butterknife.* <methods>; }
|
||||
#-keepclasseswithmembernames class * { @butterknife.* <fields>; }
|
||||
|
||||
-dontwarn butterknife.internal.**
|
||||
-keep class **$$ViewInjector { *; }
|
||||
-keepnames class * { @butterknife.InjectView *;}
|
||||
-dontwarn butterknife.Views$InjectViewProcessor
|
||||
-dontwarn com.gc.materialdesign.views.**
|
||||
|
||||
# eventbus
|
||||
-keepattributes *Annotation*
|
||||
-keepclassmembers class ** {
|
||||
@org.greenrobot.eventbus.Subscribe <methods>;
|
||||
}
|
||||
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
|
||||
|
||||
# Only required if you use AsyncExecutor
|
||||
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
|
||||
<init>(java.lang.Throwable);
|
||||
}
|
||||
|
||||
# weiboSdk
|
||||
-keep class com.sina.weibo.sdk.** { *; }
|
||||
-dontwarn android.webkit.WebView
|
||||
-dontwarn android.webkit.WebViewClient
|
||||
|
||||
# app models
|
||||
-keep class com.gh.common.view.** {*;}
|
||||
-keep class com.gh.gamecenter.db.info.** {*;}
|
||||
-keep class com.gh.gamecenter.entity.** {*;}
|
||||
-keep class com.gh.gamecenter.qa.entity.** {*;}
|
||||
-keep class com.gh.gamecenter.retrofit.** {*;}
|
||||
-keep class com.gh.gamecenter.eventbus.** {*;}
|
||||
-keep class com.gh.gamecenter.video.detail.** {*;}
|
||||
-keep class * extends rx.Subscriber
|
||||
|
||||
#---------------------------------webview------------------------------------
|
||||
-keepclassmembers class * extends android.webkit.WebViewClient {
|
||||
public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
|
||||
public boolean *(android.webkit.WebView, java.lang.String);
|
||||
}
|
||||
-keepclassmembers class * extends android.webkit.WebViewClient {
|
||||
public void *(android.webkit.WebView, java.lang.String);
|
||||
}
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
|
||||
##---------------Begin: proguard configuration for Gson ----------
|
||||
# Gson uses generic type information stored in a class file when working with fields. Proguard
|
||||
# removes such information by default, so configure it to keep all of it.
|
||||
-keepattributes Signature
|
||||
|
||||
# For using GSON @Expose annotation
|
||||
-keepattributes *Annotation*
|
||||
|
||||
# Gson specific classes
|
||||
-keep class sun.misc.Unsafe { *; }
|
||||
#-keep class com.google.gson.stream.** { *; }
|
||||
|
||||
# Prevent proguard from stripping interface information from TypeAdapterFactory,
|
||||
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
|
||||
-keep class * implements com.google.gson.TypeAdapterFactory
|
||||
-keep class * implements com.google.gson.JsonSerializer
|
||||
-keep class * implements com.google.gson.JsonDeserializer
|
||||
|
||||
-keepclassmembers enum * { *; }
|
||||
|
||||
##---------------End: proguard configuration for Gson ----------
|
||||
|
||||
# ------ bugly ---------
|
||||
-dontwarn com.tencent.bugly.**
|
||||
-keep public class com.tencent.bugly.**{*;}
|
||||
|
||||
# easypermission
|
||||
-keepclassmembers class * {
|
||||
@pub.devrel.easypermissions.AfterPermissionGranted <methods>;
|
||||
}
|
||||
|
||||
# 重命名文件为SourceFile,再配合mapping符号表,可以拿到真实的类名
|
||||
-renamesourcefileattribute SourceFile
|
||||
# 保留源文件行号
|
||||
-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
-ignorewarnings
|
||||
|
||||
-keep @androidx.annotation.Keep class *
|
||||
-keepclassmembers class ** {
|
||||
@androidx.annotation.Keep *;
|
||||
}
|
||||
|
||||
-keep class com.gh.loghub.** { *; }
|
||||
|
||||
### greenDAO 3
|
||||
-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
|
||||
public static java.lang.String TABLENAME;
|
||||
}
|
||||
-keep class **$Properties
|
||||
-keep class org.greenrobot.greendao.** { *; }
|
||||
# If you do not use SQLCipher:
|
||||
-dontwarn org.greenrobot.greendao.database.**
|
||||
# If you do not use RxJava:
|
||||
-dontwarn rx.**
|
||||
-dontwarn org.greenrobot.greendao.rx.**
|
||||
-dontwarn org.greenrobot.greendao.**
|
||||
|
||||
### fastJson
|
||||
-dontwarn com.alibaba.fastjson.**
|
||||
-keep class com.alibaba.fastjson.** { *; }
|
||||
-keepattributes Signature
|
||||
-keepattributes Annotation
|
||||
|
||||
### 广点通
|
||||
-dontwarn com.qq.gdt.action.**
|
||||
-keep class com.qq.gdt.action.** {*;}
|
||||
|
||||
### AndroidX
|
||||
-keep class androidx.core.app.CoreComponentFactory { *; }
|
||||
|
||||
#阿里云上传
|
||||
-keep class com.alibaba.sdk.android.oss.** { *; }
|
||||
-dontwarn okio.**
|
||||
-dontwarn org.apache.commons.codec.binary.**
|
||||
|
||||
#视频相关
|
||||
-keep class com.shuyu.gsyvideoplayer.video.** { *; }
|
||||
-dontwarn com.shuyu.gsyvideoplayer.video.**
|
||||
-keep class com.shuyu.gsyvideoplayer.video.base.** { *; }
|
||||
-dontwarn com.shuyu.gsyvideoplayer.video.base.**
|
||||
-keep class com.shuyu.gsyvideoplayer.utils.** { *; }
|
||||
-dontwarn com.shuyu.gsyvideoplayer.utils.**
|
||||
-keep class tv.danmaku.ijk.** { *; }
|
||||
-dontwarn tv.danmaku.ijk.**
|
||||
-keep public class * extends android.view.View{
|
||||
*** get*();
|
||||
void set*(***);
|
||||
public <init>(android.content.Context);
|
||||
public <init>(android.content.Context, android.util.AttributeSet);
|
||||
public <init>(android.content.Context, android.util.AttributeSet, int);
|
||||
}
|
||||
|
||||
#穿山甲
|
||||
-keep class com.bytedance.sdk.openadsdk.** { *; }
|
||||
-keep public interface com.bytedance.sdk.openadsdk.downloadnew.** {*;}
|
||||
-keep class com.pgl.sys.ces.* {*;}
|
||||
|
||||
-keep class com.gyf.immersionbar.* {*;}
|
||||
-dontwarn com.gyf.immersionbar.**
|
||||
|
||||
-keep class com.taobao.securityjni.**{*;}
|
||||
-keep class com.taobao.wireless.security.**{*;}
|
||||
-keep class com.ut.secbody.**{*;}
|
||||
-keep class com.taobao.dp.**{*;}
|
||||
-keep class com.alibaba.wireless.security.**{*;}
|
||||
|
||||
-keep class com.alibaba.sdk.android.**{*;}
|
||||
-keep class com.ut.**{*;}
|
||||
-keep class com.ta.**{*;}
|
||||
|
||||
-keep class com.gh.gamecenter.GdtHelper { *; }
|
||||
-keep class com.gh.gamecenter.TeaHelper { *; }
|
||||
@ -1,18 +1,6 @@
|
||||
|
||||
#--------- remove logs start ----------------
|
||||
-assumenosideeffects class com.lightgame.config.CommonDebug {
|
||||
private static String getLogTag(...);
|
||||
private static String getMethodName();
|
||||
public static void logMethodName(...);
|
||||
public static void logParams(...);
|
||||
public static void logFields(...);
|
||||
public static void logMethodWithParams(...);
|
||||
}
|
||||
|
||||
-assumenosideeffects class com.lightgame.utils.Utils {
|
||||
public static void log(...);
|
||||
}
|
||||
#--------- remove logs end ----------------
|
||||
# inline getter method
|
||||
-allowaccessmodification
|
||||
|
||||
# TODO Dicard sourceFile in final release build but remain in internal build.
|
||||
-renamesourcefileattribute SourceFile
|
||||
@ -28,37 +16,6 @@
|
||||
-keepclassmembers interface com.j256.* { *; }
|
||||
-dontwarn com.j256.**
|
||||
|
||||
### AutoScrollViewPager
|
||||
-keep class cn.trinea.android.* { *; }
|
||||
-keepclassmembers class cn.trinea.android.* { *; }
|
||||
-dontwarn cn.trinea.android.**
|
||||
|
||||
### Butterknife
|
||||
-keep public class * implements butterknife.Unbinder { public <init>(**, android.view.View); }
|
||||
-keep class butterknife.*
|
||||
-keepclasseswithmembernames class * { @butterknife.* <methods>; }
|
||||
-keepclasseswithmembernames class * { @butterknife.* <fields>; }
|
||||
|
||||
### eventbus
|
||||
-keepclassmembers class * {
|
||||
@org.greenrobot.eventbus.Subscribe <methods>;
|
||||
}
|
||||
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
|
||||
|
||||
### Only required if you use AsyncExecutor
|
||||
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
|
||||
<init>(java.lang.Throwable);
|
||||
}
|
||||
|
||||
### weiboSdk
|
||||
-keep class com.sina.weibo.sdk.* { *; }
|
||||
-dontwarn android.webkit.WebView
|
||||
-dontwarn android.webkit.WebViewClient
|
||||
|
||||
### wechatSdk
|
||||
### TODO 这里用 com.tencent.*{*;} 不起效?但其它地方可以?
|
||||
-keep class com.tencent.**{*;}
|
||||
|
||||
### app models
|
||||
-keep class com.gh.common.view.* {*;}
|
||||
-keep class com.gh.gamecenter.db.info.* {*;}
|
||||
@ -67,39 +24,12 @@
|
||||
-keep class com.gh.gamecenter.retrofit.* {*;}
|
||||
-keep class com.gh.gamecenter.eventbus.* {*;}
|
||||
-keep class com.gh.gamecenter.video.detail.* {*;}
|
||||
-keep class com.gh.gamecenter.home.gamecollection.* {*;}
|
||||
|
||||
###
|
||||
-keepclassmembers class * extends android.webkit.WebViewClient {
|
||||
public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
|
||||
public boolean *(android.webkit.WebView, java.lang.String);
|
||||
}
|
||||
-keepclassmembers class * extends android.webkit.WebViewClient {
|
||||
public void *(android.webkit.WebView, java.lang.String);
|
||||
}
|
||||
|
||||
### easypermission
|
||||
-keepclassmembers class * {
|
||||
@pub.devrel.easypermissions.AfterPermissionGranted <methods>;
|
||||
}
|
||||
|
||||
# TODO What's this ?
|
||||
-ignorewarnings
|
||||
|
||||
### Keep Annotation
|
||||
-keep @androidx.annotation.Keep class *
|
||||
-keepclassmembers class * {
|
||||
@androidx.annotation.Keep *;
|
||||
}
|
||||
|
||||
### 广点通
|
||||
-dontwarn com.qq.gdt.action.**
|
||||
-keep class com.qq.gdt.action.* {*;}
|
||||
|
||||
### 阿里云上传
|
||||
-keep class com.alibaba.sdk.android.oss.* { *; }
|
||||
-dontwarn okio.**
|
||||
-dontwarn org.apache.commons.codec.binary.**
|
||||
|
||||
### 视频相关
|
||||
-keep class com.shuyu.gsyvideoplayer.video.* { *; }
|
||||
-dontwarn com.shuyu.gsyvideoplayer.video.**
|
||||
@ -117,18 +47,22 @@
|
||||
public <init>(android.content.Context, android.util.AttributeSet, int);
|
||||
}
|
||||
|
||||
-keep class com.alibaba.sdk.android.*{*;}
|
||||
-keep class com.ut.*{*;}
|
||||
-keep class com.ta.*{*;}
|
||||
|
||||
### GDT & TEA
|
||||
-keep class com.gh.gamecenter.GdtHelper { *; }
|
||||
### TEA
|
||||
-keep class com.gh.gamecenter.TeaHelper { *; }
|
||||
|
||||
### 阿里云日志
|
||||
-keep class com.aliyun.sls.android.producer.* { *; }
|
||||
-keep interface com.aliyun.sls.android.producer.* { *; }
|
||||
### EasyFloat
|
||||
-keep class com.lzf.easyfloat.* {*;}
|
||||
|
||||
### dokit
|
||||
-keep class com.didichuxing.** {*;}
|
||||
|
||||
# Flutter模块
|
||||
-keep class com.gh.common.util.DirectUtils {
|
||||
public static void directToQa(...);
|
||||
public static void directToQaCollection(...);
|
||||
public static void directToGift(...);
|
||||
public static void directToConcernInfo(...);
|
||||
public static void directToFeedback(...);
|
||||
public static void directToSuggestion(...);
|
||||
}
|
||||
|
||||
### 中国移动一键登录
|
||||
-dontwarn com.cmic.sso.sdk.**
|
||||
-keep class com.cmic.sso.sdk.* { *; }
|
||||
@ -1,38 +0,0 @@
|
||||
package com.gh.gamecenter;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import com.facebook.stetho.Stetho;
|
||||
import com.facebook.stetho.okhttp3.StethoInterceptor;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
|
||||
/**
|
||||
* @author CsHeng
|
||||
* @Date 03/09/2017
|
||||
* @Time 4:34 PM
|
||||
*/
|
||||
|
||||
public class Injection {
|
||||
|
||||
public static boolean appInit(Application application) {
|
||||
// init stetho
|
||||
Stetho.initializeWithDefaults(application);
|
||||
|
||||
// 监控Bundle大小,预防溢出(需要调试的时候再开启吧!)
|
||||
// TooLargeTool.startLogging(application);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static OkHttpClient.Builder provideRetrofitBuilder() {
|
||||
OkHttpClient.Builder builder = new OkHttpClient.Builder();
|
||||
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
|
||||
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
|
||||
builder.addNetworkInterceptor(interceptor);
|
||||
builder.addNetworkInterceptor(new StethoInterceptor());
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package com.gh.gamecenter.provider
|
||||
|
||||
import android.app.Application
|
||||
import android.text.TextUtils
|
||||
import com.gh.gamecenter.common.constant.Config
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.utils.PackageFlavorHelper
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.leon.channel.helper.ChannelReaderUtil
|
||||
|
||||
class ChannelProviderImp : ChannelProvider {
|
||||
override fun getChannelStr(application: Application): String {
|
||||
var channel = ChannelReaderUtil.getChannel(application)
|
||||
if (channel == null || TextUtils.isEmpty(channel.trim())) {
|
||||
channel = if (PackageFlavorHelper.IS_TEST_FLAVOR) {
|
||||
Config.DEFAULT_CHANNEL
|
||||
} else {
|
||||
Config.DEFAULT_CHANNEL_FOR_RELEASE
|
||||
}
|
||||
}
|
||||
if (PackageFlavorHelper.IS_TEST_FLAVOR) {
|
||||
channel = SPUtils.getString(Constants.SP_TEST_FLAVOR_CHANNEL, channel)
|
||||
}
|
||||
return channel
|
||||
}
|
||||
}
|
||||
@ -1,77 +0,0 @@
|
||||
package com.gh.gamecenter
|
||||
|
||||
import android.app.Application
|
||||
import android.text.TextUtils
|
||||
import android.util.Log
|
||||
import com.gh.common.util.ToastUtils
|
||||
import com.lightgame.utils.Utils
|
||||
import com.qq.gdt.action.GDTAction
|
||||
import org.json.JSONObject
|
||||
|
||||
/**
|
||||
* 广点通辅助类 [https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/403]
|
||||
*
|
||||
* 更换帐号 [https://gitlab.ghzs.com/pm/yunying/issues/893]
|
||||
*/
|
||||
object GdtHelper {
|
||||
|
||||
const val NETWORK_TYPE = "NETWORK_TYPE"
|
||||
const val PAGE_TYPE = "PAGE_TYPE"
|
||||
const val CONTENT_TYPE = "CONTENT_TYPE"
|
||||
const val CONTENT_ID = "CONTENT_ID"
|
||||
const val KEYWORD = "KEYWORD"
|
||||
const val GAME_ID = "GAME_ID"
|
||||
const val SCORE = "SCORE"
|
||||
const val PLATFORM = "PLATFORM"
|
||||
|
||||
@JvmStatic
|
||||
fun init(application: Application, channel: String) {
|
||||
if (shouldUseGdtHelper()) {
|
||||
if (channel == "GH_728") {
|
||||
GDTAction.init(application, "1111012969", "9d3d9da5b0948a317c03d08f14d445dc")
|
||||
} else if (channel == "GH_729") {
|
||||
GDTAction.init(application, "1111013063", "f53dabf458a356b101d99fc4069eb7f1")
|
||||
} else if (channel == "GH_765") {
|
||||
GDTAction.init(application, "1111327925", "588d503f0990f98f9b2394fbb795c570")
|
||||
} else {
|
||||
GDTAction.init(application, "1110680399", "f5ddaafbf520d7d7385499232a408d0a")
|
||||
}
|
||||
}
|
||||
Utils.log("init GdtHelper")
|
||||
}
|
||||
|
||||
// fun logAction(type: String) {
|
||||
// if (shouldUseGdtHelper()) {
|
||||
// GDTAction.logAction(type)
|
||||
// Utils.log("GDT", type)
|
||||
// }
|
||||
// }
|
||||
@JvmStatic
|
||||
fun logAction(type: String, vararg kv: String?) {
|
||||
try {
|
||||
val actionParam = JSONObject()
|
||||
for (i in kv.indices) {
|
||||
if (i % 2 != 0) {
|
||||
val key = kv[i - 1]
|
||||
val value = kv[i]
|
||||
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
|
||||
actionParam.put(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
Utils.log("GDT", "$type + [${kv.joinToString(" , ")}]")
|
||||
GDTAction.logAction(type, actionParam)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO 确认开启的渠道条件
|
||||
private fun shouldUseGdtHelper(): Boolean {
|
||||
return true
|
||||
//
|
||||
// val channel = HaloApp.getInstance().channel
|
||||
// return !(TextUtils.isEmpty(channel) || channel.contains("GDT".toLowerCase(Locale.CHINA)))
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
@ -3,6 +3,9 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.gh.gamecenter">
|
||||
|
||||
<queries>
|
||||
<package android:name="com.gh.gamecenter" />
|
||||
</queries>
|
||||
<!-- 允许应用程序访问网络连接 -->
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<!-- 允许应用程序写入外部存储,如SD卡上写文件 -->
|
||||
@ -13,10 +16,6 @@
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<!-- 允许应用程序获取网络信息状态 -->
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<!-- 允许应用程序读取电话状态 -->
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
<!-- 允许应用程序获取当前或最近运行的应用 -->
|
||||
<uses-permission android:name="android.permission.GET_TASKS" />
|
||||
<!-- 允许访问振动设备 -->
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<!-- 允许应用程序改变Wi-Fi连接状态 -->
|
||||
@ -25,18 +24,19 @@
|
||||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
|
||||
<!-- 允许应用程序快捷方式 -->
|
||||
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
|
||||
<!-- 应用安装相关 -->
|
||||
<uses-permission android:name="com.android.permission.GET_INSTALLED_APPS" />
|
||||
|
||||
<!-- 前台服务权限-->
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.PACKAGE_USAGE_STATS"
|
||||
tools:ignore="ProtectedPermissions" />
|
||||
|
||||
<!-- bugly with tinker -->
|
||||
<!-- <uses-permission android:name="android.permission.READ_LOGS" />-->
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
|
||||
<!--可选,穿山甲提供“获取地理位置权限”和“不给予地理位置权限,开发者传入地理位置参数”两种方式上报用户位置,两种方式均可不选,添加位置权限或参数将帮助投放定位广告-->
|
||||
<!--请注意:无论通过何种方式提供给穿山甲用户地理位置,均需向用户声明地理位置权限将应用于穿山甲广告投放,穿山甲不强制获取地理位置信息-->
|
||||
<!--<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />-->
|
||||
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
|
||||
|
||||
<!-- 如果有视频相关的广告且使用textureView播放,请务必添加,否则黑屏 -->
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
@ -47,15 +47,25 @@
|
||||
com.shuyu.gsyvideoplayer.armv7a,
|
||||
com.shuyu.gsyvideoplayer.x86,
|
||||
com.shuyu.gsy.base,
|
||||
shuyu.com.androidvideocache,
|
||||
com.google.android.exoplayer2,
|
||||
tv.danmaku.ijk.media.exo2,
|
||||
pl.droidsonroids.gif" />
|
||||
pl.droidsonroids.gif,
|
||||
com.lzf.easyfloat" />
|
||||
|
||||
<!-- 去掉 SDK 一些流氓权限 -->
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_CONTACTS"
|
||||
tools:node="remove" />
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_PHONE_STATE"
|
||||
tools:node="remove" />
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.GET_TASKS"
|
||||
tools:node="remove" />
|
||||
|
||||
<supports-screens
|
||||
android:anyDensity="true"
|
||||
android:largeScreens="true"
|
||||
@ -72,8 +82,7 @@
|
||||
android:largeHeap="true"
|
||||
android:resizeableActivity="true"
|
||||
android:theme="@style/AppCompatTheme.APP"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
tools:replace="android:allowBackup"
|
||||
tools:replace="android:name,android:allowBackup"
|
||||
tools:targetApi="n">
|
||||
|
||||
<meta-data
|
||||
@ -85,7 +94,6 @@
|
||||
android:name="io.sentry.breadcrumbs.system-events"
|
||||
android:value="false" />
|
||||
|
||||
<!--android:launchMode = "singleTask"-->
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.SplashScreenActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
@ -112,7 +120,6 @@
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<!--android:theme = "@android:style/Theme.Black.NoTitleBar.Fullscreen" 退出时屏幕抖动 -->
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.ImageViewerActivity"
|
||||
android:theme="@style/Theme.Transparent" />
|
||||
@ -170,6 +177,10 @@
|
||||
android:name="com.gh.gamecenter.WebActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.SingletonWebActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.FullScreenWebActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
@ -242,11 +253,6 @@
|
||||
android:screenOrientation="portrait"
|
||||
android:windowSoftInputMode="stateAlwaysHidden|adjustResize" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.ToolBoxActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:windowSoftInputMode="stateHidden" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.WeiBoShareActivity"
|
||||
android:screenOrientation="portrait"
|
||||
@ -260,11 +266,6 @@
|
||||
android:name=".category.CategoryListActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.LoginActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:windowSoftInputMode="stateHidden" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.UserInfoActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
@ -286,22 +287,10 @@
|
||||
android:screenOrientation="portrait"
|
||||
android:windowSoftInputMode="stateHidden" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.search.AskSearchActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.questions.detail.QuestionsDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".qa.answer.fold.AnswerFoldActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.answer.edit.AnswerEditActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
@ -318,14 +307,6 @@
|
||||
android:name="com.gh.gamecenter.MessageKeFuActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.select.CommunitiesSelectActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.subject.CommunitySubjectActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.MessageInviteActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
@ -342,10 +323,6 @@
|
||||
android:name="com.gh.gamecenter.qa.myqa.MyAskActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.column.order.AskTabOrderActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.questions.edit.QuestionEditActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
@ -367,10 +344,6 @@
|
||||
android:name="com.gh.gamecenter.amway.AmwayActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.column.detail.AskColumnDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.NetworkDiagnosisActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
@ -403,10 +376,6 @@
|
||||
android:name="com.gh.gamecenter.qa.article.detail.ArticleDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.article.detail.comment.ArticleDetailCommentActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.draft.CommunityDraftWrapperActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
@ -416,14 +385,6 @@
|
||||
android:screenOrientation="portrait"
|
||||
android:windowSoftInputMode="stateVisible" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.questions.edit.manager.HistoryDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.questions.edit.manager.HistoryActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.editor.InsertAnswerWrapperActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
@ -457,10 +418,6 @@
|
||||
android:name="com.gh.gamecenter.tag.TagsActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.article.SimpleArticleListActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.video.videomanager.VideoManagerActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
@ -475,7 +432,7 @@
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.editor.VideoActivity"
|
||||
android:name="com.gh.gamecenter.qa.editor.LocalMediaActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
@ -509,7 +466,11 @@
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.comment.CommentActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/Theme.Transparent"
|
||||
android:windowSoftInputMode="adjustNothing" />
|
||||
|
||||
<activity
|
||||
android:name=".qa.dialog.ChooseForumActivity"
|
||||
android:theme="@style/Theme.Transparent"
|
||||
android:windowSoftInputMode="adjustNothing" />
|
||||
|
||||
@ -548,14 +509,6 @@
|
||||
android:name=".video.poster.PosterClipActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".forum.select.ForumSelectActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".forum.follow.ForumMyFollowActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".forum.detail.ForumDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
@ -564,6 +517,10 @@
|
||||
android:name=".forum.moderator.ModeratorListActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".forum.moderator.ApplyModeratorActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".video.label.VideoLabelActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
@ -585,10 +542,6 @@
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/TransparentStatusBarAndNavigationBar" />
|
||||
|
||||
<activity
|
||||
android:name=".personalhome.excellentcomments.ExcellentCommentsActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".simulatorgame.SimulatorGameActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
@ -609,19 +562,6 @@
|
||||
android:name=".forum.search.ForumOrUserSearchActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".energy.EnergyCenterActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:launchMode="singleTask" />
|
||||
|
||||
<activity
|
||||
android:name=".energy.EnergyHouseActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".personal.NewPersonalActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".qa.questions.draft.QuestionDraftActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
@ -639,13 +579,56 @@
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.cmic.sso.sdk.activity.LoginAuthActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:theme="@android:style/Theme.Dialog"
|
||||
android:screenOrientation="portrait"
|
||||
android:launchMode="singleTop">
|
||||
</activity>
|
||||
android:name=".qa.editor.PreviewVideoActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".qa.video.publish.VideoPublishActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".setting.GameDownloadSettingActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".setting.VideoSettingActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".qa.video.detail.ForumVideoDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".video.videomanager.VideoDraftActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".qa.questions.newdetail.NewQuestionDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".qa.editor.FullScreenVideoActivity"
|
||||
android:theme="@style/AppFullScreenTheme" />
|
||||
|
||||
<activity
|
||||
android:name=".forum.list.ForumListActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".qa.answer.detail.SimpleAnswerDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".game.commoncollection.detail.CommonCollectionDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".gamecollection.detail.GameCollectionDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".gamecollection.detail.GameCollectionPosterActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".home.skip.PackageSkipActivity"
|
||||
@ -659,6 +642,7 @@
|
||||
<!-- android:theme="@android:style/Theme.Translucent" />-->
|
||||
|
||||
<activity
|
||||
android:exported="true"
|
||||
android:name="com.gh.gamecenter.SkipActivity"
|
||||
android:theme="@style/Theme.AppCompat.Light.Fullscreen.Transparent">
|
||||
<intent-filter>
|
||||
@ -679,12 +663,75 @@
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="${applicationId}.wxapi.WXEntryActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTop"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar"></activity>
|
||||
android:name="com.gh.gamecenter.teenagermode.TeenagerModeActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".gamecollection.publish.GameCollectionEditActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".gamecollection.choose.ChooseGamesActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".gamecollection.choose.AddGamesActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".gamecollection.mine.MyGameCollectionActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.gamecollection.square.GameCollectionSquareActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.gamecollection.tag.GameCollectionTagSelectActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".qa.editor.InsertGameCollectionWrapperActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".qa.editor.InsertVideoWrapperActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.toolbox.ToolBoxBlockActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.vspace.VDownloadManagerActivity"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.vspace.VSpaceLoadingActivity"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.subject.CommunitySubjectActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".qa.comment.NewCommentDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.mypost.MyPostActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".VerifyPhoneActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".BbsCertificationActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<!-- <activity-->
|
||||
<!-- android:name="${applicationId}.douyinapi.DouYinEntryActivity"-->
|
||||
@ -703,9 +750,22 @@
|
||||
</provider>
|
||||
|
||||
<provider
|
||||
android:name="androidx.work.impl.WorkManagerInitializer"
|
||||
android:authorities="${applicationId}.workmanager-init"
|
||||
tools:node="remove" />
|
||||
android:name="com.gh.gamecenter.provider.GhContentProvider"
|
||||
android:authorities="${applicationId}.provider"
|
||||
android:enabled="true"
|
||||
android:exported="true" />
|
||||
|
||||
<!-- <provider-->
|
||||
<!-- android:name="androidx.startup.InitializationProvider"-->
|
||||
<!-- android:authorities="${applicationId}.androidx-startup"-->
|
||||
<!-- android:exported="false"-->
|
||||
<!-- tools:node="merge">-->
|
||||
<!-- <!– If you are using androidx.startup to initialize other components –>-->
|
||||
<!-- <meta-data-->
|
||||
<!-- android:name="androidx.work.WorkManagerInitializer"-->
|
||||
<!-- android:value="androidx.startup"-->
|
||||
<!-- tools:node="remove" />-->
|
||||
<!-- </provider>-->
|
||||
|
||||
<receiver
|
||||
android:name="com.gh.gamecenter.receiver.DownloadReceiver"
|
||||
@ -730,48 +790,6 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<!-- <receiver android:name="com.gh.gamecenter.receiver.UmengMessageReceiver">-->
|
||||
<!-- <intent-filter>-->
|
||||
<!-- <action android:name="com.gh.gamecenter.UMENG" />-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- </receiver>-->
|
||||
|
||||
<!-- <!–魅族push应用定义消息receiver声明 –>-->
|
||||
<!-- <receiver android:name="com.gh.gamecenter.receiver.UmengMeizuPushReceiver">-->
|
||||
<!-- <intent-filter>-->
|
||||
<!-- <!– 接收push消息 –>-->
|
||||
<!-- <action android:name="com.meizu.flyme.push.intent.MESSAGE" />-->
|
||||
<!-- <!– 接收register消息 –>-->
|
||||
<!-- <action android:name="com.meizu.flyme.push.intent.REGISTER.FEEDBACK" />-->
|
||||
<!-- <!– 接收unregister消息–>-->
|
||||
<!-- <action android:name="com.meizu.flyme.push.intent.UNREGISTER.FEEDBACK" />-->
|
||||
<!-- <!– 兼容低版本Flyme3推送服务配置 –>-->
|
||||
<!-- <action android:name="com.meizu.c2dm.intent.REGISTRATION" />-->
|
||||
<!-- <action android:name="com.meizu.c2dm.intent.RECEIVE" />-->
|
||||
|
||||
<!-- <category android:name="${applicationId}" />-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- </receiver>-->
|
||||
|
||||
<!-- <receiver-->
|
||||
<!-- android:name="com.gh.common.im.ImReceiver"-->
|
||||
<!-- android:enabled="true">-->
|
||||
<!-- <intent-filter android:priority="2147483647">-->
|
||||
<!-- <action android:name="com.gh.im" />-->
|
||||
<!-- <action android:name="action_finish" />-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- </receiver>-->
|
||||
|
||||
<!-- <meta-data-->
|
||||
<!-- android:name="com.huawei.hms.client.appid"-->
|
||||
<!-- android:value="@string/huawei_push_appid" />-->
|
||||
|
||||
<!-- <service-->
|
||||
<!-- android:name="com.gh.base.GHUmengNotificationService"-->
|
||||
<!-- android:permission="android.permission.BIND_JOB_SERVICE" />-->
|
||||
|
||||
<!--<service android:name = "com.gh.gamecenter.statistics.AppStaticService" />-->
|
||||
|
||||
<!-- 梦工厂配置 开始 -->
|
||||
<!--<meta-data
|
||||
android:name="MGC_APPID"
|
||||
|
||||
BIN
app/src/main/assets/fonts/d_din_bold.ttf
Normal file
BIN
app/src/main/assets/fonts/d_din_bold.ttf
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
1
app/src/main/assets/lottie/switch_turnoff.json
Normal file
1
app/src/main/assets/lottie/switch_turnoff.json
Normal file
@ -0,0 +1 @@
|
||||
{"v":"5.6.9","fr":60,"ip":0,"op":36,"w":120,"h":66,"nm":"开关动画-关闭","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"按钮手柄","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.667,"y":0},"t":0,"s":[87,33,0],"to":[7.682,0,0],"ti":[-13.443,0,0]},{"i":{"x":0.333,"y":1},"o":{"x":0.333,"y":0},"t":18,"s":[31,33,0],"to":[2.306,0,0],"ti":[-1.318,0,0]},{"t":24,"s":[33,33,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"指示器-on","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[100]},{"t":18,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,33,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":0,"s":[6.5,6.5]},{"t":18,"s":[4.5,4.5]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.966666666667,0.966666666667,0.966666666667,0.420000005762],"ix":3},"o":{"a":0,"k":40,"ix":4},"w":{"a":0,"k":1.5,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"指示器-off","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[87,33,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":0,"s":[1.5,4]},{"t":18,"s":[1.5,6]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0.75,"ix":4},"nm":"矩形路径 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":5,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":90,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[0]},{"t":18,"s":[100]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"按钮背景","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[60,33,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"sy":[{"c":{"a":0,"k":[0,0,0,1],"ix":2},"o":{"a":0,"k":5,"ix":3},"a":{"a":0,"k":120,"ix":5},"s":{"a":0,"k":1,"ix":8},"d":{"a":0,"k":0,"ix":6},"ch":{"a":0,"k":100,"ix":7},"bm":{"a":0,"k":5,"ix":1},"no":{"a":0,"k":0,"ix":9},"ty":2,"nm":"内阴影"}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[40,22],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12,"ix":4},"nm":"矩形路径 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[0.141176477075,0.588235318661,1,1]},{"t":18,"s":[0.933333337307,0.933333337307,0.933333337307,1]}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"filling","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0.118,0.006],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0}],"markers":[]}
|
||||
1
app/src/main/assets/lottie/switch_turnoff_dark.json
Normal file
1
app/src/main/assets/lottie/switch_turnoff_dark.json
Normal file
@ -0,0 +1 @@
|
||||
{"v":"5.9.1","fr":60,"ip":0,"op":36,"w":120,"h":66,"nm":"开关动画-关闭","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"按钮手柄","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.667,"y":0},"t":0,"s":[87,33,0],"to":[7.682,0,0],"ti":[-13.443,0,0]},{"i":{"x":0.333,"y":1},"o":{"x":0.333,"y":0},"t":18,"s":[31,33,0],"to":[2.306,0,0],"ti":[-1.318,0,0]},{"t":24,"s":[33,33,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"指示器-on","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[100]},{"t":18,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":0,"s":[6.5,6.5]},{"t":18,"s":[4.5,4.5]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":40,"ix":4},"w":{"a":0,"k":1.5,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"指示器-off","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[87,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":0,"s":[1.5,4]},{"t":18,"s":[1.5,6]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0.75,"ix":4},"nm":"矩形路径 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":20,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":90,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[0]},{"t":18,"s":[100]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"按钮背景","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[60,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[40,22],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12,"ix":4},"nm":"矩形路径 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[0.156862750649,0.533333361149,0.878431379795,1]},{"t":18,"s":[1,1,1,1]}],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[100]},{"t":18,"s":[8]}],"ix":5},"r":1,"bm":0,"nm":"filling","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0.118,0.006],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0}],"markers":[]}
|
||||
1
app/src/main/assets/lottie/switch_turnoff_light.json
Normal file
1
app/src/main/assets/lottie/switch_turnoff_light.json
Normal file
@ -0,0 +1 @@
|
||||
{"v":"5.9.1","fr":60,"ip":0,"op":36,"w":120,"h":66,"nm":"开关动画-关闭","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"按钮手柄","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.667,"y":0},"t":0,"s":[87,33,0],"to":[7.682,0,0],"ti":[-13.443,0,0]},{"i":{"x":0.333,"y":1},"o":{"x":0.333,"y":0},"t":18,"s":[31,33,0],"to":[2.306,0,0],"ti":[-1.318,0,0]},{"t":24,"s":[33,33,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"指示器-on","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[100]},{"t":18,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":0,"s":[6.5,6.5]},{"t":18,"s":[4.5,4.5]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":40,"ix":4},"w":{"a":0,"k":1.5,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"指示器-off","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[87,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":0,"s":[1.5,4]},{"t":18,"s":[1.5,6]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0.75,"ix":4},"nm":"矩形路径 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":5,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":90,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[0]},{"t":18,"s":[100]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"按钮背景","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[60,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[40,22],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12,"ix":4},"nm":"矩形路径 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[0.141176477075,0.588235318661,1,1]},{"t":18,"s":[0.933333337307,0.933333337307,0.933333337307,1]}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"filling","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0.118,0.006],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0}],"markers":[]}
|
||||
1
app/src/main/assets/lottie/switch_turnon_dark.json
Normal file
1
app/src/main/assets/lottie/switch_turnon_dark.json
Normal file
@ -0,0 +1 @@
|
||||
{"v":"5.9.1","fr":60,"ip":0,"op":36,"w":120,"h":66,"nm":"开关动画-打开","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"按钮手柄","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.667,"y":0},"t":0,"s":[33,33,0],"to":[7.682,0,0],"ti":[-13.443,0,0]},{"i":{"x":0.333,"y":1},"o":{"x":0.333,"y":0},"t":18,"s":[89,33,0],"to":[2.306,0,0],"ti":[-1.318,0,0]},{"t":24,"s":[87,33,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"指示器-on","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[0]},{"t":18,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":0,"s":[4.5,4.5]},{"t":18,"s":[6.5,6.5]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":40,"ix":4},"w":{"a":0,"k":1.5,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"指示器-off","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[87,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":0,"s":[1.5,6]},{"t":18,"s":[1.5,4]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0.75,"ix":4},"nm":"矩形路径 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":20,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":90,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[100]},{"t":18,"s":[0]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"按钮背景","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[60,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[40,22],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12,"ix":4},"nm":"矩形路径 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[1,1,1,1]},{"t":18,"s":[0.156862750649,0.533333361149,0.878431379795,1]}],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[8]},{"t":18,"s":[100]}],"ix":5},"r":1,"bm":0,"nm":"filling","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0.118,0.006],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0}],"markers":[]}
|
||||
1
app/src/main/assets/lottie/switch_turnon_light.json
Normal file
1
app/src/main/assets/lottie/switch_turnon_light.json
Normal file
@ -0,0 +1 @@
|
||||
{"v":"5.9.1","fr":60,"ip":0,"op":36,"w":120,"h":66,"nm":"开关动画-打开","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"按钮手柄","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.667,"y":0},"t":0,"s":[33,33,0],"to":[7.682,0,0],"ti":[-13.443,0,0]},{"i":{"x":0.333,"y":1},"o":{"x":0.333,"y":0},"t":18,"s":[89,33,0],"to":[2.306,0,0],"ti":[-1.318,0,0]},{"t":24,"s":[87,33,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"指示器-on","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[0]},{"t":18,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":0,"s":[4.5,4.5]},{"t":18,"s":[6.5,6.5]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":40,"ix":4},"w":{"a":0,"k":1.5,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"指示器-off","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[87,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":0,"s":[1.5,6]},{"t":18,"s":[1.5,4]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0.75,"ix":4},"nm":"矩形路径 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":5,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":90,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[100]},{"t":18,"s":[0]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"按钮背景","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[60,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[40,22],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12,"ix":4},"nm":"矩形路径 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[0.933332979679,0.933332979679,0.933332979679,1]},{"t":18,"s":[0.141176477075,0.588235318661,1,1]}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"filling","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0.118,0.006],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0}],"markers":[]}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,758 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
||||
<title>隐私政策</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
-webkit-user-select: text;
|
||||
-moz-user-select: text;
|
||||
-ms-user-select: text;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.page {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.date p {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-family: "SourceHanSansSC-regular" !important;
|
||||
color: #101010;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
margin-bottom: 6px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
b {
|
||||
font-weight: 700;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.points {
|
||||
margin: 14px 0;
|
||||
}
|
||||
|
||||
.points p {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.introduce p {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.content p b {
|
||||
margin: 6px 0;
|
||||
display: block;
|
||||
}
|
||||
.link-text {
|
||||
color: rgb(19, 131, 235);
|
||||
cursor: pointer;
|
||||
}
|
||||
.link-text a {
|
||||
color: rgb(19, 131, 235);
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
.left-indent {
|
||||
margin-left: 20px;
|
||||
}
|
||||
.page-title {
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
margin: 20px 0 10px 0;
|
||||
}
|
||||
.red-style {
|
||||
color: red;
|
||||
}
|
||||
.bold-font {
|
||||
font-weight: bold;
|
||||
}
|
||||
span.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
.link-text {
|
||||
color: #005ad0;
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="page">
|
||||
<div class="page-title">欢迎您使用光环助手!</div>
|
||||
|
||||
<div class="introduce">
|
||||
<p>
|
||||
为了向您提供游戏预约、论坛互动交流等相关服务,受制于手机系统限制,我们会申请您的设备信息权限;
|
||||
</p>
|
||||
<p>为了让您正常使用游戏下载和论坛功能,我们会申请您的储存权限;</p>
|
||||
<p>以下为完整《隐私权限政策》</p>
|
||||
<p>
|
||||
光环助手(简称“我们”)深知个人信息对您的重要性,我们将依据《中华人民共和国网络安全法》、《信息安全技术
|
||||
个人信息安全规范》(GB/T
|
||||
35273-2017)以及其他相关法律法规和技术规范收集和使用您的个人信息,以帮助我们向您提供更优质的产品和/或服务,
|
||||
保护您的个人信息及隐私安全。我们制定本“隐私指引”并特别提示:希望您在使用光环助手及相关服务前仔细阅读并理解本隐私政策,以便做出适当的选择。
|
||||
</p>
|
||||
<p>
|
||||
下文将帮您详细了解我们如何收集、使用、存储、传输、共享、转让(如适用)与保护个人信息;帮您了解查询、访问、删除、更正、撤回授权个人信息的方式。其中,
|
||||
<b>
|
||||
有关您个人信息权益的条款重要内容我们已用加粗形式提示,请特别关注。
|
||||
</b>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="points">
|
||||
<p><b>1.我们处理个人信息的法律依据</b></p>
|
||||
<p><b>2.我们如何共享、转让、公开披露个人信息</b></p>
|
||||
<p><b>3.我们如何收集和使用个人信息</b></p>
|
||||
<p><b>4.我们如何存储个人信息</b></p>
|
||||
<p><b>5.我们如何保护个人信息的安全</b></p>
|
||||
<p><b>6.管理您的个人信息</b></p>
|
||||
<p><b>7.未成年人使用条款</b></p>
|
||||
<p><b>8.隐私政策的修订和通知</b></p>
|
||||
<p><b>9.联系我们</b></p>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<p><b>1.我们处理个人信息的法律依据</b></p>
|
||||
<p>
|
||||
如果您是中华人民共和国大陆地区的用户,我们将依据《中华人民共和国网络安全法》、《信息安全技术
|
||||
个人信息安全规范》(GB/T
|
||||
35273-2017)以及其他相关法律法规收集和使用您的个人信息,为您提供产品或服务。
|
||||
</p>
|
||||
<p>
|
||||
我们通常只会在征得您同意的情况下收集您的个人信息。
|
||||
在某些情况下,我们可能还会基于法律义务或者履行合同之必需向您收集个人信息,或者可能需要个人信息来保护您的重要利益或其他人的利益。
|
||||
</p>
|
||||
|
||||
<p><b>2.我们如何共享、转让、公开披露个人信息</b></p>
|
||||
|
||||
<p class="title margintop"><b>2.1第三方SDK接入说明</b></p>
|
||||
<p>
|
||||
为保障光环助手App相关功能的实现与应用安全稳定的运行,我们会接入由第三方提供的软件开发包(SDK)实现相关功能。
|
||||
<br />
|
||||
我们会对合作方获取有关信息的软件工具开发包(SDK)进行严格的安全检测,并与授权合作伙伴约定严格的数据保护措施,令其按照我们的委托目的、服务说明、本隐私权政策以及其他任何相关的保密和安全措施来处理个人信息。
|
||||
<br />
|
||||
<span class="red-style">
|
||||
下方为整个光环助手
|
||||
<span class="bold">所有版本</span>
|
||||
内接入的所有信息收集类第三方SDK的权限说明,因隐私政策会因光环助手版本迭代而新接入SDK或停止合作部分SDK,方便照顾
|
||||
<span class="bold">所有版本</span>
|
||||
的用户查看自己SDK第三方权限说明。
|
||||
<br />
|
||||
我们对涉及用户信息使用的SDK相关情况进行了逐项列举,具体如下:
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p class="margintop red-style bold-font"><b>(1)数据统计类</b></p>
|
||||
<p>1.头条推广</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">
|
||||
https://ad.oceanengine.com/openapi/index.html
|
||||
</span>
|
||||
</p>
|
||||
<p>SDK包名:com.bytedance</p>
|
||||
<p>企业主体:北京有竹居网络技术有限公司</p>
|
||||
<p>使用目的:用于广告流量统计相关服务</p>
|
||||
<p>
|
||||
收集信息类型:设备品牌、型号、软件系统相关信息、安卓(oaid、无线网SSID名称、WiFi路由器MAC地址、设备MAC地址、IMEI、地理位置)
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">
|
||||
https://ad.oceanengine.com/openapi/register/protocol.html?rid=vo25p8sfqde
|
||||
</span>
|
||||
</p>
|
||||
<p>2.talkingdata统计</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">http://www.talkingdata.com/</span>
|
||||
</p>
|
||||
<p>SDK包名:com.tendcloud</p>
|
||||
<p>企业主体:北京腾云天下科技有限公司</p>
|
||||
<p>使用目的:用于统计数据和效果分析,以便为用户提供更好的服务</p>
|
||||
<p>收集信息类型:设备信息、网络信息、位置信息、应用信息</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">
|
||||
http://www.talkingdata.com/privacy.jsp?languagetype=zh_cn
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p>3.腾讯MTA</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">https://mta.qq.com/mta/</span>
|
||||
</p>
|
||||
<p>SDK包名:com.tencent</p>
|
||||
<p>企业主体:深圳市腾讯计算机系统有限公司</p>
|
||||
<p>使用目的:用于统计数据和效果分析</p>
|
||||
<p>
|
||||
收集信息类型:Mac地址、唯一设备识别码(IMEI、android
|
||||
ID、IDFA、OPENUDID、GUID/SIM卡IMSI信息)、地理位置信息
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">
|
||||
https://mta.qq.com/mta/ctr_index/protocol_v2/
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p>4.腾讯广点通</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">https://developers.e.qq.com/</span>
|
||||
</p>
|
||||
<p>SDK包名:com.tencent</p>
|
||||
<p>企业主体:深圳市腾讯计算机系统有限公司</p>
|
||||
<p>使用目的:用于广告流量统计相关服务</p>
|
||||
<p>
|
||||
收集信息类型:
|
||||
个人常用设备信息(IMEI、AndroidID)、位置信息,IP地址、软件版本号
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">https://e.qq.com/optout.html</span>
|
||||
</p>
|
||||
|
||||
<p class="margintop red-style bold-font"><b>(2)社交登录类</b></p>
|
||||
<p>5.微信登录分享</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">https://open.weixin.qq.com/</span>
|
||||
</p>
|
||||
<p>SDK包名:com.tencent.mm.opensdk</p>
|
||||
<p>企业主体:深圳市腾讯计算机系统有限公司</p>
|
||||
<p>使用目的:用于支持微信登录、分享</p>
|
||||
<p>
|
||||
收集信息类型:个人常用设备信息(MAC地址、IMEI、AndroidID)、硬件型号、操作系统类型、软件信息(软件版本号、浏览器类型)、IP地址、服务日志信息、通讯日志信息
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">https://privacy.tencent.com/</span>
|
||||
</p>
|
||||
|
||||
<p>6.QQ登录分享</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">https://connect.qq.com/</span>
|
||||
</p>
|
||||
<p>SDK包名:com.tentcent</p>
|
||||
<p>企业主体:深圳市腾讯计算机系统有限公司</p>
|
||||
<p>使用目的:用于支持QQ登录、分享</p>
|
||||
<p>
|
||||
收集信息类型:个人常用设备信息(MAC地址、IMEI、AndroidID、IMSI、ICCID、序列号)、设备型号、操作系统版本、软件信息(软件版本号、浏览器类型)、网络信息、IP地址、服务日志信息、通讯日志信息
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">
|
||||
https://wiki.connect.qq.com/qq互联sdk隐私保护声明
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p>7.微博登录分享</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">http://open.weibo.com/authentication</span>
|
||||
</p>
|
||||
<p>SDK包名:com.sina.weibo.sdk</p>
|
||||
<p>企业主体:北京微梦创科网络技术有限公司</p>
|
||||
<p>使用目的:用于支持微博登录、分享</p>
|
||||
<p>
|
||||
收集信息类型:个人常用设备信息(MAC地址、IMEI、AndroidID、IMSI、ICCID、序列号)、网络信息、应用列表,硬件型号、操作系统类型、软件信息(软件版本号、浏览器类型)、IP地址、服务日志信息、通讯日志信息
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">https://open.weibo.com/wiki/开发者协议</span>
|
||||
</p>
|
||||
|
||||
<p>8.头条抖音登录</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">https://open.douyin.com/platform</span>
|
||||
</p>
|
||||
<p>SDK包名:com.bytedance.sdk</p>
|
||||
<p>企业主体:北京字节跳动科技有限公司</p>
|
||||
<p>使用目的:用于支持抖音登录</p>
|
||||
<p>
|
||||
收集信息类型:个人常用设备信息(MAC地址、IMEI、AndroidID)、硬件型号、操作系统类型、软件信息(软件版本号、浏览器类型)、IP地址、服务日志信息、通讯日志信息
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">
|
||||
https://www.douyin.com/agreements/?id=6773901168964798477
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p class="margintop red-style bold-font"><b>(3)推送通知类</b></p>
|
||||
<p>9.友盟推送</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">https://www.umeng.com/push</span>
|
||||
</p>
|
||||
<p>SDK包名:com.umeng</p>
|
||||
<p>企业主体:北京友盟网络科技有限公司</p>
|
||||
<p>使用目的:用于游戏相关信息的提醒通知</p>
|
||||
<p>
|
||||
收集信息类型:Mac地址、唯一设备识别码(IMEI、android
|
||||
ID、IDFA、OPENUDID、GUID/SIM卡IMSI信息)、地理位置信息
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">
|
||||
https://www.umeng.com/page/policy?spm=a213m0.14063960.0.0.7f626e72hx3nnv
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p class="margintop red-style bold-font"><b>(4)其他功能类</b></p>
|
||||
<p>10.阿里云反爬虫</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">https://www.aliyun.com/product/antibot</span>
|
||||
</p>
|
||||
<p>SDK包名:com.alibaba.wireless</p>
|
||||
<p>企业主体:阿里巴巴网络技术有限公司</p>
|
||||
<p>使用目的:为APP提供网络应用安全防护</p>
|
||||
<p>
|
||||
收集信息类型:设备相关信息(例如设备型号、操作系统版本、设备设置、唯一设备标识符等软硬件特征信息)、设备所在位置相关信息(例如IP地址、GPS位置以及能够提供相关信息的Wi-Fi接入点、蓝牙和基站等传感器信息)。
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">
|
||||
http://terms.aliyun.com/legal-agreement/terms/suit_bu1_ali_cloud/suit_bu1_ali_cloud201902141711_54837.html?spm=a2c4g.11186623.J_9220772140.81.b7574832gmk0vr
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p>11.腾讯bugly</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">https://bugly.qq.com/v2/</span>
|
||||
</p>
|
||||
<p>SDK包名:com.tencent.bugly</p>
|
||||
<p>企业主体:深圳市腾讯计算机系统有限公司</p>
|
||||
<p>使用目的:APP异常上报</p>
|
||||
<p>
|
||||
收集信息类型:设备及应用信息。如:设备名称、设备识别符、硬件型号、操作系统版本、应用程序版本
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">https://bugly.qq.com/v2/contract</span>
|
||||
</p>
|
||||
|
||||
<p>12.阿里云文件上传</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">https://www.alibabacloud.com/zh</span>
|
||||
</p>
|
||||
<p>SDK包名:com.alibaba.sdk.android</p>
|
||||
<p>SDK包名:com.alibaba.sdk.android</p>
|
||||
<p>企业主体:阿里巴巴网络技术有限公司</p>
|
||||
<p>使用目的:用于支持用户上传视频等相关内容</p>
|
||||
<p>
|
||||
收集信息类型:设备相关信息(例如设备型号、操作系统版本、设备设置、唯一设备标识符等软硬件特征信息)、设备所在位置相关信息(例如IP地址、GPS位置以及能够提供相关信息的Wi-Fi接入点、蓝牙和基站等传感器信息)。
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">
|
||||
http://terms.aliyun.com/legal-agreement/terms/suit_bu1_ali_cloud/suit_bu1_ali_cloud201902141711_54837.html?spm=a2c4g.11186623.J_9220772140.81.b7574832gmk0vr
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p>13.阿里云日志上传</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">https://www.alibabacloud.com/zh</span>
|
||||
</p>
|
||||
<p>SDK包名:com.aliyun.sls.android.sdk</p>
|
||||
<p>企业主体:阿里巴巴网络技术有限公司</p>
|
||||
<p>
|
||||
使用目的:通过网络日志分析这些信息以便更及时响应您的帮助请求,以及用于改进服务
|
||||
</p>
|
||||
<p>
|
||||
收集信息类型:设备相关信息(例如设备型号、操作系统版本、设备设置、唯一设备标识符等软硬件特征信息)、设备所在位置相关信息(例如IP地址、GPS位置以及能够提供相关信息的Wi-Fi接入点、蓝牙和基站等传感器信息)。
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">
|
||||
http://terms.aliyun.com/legal-agreement/terms/suit_bu1_ali_cloud/suit_bu1_ali_cloud201902141711_54837.html?spm=a2c4g.11186623.J_9220772140.81.b7574832gmk0vr
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p>14.容联七陌</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">https://www.7moor.com/developer</span>
|
||||
</p>
|
||||
<p>SDK包名:com.m7.imkfsdk</p>
|
||||
<p>企业主体:北京七陌科技有限公司</p>
|
||||
<p>使用目的:用于提供对应在线客服功能</p>
|
||||
<p>
|
||||
收集信息类型:设备相关信息(设备名称、设备型号、硬件序列号、操作系统和应用程序版本及类型、语言设置、分辨率、移动终端随机存储内存、摄像头/相册、通讯录权限等)
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">
|
||||
http://m.7moor.com/72/57/p5077783560e807/
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p><b>2.2 共享您的个人信息</b></p>
|
||||
<p>
|
||||
(1)我们不会与任何公司、组织和个人共享您的个人信息,但以下情况除外:
|
||||
</p>
|
||||
<p>
|
||||
(2)事先获得您的明确授权或同意:
|
||||
获得您的明确同意后,我们会与其他方共享您的个人信息;
|
||||
</p>
|
||||
<p>
|
||||
(3)在法定情形下的共享:
|
||||
根据适用的法律法规、法律程序、政府的强制命令或司法裁定而需共享您的个人信息;
|
||||
</p>
|
||||
<p>
|
||||
(4)在法律要求或允许的范围内,为了保护光环助手及其用户或社会公众的利益、财产或安全免遭损害而有必要提供您的个人信息给第三方;
|
||||
</p>
|
||||
<p>
|
||||
(5)与我们的关联公司共享:
|
||||
您的个人信息可能会在我们的关联公司之间共享。我们会对共享的个人信息进行匿名化处理,且这种共享受本指引所声明目的的约束。关联公司如要改变个人信息的处理目的,将再次征求您的授权同意。
|
||||
</p>
|
||||
<p><b>2.3转让</b></p>
|
||||
<p>
|
||||
(1)我们不会转让您的个人信息给任何其他第三方,除非征得您的明确同意。
|
||||
</p>
|
||||
<p>
|
||||
(2)随着我们业务的持续发展,我们将有可能进行合并、收购、资产转让,您的个人信息有可能因此而被转移。在发生前述变更时,我们将按照法律法规及不低于本隐私政策所载明的安全标准要求继受方保护您的个人信息,否则我们将要求继受方重新征得您的授权同意。
|
||||
</p>
|
||||
<p><b>2.4披露</b></p>
|
||||
<p>
|
||||
(1)我们不会公开披露您的信息,除非遵循国家法律法规规定或者获得您的同意。我们公开披露您的个人信息会采用符合行业内标准的安全保护措施。
|
||||
</p>
|
||||
<p>
|
||||
(2)基于法律、法律程序、诉讼或政府主管部门强制性要求的情况下,我们可能会向有权机关披露您的个人信息。但我们保证,在上述情况发生时,我们会要求披露请求方必须出具与之相应的有效法律文件,并对被披露的信息采取符合法律和业界标准的安全防护措施。
|
||||
</p>
|
||||
<p>
|
||||
(3)对违规账号、欺诈行为进行处罚公告时,我们会披露相关账号的信息。
|
||||
</p>
|
||||
|
||||
<p><b>2.5依法豁免征得同意共享、转让、公开披露的个人信息</b></p>
|
||||
<p>
|
||||
请您理解,在下列情形中,根据法律法规及国家标准,我们共享、转让、公开披露您的个人信息无需征得您的授权同意:
|
||||
</p>
|
||||
<p>(1)与国家安全、国防安全直接相关的;</p>
|
||||
<p>(2)与公共安全、公共卫生、重大公共利益直接相关的;</p>
|
||||
<p>(3)与犯罪侦查、起诉、审判和判决执行等直接相关的;</p>
|
||||
<p>
|
||||
(4)出于维护您或其他个人的生命、财产等重大合法权益但又很难得到本人同意的;
|
||||
</p>
|
||||
<p>(5)您自行向社会公众公开的个人信息;</p>
|
||||
<p>
|
||||
(6)从合法公开披露的信息中收集个人信息的,如合法的新闻报道、政府信息公开等渠道。
|
||||
</p>
|
||||
|
||||
<p><b>3.我们如何收集和使用个人信息</b></p>
|
||||
<p>
|
||||
我们会遵循正当、合法、必要的原则,出于本指引所述的以下目的,收集和使用您在使用服务过程中主动提供或因使用产品或服务而产生的个人信息。
|
||||
</p>
|
||||
<p>
|
||||
我们收集和使用的您的个人信息类型包括两种:第一种:我们产品或服务的核心业务功能所必需的信息:此类信息为产品或服务正常运行的必备信息,您须授权我们收集。如您拒绝提供,您将无法正常使用我们的功能,以"仅浏览(游客身份)"
|
||||
的状态体验;第二种:我们产品或服务的附加业务功能可能需要收集的信息:此信息为非核心业务功能所需的信息,您可以选择是否授权我们收集。如您拒绝提供,将导致附加业务功能无法实现或无法达到我们拟达到的效果,但不影响您对核心业务功能的正常使用。
|
||||
</p>
|
||||
<p>
|
||||
如果我们要将您的个人信息用于本指引未载明的其它用途,或基于特定目的将收集而来的信息用于其他目的,我们将以合理的方式向您告知,并在使用前再次征得您的同意。
|
||||
</p>
|
||||
|
||||
<p><b>3.1实现产品或服务的基本功能</b></p>
|
||||
<p>
|
||||
(1)手机管理和内容资源下载功能。为实现手机管理及手机内容资源下载的基本功能,我们会通过手机系统的公用接口收集经过MD5算法加密的国际移动设备身份码(IMEI)和网络设备地址(MAC),以及手机型号、手机系统版本号、系统编号、系统ID号、屏幕分辨率、上网类型、手机中软件的名称、版本号、版本名、包名、软件使用时间和频率、软件崩溃信息、设备和软件相关的信息。这些信息是提供服务所必须收集的基础信息,如您拒绝提供上述权限将可能导致您无法使用我们的服务。
|
||||
</p>
|
||||
<p>
|
||||
(2)软件升级管理功能。为实现手机软件下载、安装、升级、卸载软件管理功能,在您使用产品时,我们会采集您手机中已安装软件的软件名称、版本号、版本名、软件包名信息并上传到我们的服务器进行软件版本比对。发现有更新的版本,我们会提示您升级相应的软件。上述软件信息为实现此功能所必需,不涉及您个人身份敏感信息。
|
||||
</p>
|
||||
<p>
|
||||
(3)过滤无法使用的软件功能。为了过滤您手机无法使用的软件,我们会收集您手机的手机型号、手机系统版本号、系统版本号、屏幕分辨率信息,并依据这些信息排除您手机无法使用的软件,以保证您在光环助手下载的软件都可安装使用。
|
||||
</p>
|
||||
|
||||
<p><b>3.2关于获取手机设备信息的说明</b></p>
|
||||
<p>
|
||||
(1)为方便区分每个用户的个人信息等,本软件需获取用户的手机设备信息,用于游戏主动预约、论坛互动交流后进行推送等用户相关的行为
|
||||
</p>
|
||||
<p>
|
||||
(2)为了保障软件与服务的安全运行,我们会收集您的硬件型号、操作系统版本号、国际移动设备识别码、唯一设备标识符、网络设备硬件地址、IP
|
||||
地址、WLAN接入点、蓝牙、基站、软件版本号、网络接入方式、类型、状态、网络质量数据、操作、使用、服务日志。
|
||||
</p>
|
||||
<p>
|
||||
(3)为了预防恶意程序及安全运营所必需,我们会收集安装的应用信息或正在运行的进程信息、应用程序的总体运行、使用情况与频率、应用崩溃情况、总体安装使用情况、性能数据、应用来源。
|
||||
</p>
|
||||
<p>
|
||||
(4)我们可能使用您的账户信息、设备信息、服务日志信息以及我们关联公司、合作方在获得您授权或依法可以共享的信息,用于判断账户安全、进行身份验证、检测及防范安全事件。
|
||||
</p>
|
||||
<p>(5)具体会发生获取手机设备信息场景如下说明:</p>
|
||||
|
||||
<p class="left-indent">
|
||||
1) 首次启动光环助手
|
||||
<b></b>
|
||||
2) 游戏列表/游戏详情/资讯文章详情/搜索结果页-预约功能
|
||||
<b></b>
|
||||
3) 礼包中心/礼包详情-领取功能
|
||||
<b></b>
|
||||
4) 评论详情-发送评论功能
|
||||
<b></b>
|
||||
5) 回答/问题详情-我来回答功能
|
||||
<b></b>
|
||||
6) 问答首页-提问功能
|
||||
<b></b>
|
||||
7) 个人主页-发文章功能
|
||||
<b></b>
|
||||
8) 帖子草稿/我的草稿-编辑功能
|
||||
<b></b>
|
||||
9) 游戏投稿功能
|
||||
<b></b>
|
||||
10)视频投稿-上传视频功能
|
||||
<b></b>
|
||||
11)游戏详情-关注游戏功能
|
||||
</p>
|
||||
|
||||
<p><b>3.3帮助您成为我们的在线用户</b></p>
|
||||
<p>(1)注册账号/登录账号</p>
|
||||
<p>
|
||||
a.当您注册、登录我们相关服务时,您可以通过手机号创建账号,并且您可以完善相关的网络身份识别信息(头像、昵称、密码),收集这些信息是为了帮助您完成注册。您还可以根据自身需求选择填写性别、生日、地区及个人介绍来完善您的信息。
|
||||
</p>
|
||||
<p>
|
||||
b.您也可以使用第三方账号登录并使用,您将授权我们获取您在第三方平台注册的公开信息(头像、昵称以及您授权的其他信息),用于与光环助手账号绑定,使您可以直接登录并使用本产品和相关服务。
|
||||
</p>
|
||||
<p>(2)认证用户</p>
|
||||
<p>
|
||||
a.在您使用身份认证的功能或服务时,根据相关法律法规,您可能需要提供您的真实身份信息(真实姓名、身份证号码、电话号码)以完成实名验证。
|
||||
</p>
|
||||
<p>
|
||||
b.这些信息属于个人敏感信息,您可以拒绝提供,但您将可能无法获得相关服务,但不影响其他功能与服务的正常使用。
|
||||
</p>
|
||||
|
||||
<p><b>3.4搜索</b></p>
|
||||
<p>
|
||||
(1)您使用“光环助手”的搜索服务时,我们会收集您的搜索关键字信息、日志记录。
|
||||
</p>
|
||||
<p>
|
||||
(2)为了提供高效的搜索服务,部分前述信息会暂时存储在您的本地存储设备之中,并可向您展示搜索结果内容、搜索历史记录。
|
||||
</p>
|
||||
|
||||
<p><b>3.5预约游戏</b></p>
|
||||
<p>
|
||||
当您使用游戏预约、游戏开测提醒功能时,您可以根据需要是否填写手机号。如您拒绝提供,仅会使您无法接收该预约游戏的短信快速提醒功能,但并不影响您正常使用产品与服务的其他。
|
||||
</p>
|
||||
|
||||
<p><b>3.6游戏时长统计</b></p>
|
||||
<p>
|
||||
您可以授权我们使用应用使用记录访问权限,我们会获取您使用某款游戏应用的使用时长,以便于提供游戏时长展示服务以及对应的大数据统计分析。
|
||||
</p>
|
||||
|
||||
<p><b>3.7信息发布功能</b></p>
|
||||
<p>
|
||||
(1)注册成为光环用户后,可在光环平台上发布提问、帖子、视频,并对别人的提问作出回答或邀请其他用户回答,您还可以对别人的回答、帖子和视频的评论作出回复、赞同、感谢。
|
||||
</p>
|
||||
<p>
|
||||
(2)上述功能基于相册(图片库/视频库)的图片/视频访问及上传的附加服务,我们会请求您授权相机、照片、麦克风权限,您可以使用该功能上传您的照片/图片/视频,以实现发布照片/图片/视频的功能、与其他用户进行照片/图片分享等功能。如您拒绝提供该权限和内容的,仅会使您无法使用该功能,但并不影响您正常使用产品与/或服务的其他功能。
|
||||
</p>
|
||||
<p>
|
||||
(3)您发布内容、评论、提问或回答时,我们将收集您发布的信息,并展示您的昵称、头像、发布内容。
|
||||
</p>
|
||||
<p>
|
||||
(4)用户因使用我们的产品或者服务而被我们收集的信息,例如其他用户发布的信息中可能含有您的部分信息(如:在评论、留言、发布图文、音视频中涉及到与您相关的信息)。
|
||||
</p>
|
||||
|
||||
<p><b>3.8浏览、关注与收藏功能</b></p>
|
||||
<p>(1)您可浏览的内容包括问答、评论、专栏、文章。</p>
|
||||
<p>
|
||||
(2)在浏览的过程中,您还可以关注您感兴趣的用户、专栏、问题、收藏,并收藏上述内容。
|
||||
</p>
|
||||
<p>
|
||||
(3)为此,
|
||||
我们可能会收集您使用时的设备信息,如设备型号、唯一设备标识符、操作系统、分辨率、电信运营商等软硬件信息。
|
||||
我们还可能收集您的浏览器类型,以此来为您提供信息展示的最优方案。
|
||||
</p>
|
||||
<p>
|
||||
(4)此外,在您使用浏览和收藏功能的过程中,我们会自动收集您使用的详细情况,并作为有关的
|
||||
网络日志保存,包括但不限于您输入的搜索关键词信息和点击的链接。
|
||||
</p>
|
||||
<p>
|
||||
(5)您浏览和发布的内容及评论信息,您上传的图片信息、您的交易信息、您使用的语言、访问的日期和时间、及您请求的网页记录、操作系统、软件版本号、登录
|
||||
IP 信息。
|
||||
</p>
|
||||
<p>
|
||||
(6)在此过程中,
|
||||
我们会收集您的浏览记录,浏览记录包括您浏览的问答、主页、文章、专栏,
|
||||
您可以自主删除浏览记录。
|
||||
</p>
|
||||
<p><b>3.9互动交流</b></p>
|
||||
<p>
|
||||
(1)您主动关注您感兴趣的账号、内容、视频并与之进行互动,进行浏览、评论、收藏、点赞或分享内容时,我们会收集您关注的账号,并向您展示您关注账号发布内容。
|
||||
</p>
|
||||
<p>
|
||||
(2)您使用推荐通讯录好友功能时,我们会请求通讯录权限,并将通讯录中的信息进行高强度加密算法处理后,用于向您推荐通信录中的好友。通讯录信息属于个人敏感信息,拒绝提供该信息仅会使您无法使用上述功能,但不影响您正常使用“光环助手”及相关服务的其他功能。
|
||||
</p>
|
||||
|
||||
<p><b>3.10收集、使用个人信息目的变更</b></p>
|
||||
<p>
|
||||
(1)请您了解,随着我们业务的发展,可能会对“光环助手”的功能和提供的服务有所调整变化。
|
||||
</p>
|
||||
<p>
|
||||
(2)原则上,当新功能或服务与我们当前提供的功能或服务相关时,收集与使用的个人信息将与原处理目的具有直接或合理关联。
|
||||
</p>
|
||||
<p>
|
||||
(3)在与原处理目的无直接或合理关联的场景下,我们收集、使用您的个人信息,会再次进行告知,并征得您的同意。
|
||||
</p>
|
||||
|
||||
<p><b>3.11依法豁免征得同意收集和使用的个人信息</b></p>
|
||||
<p>
|
||||
请您理解,在下列情形中,根据法律法规及相关国家标准,我们收集和使用您的个人信息无需征得您的授权同意:
|
||||
</p>
|
||||
<p>(1)与国家安全、国防安全直接相关的;</p>
|
||||
<p>(2)与公共安全、公共卫生、重大公共利益直接相关的;</p>
|
||||
<p>(3)与犯罪侦查、起诉、审判和判决执行等直接相关的;</p>
|
||||
<p>
|
||||
(4)出于维护个人信息主体或其他个人的生命、财产等重大合法权益但又很难得到本人同意的;
|
||||
</p>
|
||||
<p>(5)所收集的您的个人信息是您自行向社会公众公开的;</p>
|
||||
<p>
|
||||
(6)从合法公开披露的信息中收集的您的个人信息的,如合法的新闻报道、政府信息公开等渠道;
|
||||
</p>
|
||||
<p>(7)根据您的要求签订或履行合同所必需的;</p>
|
||||
<p>
|
||||
(8)用于维护软件及相关服务的安全稳定运行所必需的,例如发现、处置软件及相关服务的故障;
|
||||
</p>
|
||||
<p>(9)为合法的新闻报道所必需的;</p>
|
||||
<p>
|
||||
(10)学术研究机构基于公共利益开展统计或学术研究所必要,且对外提供学术研究或描述的结果时,对结果中所包含的个人信息进行去标识化处理的。
|
||||
</p>
|
||||
<p>(11)法律法规规定的其他情形。</p>
|
||||
<p>
|
||||
特别提示您注意,如信息无法单独或结合其他信息识别到您的个人身份,其不属于法律意义上您的个人信息;当您的信息可以单独或结合其他信息识别到您的个人身份时或我们将无法与任何特定个人信息建立联系的数据与其他您的个人信息结合使用时,这些信息在结合使用期间,将作为您的个人信息按照本隐私政策处理与保护。
|
||||
</p>
|
||||
|
||||
<p><b>4.我们如何存储个人信息</b></p>
|
||||
<p><b>4.1 存储地点</b></p>
|
||||
<p>
|
||||
(1)我们依照法律法规的规定,将在境内运营过程中收集和产生的您的个人信息存储于中华人民共和国境内。
|
||||
</p>
|
||||
<p>
|
||||
(2)目前,我们不会将上述信息传输至境外,如果我们向境外传输,我们将会遵循相关国家规定或者征求您的同意。
|
||||
</p>
|
||||
<p><b>4.2存储期限</b></p>
|
||||
<p>
|
||||
(1)我们仅在为提供“光环助手”及服务之目的所必需的期间内保留您的个人信息:您发布的信息、评论、点赞及相关信息,在您未撤回、删除或未注销账号期间,我们会保留相关信息。
|
||||
</p>
|
||||
<p>
|
||||
(2)超出必要期限后,我们将对您的个人信息进行删除或匿名化处理,但法律法规另有规定的除外。
|
||||
</p>
|
||||
|
||||
<p><b>5.我们如何保护个人信息的安全</b></p>
|
||||
<p>
|
||||
(1)我们非常重视您个人信息的安全,将努力采取合理的安全措施(包括技术方面和管理方面)来保护您的个人信息,防止您提供的个人信息被不当使用或未经授权的情况下被访问、公开披露、使用、修改、损坏、丢失或泄漏。
|
||||
</p>
|
||||
<p>
|
||||
(2)我们会使用不低于行业同行的加密技术、匿名化处理及相关合理可行的手段保护您的个人信息,并使用安全保护机制防止您的个人信息遭到恶意攻击。
|
||||
</p>
|
||||
<p>
|
||||
(3)我们会建立专门的安全部门、安全管理制度、数据安全流程保障您的个人信息安全。我们采取严格的数据使用和访问制度,确保只有授权人员才可访问您的个人信息,并适时对数据和技术进行安全审计。
|
||||
</p>
|
||||
<p>
|
||||
(4)尽管已经采取了上述合理有效措施,并已经遵守了相关法律规定要求的标准,但请您理解,由于技术的限制以及可能存在的各种恶意手段,在互联网行业,即便竭尽所能加强安全措施,也不可能始终保证信息百分之百的安全,我们将尽力确保您提供给我们的个人信息的安全性。
|
||||
</p>
|
||||
<p>
|
||||
(5)您知悉并理解,您接入我们的服务所用的系统和通讯网络,有可能因我们可控范围外的因素而出现问题。因此,我们强烈建议您采取积极措施保护个人信息的安全,包括但不限于使用复杂密码、定期修改密码、不将自己的账号密码及相关个人信息透露给他人。
|
||||
</p>
|
||||
<p>
|
||||
(6)我们会制定应急处理预案,并在发生用户信息安全事件时立即启动应急预案,努力阻止这些安全事件的影响和后果扩大。一旦发生用户信息安全事件(泄露、丢失)后,我们将按照法律法规的要求,及时向您告知:安全事件的基本情况和可能的影响、我们已经采取或将要采取的处置措施、您可自主防范和降低风险的建议、对您的补救措施。我们将及时将事件相关情况以推送通知、邮件、信函、短信及相关形式告知您,难以逐一告知时,我们会采取合理、有效的方式发布公告。同时,我们还将按照相关监管部门要求,上报用户信息安全事件的处置情况。
|
||||
</p>
|
||||
<p>
|
||||
(7)您一旦离开“光环助手”及相关服务,浏览或使用其他网站、服务及内容资源,我们将没有能力和直接义务保护您在光环助手及相关服务之外的软件、网站提交的任何个人信息,无论您登录、浏览或使用上述软件、网站是否基于“光环助手”的链接或引导。
|
||||
</p>
|
||||
|
||||
<p><b>6.管理您的个人信息</b></p>
|
||||
<p>
|
||||
我们非常重视您对个人信息的管理,并尽全力保护您的隐私,对于您个人信息的查询、访问、修改、删除、撤回同意授权、注销账号、投诉举报以及设置隐私功能的相关权利,以使您有能力保障您的隐私和信息安全。
|
||||
</p>
|
||||
|
||||
<p><b>6.1 访问、删除、更正您的个人信息</b></p>
|
||||
<p>(1)访问个人账号信息</p>
|
||||
<p>a. 您可以查询、访问您的头像、用户名、简介、性别、生日、地区</p>
|
||||
<p>b.您可以在光环助手的“个人中心”中进行查询、访问。</p>
|
||||
<p>(2)查询访问、更正、取消您关注账号、查询访问粉丝、访客信息</p>
|
||||
<p>a.进入“关注”在关注列表中查询、访问、取消关注您关注的账号。</p>
|
||||
<p>
|
||||
(3)查询访问、更改、删除您的收藏、点赞、浏览记录、阅读历史记录、搜索历史历史记录
|
||||
</p>
|
||||
<p>
|
||||
a.点击“我的”—点击“我的收藏”、
|
||||
“我的点赞”、或“浏览历史”进入查询访问、删除;
|
||||
</p>
|
||||
<p>b.点击搜索栏—删除搜索“历史记录”</p>
|
||||
<p>c.您可以通过点击“系统设置”—点击“清理缓存”。</p>
|
||||
<p>(4)投诉举报</p>
|
||||
<p>a.您可按照我们公示的制度进行投诉或举报。</p>
|
||||
<p>
|
||||
b.如果您认为您的个人信息权利可能受到侵害,或者发现侵害个人信息权利的线索(例如:认为我们收集您的个人信息违反法律规定或者双方约定),“我的”—“基础功能”—“用户反馈”,进入用户反馈界面与我们联系。
|
||||
</p>
|
||||
<p>c.我们核查后会及时反馈您的投诉与举报。</p>
|
||||
<p>(5)访问隐私政策</p>
|
||||
<p>
|
||||
a.您可以在注册页面,或者在登录个人账号“设置”—“关于”查看本隐私政策的全部内容
|
||||
</p>
|
||||
<p>
|
||||
b.请您了解,本隐私政策中所述的“光环助手”及相关服务可能会根据您所使用的手机型号、系统版本、软件应用程序版本、移动客户端等因素而有所不同。最终的产品和服务以您所使用的“光环助手”软件及相关服务为准。
|
||||
</p>
|
||||
<p>(6)停止运营向您告知</p>
|
||||
<p>
|
||||
a.如我们停止运营,我们将及时停止收集您个人信息的活动,将停止运营的通知以逐一送达或公告的形式通知您,并对所持有的您的个人信息进行删除或匿名化处理。
|
||||
</p>
|
||||
|
||||
<p><b>6.2 注销您的个人账号</b></p>
|
||||
<p>
|
||||
如需要注销个人账户,可前往光环助手,我的光环> 设置 > 账号与安全 >
|
||||
账号安全中心 >
|
||||
注销账号,进行注销操作。请您注意,如果您选择注销光环助手账户,那么您的光环助手账号将不可被使用且相关账号信息将被删除,包括所发布的所有内容,包括:提问、回答、社区文章、评论、关注的人等均会被清空;您将无法再通过光环助手账号登录光环助手的服务(但不会影响您使用无需账号登录即可使用的服务和功能)
|
||||
</p>
|
||||
<p>
|
||||
当您注销账户后,除法律法规要求我们保存相关信息的情况外,我们将停止为您提供相应的产品(或服务),并在60个工作日内删除或匿名化您的个人信息。
|
||||
</p>
|
||||
|
||||
<p><b>7.未成年人条款</b></p>
|
||||
<p>
|
||||
a.若您是未满18周岁的未成年人,在使用“光环助手”及相关服务前,应在您的父母或其他监护人监护、指导下共同阅读并同意本隐私政策。
|
||||
</p>
|
||||
<p>
|
||||
b.我们根据国家相关法律法规的规定保护未成年人的个人信息,只会在法律允许、父母或其他监护人明确同意或保护未成年人所必要的情况下收集、使用、储存、共享、转让或披露未成年人的个人信息;如果我们发现在未事先获得可证实的父母同意的情况下收集了未成年人的个人信息,则会设法尽快删除相关信息。
|
||||
</p>
|
||||
<p>
|
||||
c.若您是未成年人的监护人,当您对您所监护的未成年人的个人信息有相关疑问时,请通过公司本隐私政策公示的联系方式与我们联系。
|
||||
</p>
|
||||
<p><b>8.隐私政策的修订和通知</b></p>
|
||||
<p>
|
||||
(1)为了给您提供更好的服务,光环助手及相关服务将不时更新与变化,我们会适时对本隐私政策进行修订,这些修订构成本隐私政策的一部分并具有等同于本隐私政策的效力,未经您明确同意,我们不会削减您依据当前生效的本隐私政策所应享受的权利。
|
||||
</p>
|
||||
<p>
|
||||
(2)本隐私政策更新后,我们会在光环助手发出更新版本,并在更新后的条款生效前通过公告或其他适当的方式提醒您更新的内容,以便您及时了解本隐私政策的最新版本。
|
||||
</p>
|
||||
<p><b>9.联系我们</b></p>
|
||||
<p>
|
||||
如果您对我们的隐私政策及对您个人信息的处理有任何疑问、意见、建议、或投诉,请通过以下方式与我们联系
|
||||
</p>
|
||||
<p>广州加兔网络科技有限公司</p>
|
||||
<p>注册地址:广州市番禺区市桥街丹山村青云一街2号229房</p>
|
||||
<p>在线客服QQ:350473523</p>
|
||||
<p>信息保护事务联系电话:020-85526920</p>
|
||||
<p>在一般情况下,我们会在15个工作日内对您的请求予以答复</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@ -280,12 +280,8 @@ RE.replaceAllDfImage = function(imgRuleFlag, gifRuleFlag) {
|
||||
i--;
|
||||
} else {
|
||||
if(img.src.indexOf(".gif") > 0) {
|
||||
if(gifRuleFlag.indexOf(",default") > 0) {
|
||||
img.style.cssText = "max-width: 100%; display:block; margin:8px auto; height: auto;"
|
||||
img.src = img.src.split("?")[0] + gifRuleFlag
|
||||
}
|
||||
img.src = img.src.split("?")[0] + gifRuleFlag
|
||||
} else {
|
||||
img.style.cssText = "max-width: 100%; display:block; margin:8px auto; height: auto;"
|
||||
img.src = img.src.split("?")[0] + imgRuleFlag
|
||||
}
|
||||
}
|
||||
@ -301,7 +297,7 @@ RE.hideShowBigPic = function() {
|
||||
var img = imgs[i];
|
||||
var imageClassName = img.className;
|
||||
if (imageClassName == "image-link" || img.className == "poster") continue;
|
||||
if(img.src.indexOf(",thumbnail") > 0 && img.src.indexOf(".gif") == -1) {
|
||||
if (img.src.indexOf(".gif") == -1) {
|
||||
j++;
|
||||
}
|
||||
}
|
||||
@ -327,7 +323,6 @@ RE.replaceDfImageByUrl = function(imgUrl, imgRuleFlag, gifRuleFlag) {
|
||||
var imageClassName = img.className;
|
||||
if (imageClassName == "image-link" || img.className == "poster") continue;
|
||||
if (img.src.indexOf(imgUrl) != -1) {
|
||||
img.style.cssText = "max-width: 100%; display:block; margin:8px auto; height: auto;"
|
||||
if(img.src.indexOf(".gif") > 0) {
|
||||
img.src = img.src.split("?")[0] + gifRuleFlag
|
||||
} else {
|
||||
|
||||
@ -1,493 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
||||
<title>光环助手软件许可及服务协议</title>
|
||||
</head>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 14px;
|
||||
-webkit-user-select: text;
|
||||
-moz-user-select: text;
|
||||
-ms-user-select: text;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.top {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
padding: 10px 0 10px 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: 700;
|
||||
}
|
||||
.margintop {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.left-indent {
|
||||
margin-left: 20px;
|
||||
}
|
||||
.red-style {
|
||||
color: red;
|
||||
}
|
||||
.bold-font {
|
||||
font-weight: bold;
|
||||
}
|
||||
span.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
.link-text {
|
||||
color: #005ad0;
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
<h3 class="top">光环助手软件许可及服务协议</h3>
|
||||
<h5 class="title">首部及导言</h5>
|
||||
<p>欢迎使用光环助手软件许可及服务</p>
|
||||
<p>
|
||||
各位用户在使用光环助手前,请您务必审慎阅读、并充分理解本协议中的各项条款,
|
||||
<span class="bold">
|
||||
特别是免除或者限制责任的条款,以及开通或使用某项服务的单独协议,并选择接受或不接受。
|
||||
</span>
|
||||
除非您已阅读并接受本协议所有条款,否则您无权下载、安装或使用本软件及相关服务。您的下载、安装、使用、登录等行为即视为您已阅读并同意上述协议的约束。
|
||||
</p>
|
||||
<p>如果您未满18周岁,请在法定监护人的陪同下阅读本协议及其他上述协议。</p>
|
||||
<h5 class="title margintop">一、权利声明</h5>
|
||||
<p>
|
||||
“光环助手”的一切知识产权,以及与“光环助手”相关的所有信息内容,包括但不限于:文字表述及其组合、图标、图饰、图像、图表、色彩、界面设计、版面框架、有关数据、附加程序、印刷材料或电子文档等均为光环助手所有,受著作权法和国际著作权条约以及其他知识产权法律法规的保护。
|
||||
</p>
|
||||
<h5 class="title margintop">二、软件使用规范</h5>
|
||||
<p>
|
||||
2.1
|
||||
本软件是基于Android(安卓)系统手机、平板电脑(PAD)等设备开发的一款软件,提供注册登录、手机游戏管理、游戏推荐、文章阅读等功能
|
||||
</p>
|
||||
<p>2.2 软件的下载、安装和使用</p>
|
||||
<p>
|
||||
本软件为免费软件,用户可以非商业性、无限制数量地从光环授权的渠道下载、安装及使用本软件。
|
||||
</p>
|
||||
<p>
|
||||
<span class="bold">
|
||||
如果您从未经光环授权的第三方获取本软件或与本软件名称相同的安装程序,光环无法保证该软件能够正常使用,并对因此给您造成的损失不予负责。
|
||||
</span>
|
||||
</p>
|
||||
<p>2.3 软件的复制、分发和传播</p>
|
||||
<p>
|
||||
本产品以学习、研究交流为目的。用户可以非商业性、无限制数量地复制、分发和传播本软件产品。但必须保证每一份复制、分发和传播都是完整和真实的,
|
||||
包括所有有关本软件产品的软件、电子文档, 版权和商标,亦包括本协议。
|
||||
</p>
|
||||
<p>2.4 软件的更新</p>
|
||||
<p>
|
||||
为了改善用户体验、完善服务内容,光环将不断努力开发新的服务,并为您不时提供软件更新(这些更新可能会采取软件替换、修改、功能强化、版本升级等形式)。为了保证本软件及服务的安全性和功能的一致性,光环有权不经向您特别通知而对软件进行更新,或者对软件的部分功能效果进行改变或限制。本软件新版本发布后,旧版本的软件可能无法使用。光环不保证旧版本软件继续可用及相应的客户服务,请您随时核对并下载最新版本。
|
||||
</p>
|
||||
<h5 class="title margintop">三、用户使用须知</h5>
|
||||
<p>3.1 您理解并同意:</p>
|
||||
<p>
|
||||
为了向您提供有效的服务,本软件会利用您移动通讯终端的处理器和带宽等资源。本软件使用过程中可能产生数据流量的费用,用户需自行向运营商了解相关资费信息,并自行承担相关费用.
|
||||
</p>
|
||||
<p>3.2 您理解并同意:</p>
|
||||
<p>
|
||||
由本软件进行收录、推荐并提供下载、升级服务的第三方软件,由第三方享有一切合法权利,光环并不能识别用户利用本软件下载、安装的第三方软件是否有合法来源。
|
||||
<span class="bold">
|
||||
因第三方软件引发的任何纠纷,由该第三方负责解决,光环不承担任何责任。
|
||||
</span>
|
||||
同时光环不对第三方软件或技术提供客服支持,若用户需要获取支持,请与该软件或技术提供商联系,若您为有关软件的权利人,不愿本软件为您的软件提供用户下载、安装、使用的服务,也可按本协议约定的联系方式联系我们,我们将会积极配合进行处理。
|
||||
</p>
|
||||
<p>3.3 您理解并同意:</p>
|
||||
<p>
|
||||
<span class="bold">
|
||||
如果因您不正当使用本软件造成了不良影响,或因使用本软件造成的包括但不限于数据异常等问题,均由使用者自行承担,光环团队不对任意类型的使用结果承担责任;
|
||||
</span>
|
||||
</p>
|
||||
<p>3.4 您理解并同意:</p>
|
||||
<p>
|
||||
本软件不含任何破坏用户移动通讯设备数据和获取用户隐私信息的恶意代码,不会泄露用户的个人信息和隐私;
|
||||
</p>
|
||||
<p>3.5 您理解并同意:</p>
|
||||
<p>
|
||||
<span class="bold">
|
||||
对于包括但不限于互联网网络故障、计算机故障、手机故障或病毒、信息损坏或丢失、计算机系统问题,或其它任何基于不可抗力原因而产生的损失,光环团队不承担任何责任。
|
||||
</span>
|
||||
</p>
|
||||
<p>3.6 您理解并同意:</p>
|
||||
<p>光环发布、收录的文章均不代表光环立场。</p>
|
||||
<p>3.7 您理解并同意:</p>
|
||||
<p>
|
||||
为实现软件包括但不限于集中展示、下载、安装、卸载等游戏管理功能以及文章优先推荐功能,本软件会检测用户手机中已安装游戏的包名、版本号、版本名、游戏名称信息。除征得用户明确同意和法律明确规定外,光环不会向第三方泄露任何的用户信息
|
||||
</p>
|
||||
<p>3.8 您理解并同意:</p>
|
||||
<p>
|
||||
用户应在遵守法律及本协议的前提下使用本软件。用户无权实施包括但不限于下列行为:
|
||||
</p>
|
||||
3.8.1 不得删除或者改变本软件上的所有权利管理电子信息
|
||||
<br />
|
||||
3.8.2 不得故意避开或者破坏著作权人为保护本软件著作权而采取的技术措施;
|
||||
<br />
|
||||
3.8.3 用户不得利用本软件误导、欺骗他人;
|
||||
<br />
|
||||
3.8.4
|
||||
违反国家规定,对计算机信息系统功能进行删除、修改、增加、干扰,造成计算机信息系统不能正常运行;
|
||||
<br />
|
||||
3.8.5 未经允许,进入计算机信息网络或者使用计算机信息网络资源;
|
||||
<br />
|
||||
3.8.6 未经允许,对计算机信息网络功能进行删除、修改或者增加;
|
||||
<br />
|
||||
3.8.7
|
||||
未经允许,对计算机信息网络中存储、处理或者传输的数据和应用程序进行删除、修改或者增加;
|
||||
<br />
|
||||
3.8.8 破坏本软件系统或网站的正常运行,故意传播计算机病毒等破坏性程序;
|
||||
<br />
|
||||
3.8.9 其他任何危害计算机信息网络安全的行为。
|
||||
<br />
|
||||
<p>3.9 您理解并同意:</p>
|
||||
<p>
|
||||
本软件经过详细的测试,但不能保证与所有的软硬件系统完全兼容,不能保证本软件完全没有错误。如果出现不兼容及软件错误的情况,用户可通过各反馈途径将情况告知光环团队,获得技术支持。如果无法解决兼容性问题,用户可以删除本软件。
|
||||
</p>
|
||||
<h5 class="title margintop">四、争议解决处理</h5>
|
||||
<p>
|
||||
本《协议》的解释、效力及纠纷的解决,适用于中华人民共和国法律。若用户和光环助手之间发生任何纠纷或争议,首先应友好协商解决,协商不成的,用户在此完全同意将纠纷或争议提交光环助手所在地法院管辖
|
||||
</p>
|
||||
|
||||
<p class="title margintop"><b>五、第三方SDK接入说明</b></p>
|
||||
<p>
|
||||
为保障光环助手App相关功能的实现与应用安全稳定的运行,我们会接入由第三方提供的软件开发包(SDK)实现相关功能。
|
||||
<br />
|
||||
我们会对合作方获取有关信息的软件工具开发包(SDK)进行严格的安全检测,并与授权合作伙伴约定严格的数据保护措施,令其按照我们的委托目的、服务说明、本隐私权政策以及其他任何相关的保密和安全措施来处理个人信息。
|
||||
<br />
|
||||
<span class="red-style">
|
||||
下方为整个光环助手
|
||||
<span class="bold">所有版本</span>
|
||||
内接入的所有信息收集类第三方SDK的权限说明,因隐私政策会因光环助手版本迭代而新接入SDK或停止合作部分SDK,方便照顾
|
||||
<span class="bold">所有版本</span>
|
||||
的用户查看自己SDK第三方权限说明。
|
||||
<br />
|
||||
我们对涉及用户信息使用的SDK相关情况进行了逐项列举,具体如下:
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p class="margintop red-style bold-font"><b>(1)数据统计类</b></p>
|
||||
<p>1.头条推广</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">
|
||||
https://ad.oceanengine.com/openapi/index.html
|
||||
</span>
|
||||
</p>
|
||||
<p>SDK包名:com.bytedance</p>
|
||||
<p>企业主体:北京有竹居网络技术有限公司</p>
|
||||
<p>使用目的:用于广告流量统计相关服务</p>
|
||||
<p>
|
||||
收集信息类型:设备品牌、型号、软件系统相关信息、安卓(oaid、无线网SSID名称、WiFi路由器MAC地址、设备MAC地址、IMEI、地理位置)
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">
|
||||
https://ad.oceanengine.com/openapi/register/protocol.html?rid=vo25p8sfqde
|
||||
</span>
|
||||
</p>
|
||||
<p>2.talkingdata统计</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">http://www.talkingdata.com/</span>
|
||||
</p>
|
||||
<p>SDK包名:com.tendcloud</p>
|
||||
<p>企业主体:北京腾云天下科技有限公司</p>
|
||||
<p>使用目的:用于统计数据和效果分析,以便为用户提供更好的服务</p>
|
||||
<p>收集信息类型:设备信息、网络信息、位置信息、应用信息</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">
|
||||
http://www.talkingdata.com/privacy.jsp?languagetype=zh_cn
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p>3.腾讯MTA</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">https://mta.qq.com/mta/</span>
|
||||
</p>
|
||||
<p>SDK包名:com.tencent</p>
|
||||
<p>企业主体:深圳市腾讯计算机系统有限公司</p>
|
||||
<p>使用目的:用于统计数据和效果分析</p>
|
||||
<p>
|
||||
收集信息类型:Mac地址、唯一设备识别码(IMEI、android
|
||||
ID、IDFA、OPENUDID、GUID/SIM卡IMSI信息)、地理位置信息
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">
|
||||
https://mta.qq.com/mta/ctr_index/protocol_v2/
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p>4.腾讯广点通</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">https://developers.e.qq.com/</span>
|
||||
</p>
|
||||
<p>SDK包名:com.tencent</p>
|
||||
<p>企业主体:深圳市腾讯计算机系统有限公司</p>
|
||||
<p>使用目的:用于广告流量统计相关服务</p>
|
||||
<p>
|
||||
收集信息类型:
|
||||
个人常用设备信息(IMEI、AndroidID)、位置信息,IP地址、软件版本号
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">https://e.qq.com/optout.html</span>
|
||||
</p>
|
||||
|
||||
<p class="margintop red-style bold-font"><b>(2)社交登录类</b></p>
|
||||
<p>5.微信登录分享</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">https://open.weixin.qq.com/</span>
|
||||
</p>
|
||||
<p>SDK包名:com.tencent.mm.opensdk</p>
|
||||
<p>企业主体:深圳市腾讯计算机系统有限公司</p>
|
||||
<p>使用目的:用于支持微信登录、分享</p>
|
||||
<p>
|
||||
收集信息类型:个人常用设备信息(MAC地址、IMEI、AndroidID)、硬件型号、操作系统类型、软件信息(软件版本号、浏览器类型)、IP地址、服务日志信息、通讯日志信息
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">https://privacy.tencent.com/</span>
|
||||
</p>
|
||||
|
||||
<p>6.QQ登录分享</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">https://connect.qq.com/</span>
|
||||
</p>
|
||||
<p>SDK包名:com.tentcent</p>
|
||||
<p>企业主体:深圳市腾讯计算机系统有限公司</p>
|
||||
<p>使用目的:用于支持QQ登录、分享</p>
|
||||
<p>
|
||||
收集信息类型:个人常用设备信息(MAC地址、IMEI、AndroidID、IMSI、ICCID、序列号)、设备型号、操作系统版本、软件信息(软件版本号、浏览器类型)、网络信息、IP地址、服务日志信息、通讯日志信息
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">
|
||||
https://wiki.connect.qq.com/qq互联sdk隐私保护声明
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p>7.微博登录分享</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">http://open.weibo.com/authentication</span>
|
||||
</p>
|
||||
<p>SDK包名:com.sina.weibo.sdk</p>
|
||||
<p>企业主体:北京微梦创科网络技术有限公司</p>
|
||||
<p>使用目的:用于支持微博登录、分享</p>
|
||||
<p>
|
||||
收集信息类型:个人常用设备信息(MAC地址、IMEI、AndroidID、IMSI、ICCID、序列号)、网络信息、应用列表,硬件型号、操作系统类型、软件信息(软件版本号、浏览器类型)、IP地址、服务日志信息、通讯日志信息
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">https://open.weibo.com/wiki/开发者协议</span>
|
||||
</p>
|
||||
|
||||
<p>8.头条抖音登录</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">https://open.douyin.com/platform</span>
|
||||
</p>
|
||||
<p>SDK包名:com.bytedance.sdk</p>
|
||||
<p>企业主体:北京字节跳动科技有限公司</p>
|
||||
<p>使用目的:用于支持抖音登录</p>
|
||||
<p>
|
||||
收集信息类型:个人常用设备信息(MAC地址、IMEI、AndroidID)、硬件型号、操作系统类型、软件信息(软件版本号、浏览器类型)、IP地址、服务日志信息、通讯日志信息
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">
|
||||
https://www.douyin.com/agreements/?id=6773901168964798477
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p class="margintop red-style bold-font"><b>(3)推送通知类</b></p>
|
||||
<p>9.友盟推送</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">https://www.umeng.com/push</span>
|
||||
</p>
|
||||
<p>SDK包名:com.umeng</p>
|
||||
<p>企业主体:北京友盟网络科技有限公司</p>
|
||||
<p>使用目的:用于游戏相关信息的提醒通知</p>
|
||||
<p>
|
||||
收集信息类型:Mac地址、唯一设备识别码(IMEI、android
|
||||
ID、IDFA、OPENUDID、GUID/SIM卡IMSI信息)、地理位置信息
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">
|
||||
https://www.umeng.com/page/policy?spm=a213m0.14063960.0.0.7f626e72hx3nnv
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p class="margintop red-style bold-font"><b>(4)其他功能类</b></p>
|
||||
<p>10.阿里云反爬虫</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">https://www.aliyun.com/product/antibot</span>
|
||||
</p>
|
||||
<p>SDK包名:com.alibaba.wireless</p>
|
||||
<p>企业主体:阿里巴巴网络技术有限公司</p>
|
||||
<p>使用目的:为APP提供网络应用安全防护</p>
|
||||
<p>
|
||||
收集信息类型:设备相关信息(例如设备型号、操作系统版本、设备设置、唯一设备标识符等软硬件特征信息)、设备所在位置相关信息(例如IP地址、GPS位置以及能够提供相关信息的Wi-Fi接入点、蓝牙和基站等传感器信息)。
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">
|
||||
http://terms.aliyun.com/legal-agreement/terms/suit_bu1_ali_cloud/suit_bu1_ali_cloud201902141711_54837.html?spm=a2c4g.11186623.J_9220772140.81.b7574832gmk0vr
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p>11.腾讯bugly</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">https://bugly.qq.com/v2/</span>
|
||||
</p>
|
||||
<p>SDK包名:com.tencent.bugly</p>
|
||||
<p>企业主体:深圳市腾讯计算机系统有限公司</p>
|
||||
<p>使用目的:APP异常上报</p>
|
||||
<p>
|
||||
收集信息类型:设备及应用信息。如:设备名称、设备识别符、硬件型号、操作系统版本、应用程序版本
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">https://bugly.qq.com/v2/contract</span>
|
||||
</p>
|
||||
|
||||
<p>12.阿里云文件上传</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">https://www.alibabacloud.com/zh</span>
|
||||
</p>
|
||||
<p>SDK包名:com.alibaba.sdk.android</p>
|
||||
<p>SDK包名:com.alibaba.sdk.android</p>
|
||||
<p>企业主体:阿里巴巴网络技术有限公司</p>
|
||||
<p>使用目的:用于支持用户上传视频等相关内容</p>
|
||||
<p>
|
||||
收集信息类型:设备相关信息(例如设备型号、操作系统版本、设备设置、唯一设备标识符等软硬件特征信息)、设备所在位置相关信息(例如IP地址、GPS位置以及能够提供相关信息的Wi-Fi接入点、蓝牙和基站等传感器信息)。
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">
|
||||
http://terms.aliyun.com/legal-agreement/terms/suit_bu1_ali_cloud/suit_bu1_ali_cloud201902141711_54837.html?spm=a2c4g.11186623.J_9220772140.81.b7574832gmk0vr
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p>13.阿里云日志上传</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">https://www.alibabacloud.com/zh</span>
|
||||
</p>
|
||||
<p>SDK包名:com.aliyun.sls.android.sdk</p>
|
||||
<p>企业主体:阿里巴巴网络技术有限公司</p>
|
||||
<p>
|
||||
使用目的:通过网络日志分析这些信息以便更及时响应您的帮助请求,以及用于改进服务
|
||||
</p>
|
||||
<p>
|
||||
收集信息类型:设备相关信息(例如设备型号、操作系统版本、设备设置、唯一设备标识符等软硬件特征信息)、设备所在位置相关信息(例如IP地址、GPS位置以及能够提供相关信息的Wi-Fi接入点、蓝牙和基站等传感器信息)。
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">
|
||||
http://terms.aliyun.com/legal-agreement/terms/suit_bu1_ali_cloud/suit_bu1_ali_cloud201902141711_54837.html?spm=a2c4g.11186623.J_9220772140.81.b7574832gmk0vr
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p>14.容联七陌</p>
|
||||
<p>
|
||||
SDK官网:
|
||||
<span class="link-text">https://www.7moor.com/developer</span>
|
||||
</p>
|
||||
<p>SDK包名:com.m7.imkfsdk</p>
|
||||
<p>企业主体:北京七陌科技有限公司</p>
|
||||
<p>使用目的:用于提供对应在线客服功能</p>
|
||||
<p>
|
||||
收集信息类型:设备相关信息(设备名称、设备型号、硬件序列号、操作系统和应用程序版本及类型、语言设置、分辨率、移动终端随机存储内存、摄像头/相册、通讯录权限等)
|
||||
</p>
|
||||
<p>
|
||||
隐私政策链接:
|
||||
<span class="link-text">http://m.7moor.com/72/57/p5077783560e807/</span>
|
||||
</p>
|
||||
|
||||
<h5 class="title margintop">六、关于获取手机设备信息的说明</h5>
|
||||
<div>
|
||||
(1)为方便区分每个用户的个人信息等,本软件需获取用户的手机设备信息,用于游戏主动预约、论坛互动交流后进行推送等用户相关的行为
|
||||
<br />
|
||||
(2)为了保障软件与服务的安全运行,我们会收集您的硬件型号、操作系统版本号、国际移动设备识别码、唯一设备标识符、网络设备硬件地址、IP
|
||||
地址、WLAN接入点、蓝牙、基站、软件版本号、网络接入方式、类型、状态、网络质量数据、操作、使用、服务日志。
|
||||
<br />
|
||||
(3)为了预防恶意程序及安全运营所必需,我们会收集安装的应用信息或正在运行的进程信息、应用程序的总体运行、使用情况与频率、应用崩溃情况、总体安装使用情况、性能数据、应用来源。
|
||||
<br />
|
||||
(4)我们可能使用您的账户信息、设备信息、服务日志信息以及我们关联公司、合作方在获得您授权或依法可以共享的信息,用于判断账户安全、进行身份验证、检测及防范安全事件。
|
||||
<br />
|
||||
(5)具体会发生获取手机设备信息场景如下说明:
|
||||
<br />
|
||||
<p class="left-indent">
|
||||
1) 首次启动光环助手
|
||||
<br />
|
||||
2) 游戏列表/游戏详情/资讯文章详情/搜索结果页-预约功能
|
||||
<br />
|
||||
3) 礼包中心/礼包详情-领取功能
|
||||
<br />
|
||||
4) 评论详情-发送评论功能
|
||||
<br />
|
||||
5) 回答/问题详情-我来回答功能
|
||||
<br />
|
||||
6) 问答首页-提问功能
|
||||
<br />
|
||||
7) 个人主页-发文章功能
|
||||
<br />
|
||||
8) 帖子草稿/我的草稿-编辑功能
|
||||
<br />
|
||||
9) 游戏投稿功能
|
||||
<br />
|
||||
10) 视频投稿-上传视频功能
|
||||
<br />
|
||||
11) 游戏详情-关注游戏功能
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<h5 class="title margintop">七、其他</h5>
|
||||
<p>
|
||||
7.1
|
||||
本协议所有条款的标题仅为阅读方便,本身并无实际涵义,不能作为本协议涵义解释的依据。
|
||||
<br />
|
||||
7.2
|
||||
如果本协议中的任何条款无论因何种原因完全或部分无效或不具有执行力,或违反任何适用的法律,则该条款被视为删除,但本协议的其余条款仍应有效并且有约束力。
|
||||
<br />
|
||||
7.3
|
||||
光环有权随时根据有关法律、法规的变化以及公司经营状况和经营策略的调整等修改本协议。修改后的协议会在软件设置内发布。
|
||||
当发生有关争议时,以最新的协议文本为准。如果不同意改动的内容,用户可以自行删除本软件。如果用户继续使用本软件,则视为您接受本协议的变动。
|
||||
<br />
|
||||
<span class="bold">
|
||||
7.4 光环在法律允许的最大范围内对本协议拥有解释权与修改权。
|
||||
</span>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,134 +0,0 @@
|
||||
package com.gh.base;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.os.Looper;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.common.util.DataCollectionUtils;
|
||||
import com.gh.common.util.DataUtils;
|
||||
import com.gh.gamecenter.SplashScreenActivity;
|
||||
import com.lightgame.config.CommonDebug;
|
||||
import com.lightgame.download.FileUtils;
|
||||
import com.lightgame.utils.AppManager;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.lang.Thread.UncaughtExceptionHandler;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import io.sentry.Sentry;
|
||||
|
||||
public class AppUncaughtHandler implements UncaughtExceptionHandler {
|
||||
|
||||
private Context mContext;
|
||||
|
||||
public AppUncaughtHandler(Context context) {
|
||||
// 获取系统默认的UncaughtException处理器
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uncaughtException(Thread t, Throwable e) {
|
||||
if (("FinalizerWatchdogDaemon").equals(t.getName())
|
||||
&& e instanceof TimeoutException) {
|
||||
// ignore timeoutException
|
||||
// detail can be found in this didi tech blog post https://mp.weixin.qq.com/s?__biz=MzU1ODEzNjI2NA==&mid=2247487185&idx=2&sn=cf2d9e10053f625bde0f61d246f14870&source=41#wechat_redirect
|
||||
} else {
|
||||
new Thread(() -> {
|
||||
Looper.prepare();
|
||||
Utils.toast(mContext.getApplicationContext(), "\"光环助手\"发生错误");
|
||||
Looper.loop();
|
||||
});
|
||||
saveLocalLog(mContext, e);
|
||||
restart(mContext);
|
||||
Sentry.captureException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void restart(final Context context) {
|
||||
// S450 这机器会无限重启循环 : (
|
||||
if ("S450".equals(Build.MODEL)) return;
|
||||
|
||||
// 防止重复奔溃,导致助手一直重启,20秒内不做处理
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
long curTime = System.currentTimeMillis();
|
||||
long time = sp.getLong("last_restart_time", 0);
|
||||
if (curTime - time > 20 * 1000) {
|
||||
sp.edit().putLong("last_restart_time", curTime).apply();
|
||||
Intent intent = new Intent(context, SplashScreenActivity.class);
|
||||
intent.setAction(Intent.ACTION_MAIN);
|
||||
intent.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||
PendingIntent restartIntent = PendingIntent.getActivity(context, 0, intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
// 退出程序并重启
|
||||
AlarmManager mgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
mgr.set(AlarmManager.RTC, curTime + 3000, restartIntent); // 1秒钟后重启应用
|
||||
}
|
||||
|
||||
//error restart
|
||||
// System.exit(2);
|
||||
AppManager.getInstance().finishAllActivity();
|
||||
}
|
||||
|
||||
// 保存log到本地
|
||||
public static void saveLocalLog(Context context, Throwable ex) {
|
||||
String errorMsg = Log.getStackTraceString(ex);
|
||||
Config.setExceptionMsg(errorMsg);
|
||||
|
||||
// 保存到本地
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.getDefault());
|
||||
File file = new File(FileUtils.getLogPath(context.getApplicationContext(),
|
||||
format.format(new Date()) + "_gh_assist" + ".log"));
|
||||
FileWriter writer = null;
|
||||
try {
|
||||
file.createNewFile();
|
||||
writer = new FileWriter(file);
|
||||
writer.write(errorMsg);
|
||||
writer.flush();
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
} finally {
|
||||
if (writer != null) {
|
||||
try {
|
||||
writer.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 下次应用启动再上报
|
||||
*
|
||||
* @param context
|
||||
* @param throwable
|
||||
*/
|
||||
public static void reportException(Context context, Throwable throwable) {
|
||||
|
||||
CommonDebug.logMethodWithParams(context, "ERRMSG", throwable);
|
||||
|
||||
// 上传错误数据
|
||||
try {
|
||||
DataCollectionUtils.uploadError(context, Log.getStackTraceString(throwable));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
DataUtils.onError(context, throwable);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,533 +0,0 @@
|
||||
package com.gh.base;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.Parcel;
|
||||
import android.os.TransactionTooLargeException;
|
||||
import android.text.TextUtils;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
|
||||
import com.gh.base.fragment.BaseFragment;
|
||||
import com.gh.common.constant.Constants;
|
||||
import com.gh.common.tracker.IBusiness;
|
||||
import com.gh.common.util.DialogHelper;
|
||||
import com.gh.common.util.DialogUtils;
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.gh.common.util.ExtensionsKt;
|
||||
import com.gh.common.util.MtaHelper;
|
||||
import com.gh.common.util.NetworkUtils;
|
||||
import com.gh.common.util.PackageInstaller;
|
||||
import com.gh.common.util.QuickLoginHelper;
|
||||
import com.gh.common.util.RunningUtils;
|
||||
import com.gh.common.util.SPUtils;
|
||||
import com.gh.common.util.ShareUtils;
|
||||
import com.gh.common.util.StringUtils;
|
||||
import com.gh.download.DownloadManager;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.LoginActivity;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.SplashScreenActivity;
|
||||
import com.gh.gamecenter.energy.EnergyCenterActivity;
|
||||
import com.gh.gamecenter.eventbus.EBShowDialog;
|
||||
import com.lightgame.BaseAppCompatActivity;
|
||||
import com.lightgame.download.DownloadEntity;
|
||||
import com.lightgame.download.FileUtils;
|
||||
import com.lightgame.utils.Util_System_Keyboard;
|
||||
import com.lightgame.utils.Utils;
|
||||
import com.tencent.tauth.Tencent;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.ButterKnife;
|
||||
import kotlin.Pair;
|
||||
import pub.devrel.easypermissions.EasyPermissions;
|
||||
|
||||
import static com.gh.common.util.EntranceUtils.KEY_ENTRANCE;
|
||||
|
||||
/**
|
||||
* 只提供基础的服务(EventBus/ButterKnife/Share/GlobalDialog/Permissions)
|
||||
* <p>
|
||||
* 需要工具栏的页面请继承{@link ToolBarActivity}
|
||||
*/
|
||||
|
||||
public abstract class BaseActivity extends BaseAppCompatActivity implements EasyPermissions.PermissionCallbacks, IBusiness {
|
||||
|
||||
// global dialog key
|
||||
public final static String DOWNLOAD_HIJACK = "hijack";
|
||||
public final static String LOGIN_EXCEPTION = "loginException";
|
||||
public final static String PLUGGABLE = "plugin";
|
||||
public final static String SIGNATURE_CONFLICT = "signature_conflict";
|
||||
public final static int ID_ROOT_INDICATOR = 999;
|
||||
public final int MAX_BUNDLE_SIZE = 300;
|
||||
|
||||
@NonNull
|
||||
protected String mEntrance;
|
||||
|
||||
private boolean mIsExistLogoutDialog;
|
||||
private boolean mHasAddTaskFloat = false;
|
||||
private View mTaskBackView;
|
||||
private WindowManager mWM;
|
||||
private WindowManager.LayoutParams mWmParams;
|
||||
|
||||
protected final Handler mBaseHandler = new BaseHandler(this);
|
||||
|
||||
protected static class BaseHandler extends Handler {
|
||||
|
||||
private final WeakReference<BaseActivity> mActivityWeakReference;
|
||||
|
||||
BaseHandler(BaseActivity activity) {
|
||||
mActivityWeakReference = new WeakReference<>(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
super.handleMessage(msg);
|
||||
BaseActivity activity = mActivityWeakReference.get();
|
||||
if (activity != null) activity.handleMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleMessage(Message msg) {
|
||||
|
||||
}
|
||||
|
||||
//接收QQ或者QQ空间分享回调
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
ExtensionsKt.tryCatchInRelease(() -> {
|
||||
if (requestCode == com.tencent.connect.common.Constants.REQUEST_QQ_SHARE
|
||||
|| requestCode == com.tencent.connect.common.Constants.REQUEST_QZONE_SHARE) {
|
||||
Tencent.onActivityResultData(requestCode, resultCode, data, ShareUtils.getInstance(this).QqShareListener);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (useEventBus()) EventBus.getDefault().register(this);
|
||||
if (useButterKnife()) ButterKnife.bind(this);
|
||||
mEntrance = getIntent().getStringExtra(KEY_ENTRANCE);
|
||||
if (TextUtils.isEmpty(mEntrance)) {
|
||||
mEntrance = Constants.ENTRANCE_UNKNOWN;
|
||||
}
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("ACTIVITY_ENTRANCE -> " + mEntrance);
|
||||
}
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
String xapkUnzipActivity = SPUtils.getString(Constants.SP_XAPK_UNZIP_ACTIVITY);
|
||||
String xapkUrl = SPUtils.getString(Constants.SP_XAPK_URL);
|
||||
Utils.log("页面重建了--" + xapkUnzipActivity + "--" + xapkUrl);
|
||||
if (this.getClass().getName().equals(SplashScreenActivity.class.getName())) {
|
||||
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "");
|
||||
SPUtils.setString(Constants.SP_XAPK_URL, "");
|
||||
return;
|
||||
}
|
||||
if (this.getClass().getName().equals(xapkUnzipActivity) && !TextUtils.isEmpty(xapkUrl)) {
|
||||
DownloadEntity downloadEntity = DownloadManager.getInstance(this).getDownloadEntityByUrl(xapkUrl);
|
||||
PackageInstaller.install(this, downloadEntity, false);
|
||||
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "");
|
||||
SPUtils.setString(Constants.SP_XAPK_URL, "");
|
||||
}
|
||||
}
|
||||
|
||||
if (this.getClass().getName().equals(EnergyCenterActivity.class.getName())) {
|
||||
SPUtils.setBoolean(Constants.SP_SHOW_TASK_FLOAT, false);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Override
|
||||
public void setContentView(View view) {
|
||||
if (BuildConfig.DEBUG || BuildConfig.BUILD_TIME != 0) {
|
||||
view = getRootViewWithEnvIndicator(view);
|
||||
}
|
||||
super.setContentView(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
if (useEventBus()) EventBus.getDefault().unregister(this);
|
||||
mBaseHandler.removeCallbacksAndMessages(null);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
public void toast(String msg) {
|
||||
Utils.toast(this, msg);
|
||||
}
|
||||
|
||||
public void toast(int msg) {
|
||||
toast(getString(msg));
|
||||
}
|
||||
|
||||
public void showShare(String url,
|
||||
String icon,
|
||||
String shareTitle,
|
||||
String shareSummary,
|
||||
ShareUtils.ShareEntrance shareEntrance, String id) {
|
||||
ShareUtils.getInstance(this).showShareWindows(this,
|
||||
getWindow().getDecorView(),
|
||||
url,
|
||||
icon,
|
||||
shareTitle,
|
||||
shareSummary,
|
||||
shareEntrance, id);
|
||||
if (shareEntrance == ShareUtils.ShareEntrance.game || shareEntrance == ShareUtils.ShareEntrance.plugin) {
|
||||
MtaHelper.onEvent("内容分享", "内容分享", shareTitle + shareSummary);
|
||||
} else {
|
||||
MtaHelper.onEvent("内容分享", "内容分享", shareTitle);
|
||||
}
|
||||
}
|
||||
|
||||
private View getRootViewWithEnvIndicator(View view) {
|
||||
RelativeLayout screenRootView = new RelativeLayout(this);
|
||||
screenRootView.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
|
||||
|
||||
LinearLayout ll = new LinearLayout(this);
|
||||
TextView tv = new TextView(this);
|
||||
String envText = "正式环境";
|
||||
tv.setBackground(ContextCompat.getDrawable(this, R.color.theme));
|
||||
if (BuildConfig.FLAVOR.equals("internal")) {
|
||||
envText = "测试环境";
|
||||
tv.setBackground(ContextCompat.getDrawable(this, R.color.red));
|
||||
}
|
||||
tv.setText(envText);
|
||||
tv.setGravity(Gravity.CENTER);
|
||||
tv.setTextColor(Color.WHITE);
|
||||
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13);
|
||||
tv.measure(0, 0);
|
||||
tv.setAlpha(0.15F);
|
||||
tv.setId(ID_ROOT_INDICATOR);
|
||||
int height = tv.getMeasuredHeight();
|
||||
int width = tv.getMeasuredWidth();
|
||||
tv.setPadding(DisplayUtils.dip2px(20), 0, DisplayUtils.dip2px(20), 0);
|
||||
ll.setTranslationX(DisplayUtils.dip2px(20));
|
||||
ll.setRotation(45);
|
||||
ll.addView(tv);
|
||||
ll.setPadding(0, (width - height) / 2, 0, (width - height) / 2);
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
tv.setOnLongClickListener(v -> {
|
||||
EntranceUtils.saveShortcut(this.getClass().getName(), getIntent().getExtras());
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
screenRootView.addView(view);
|
||||
screenRootView.addView(ll);
|
||||
|
||||
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) ll.getLayoutParams();
|
||||
lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
|
||||
view.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
|
||||
return screenRootView;
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onEventMainThread(final EBShowDialog showDialog) {
|
||||
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)
|
||||
&& this.getClass().getName().equals(RunningUtils.getTopActivity(this))) {
|
||||
if (DOWNLOAD_HIJACK.equals(showDialog.getType())) {
|
||||
DialogUtils.showQqSessionDialog(this);// 建议用户联系客服
|
||||
} else if (PLUGGABLE.equals(showDialog.getType())) {
|
||||
DialogHelper.showPluginDialog(this, () -> {
|
||||
if (FileUtils.isEmptyFile(showDialog.getPath())) {
|
||||
toast(R.string.install_failure_hint);
|
||||
} else {
|
||||
PackageInstaller.uninstall(BaseActivity.this, showDialog.getPath());
|
||||
}
|
||||
return null;
|
||||
});
|
||||
} else if (SIGNATURE_CONFLICT.equals(showDialog.getType())) {
|
||||
DialogHelper.showSignatureConflictDialog(this, () -> {
|
||||
PackageInstaller.uninstall(BaseActivity.this, showDialog.getPath());
|
||||
return null;
|
||||
});
|
||||
} else if (LOGIN_EXCEPTION.equals(showDialog.getType())) {
|
||||
if (mIsExistLogoutDialog) return;
|
||||
mIsExistLogoutDialog = true;
|
||||
try {
|
||||
JSONObject object = new JSONObject(showDialog.getPath());
|
||||
JSONObject device = object.getJSONObject("device");
|
||||
String model = device.getString("model");
|
||||
DialogUtils.showAlertDialog(this, "你的账号已在另外一台设备登录"
|
||||
, StringUtils.buildString("(", model, ")")
|
||||
, "知道了", "重新登录"
|
||||
, null
|
||||
, () -> {
|
||||
if (SPUtils.getBoolean(Constants.SP_HAS_GET_PHONE_INFO) || NetworkUtils.isOpenMobileData(BaseActivity.this)) {
|
||||
QuickLoginHelper.startLogin(BaseActivity.this, "你的账号已在另外一台设备登录多设备-重新登录");
|
||||
} else {
|
||||
startActivity(LoginActivity.getIntent(BaseActivity.this,
|
||||
"你的账号已在另外一台设备登录多设备-重新登录"));
|
||||
}
|
||||
}
|
||||
);
|
||||
mBaseHandler.postDelayed(() -> mIsExistLogoutDialog = false, 5000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
if (mWM != null && mTaskBackView != null && mHasAddTaskFloat) {
|
||||
mWM.removeView(mTaskBackView);
|
||||
mHasAddTaskFloat = false;
|
||||
}
|
||||
|
||||
if (isFinishing()) {
|
||||
onFinish();
|
||||
for (Fragment fragment : getSupportFragmentManager().getFragments()) {
|
||||
if (fragment.isAdded() && fragment instanceof BaseFragment) {
|
||||
((BaseFragment) fragment).onParentActivityFinish();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
if (SPUtils.getBoolean(Constants.SP_SHOW_TASK_FLOAT) && !this.getClass().getName().equals(EnergyCenterActivity.class.getName())) {
|
||||
addTaskBackView();
|
||||
mHasAddTaskFloat = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void addTaskBackView() {
|
||||
mWM = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
|
||||
mWmParams = new WindowManager.LayoutParams();
|
||||
mWmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION;
|
||||
mWmParams.format = PixelFormat.RGBA_8888;
|
||||
mWmParams.gravity = Gravity.LEFT | Gravity.BOTTOM;
|
||||
mWmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||||
mWmParams.width = DisplayUtils.dip2px(76F);
|
||||
mWmParams.height = DisplayUtils.dip2px(36F);
|
||||
mWmParams.y = SPUtils.getInt(Constants.SP_TASK_FLOAT_LAST_Y, DisplayUtils.dip2px(114F));
|
||||
mTaskBackView = View.inflate(this, R.layout.layout_task_back, null);
|
||||
mTaskBackView.setOnClickListener(v -> {
|
||||
// 如果当前是在键盘输入时,点击"返回任务"要先收起键盘
|
||||
Util_System_Keyboard.hideSoftKeyboard(this);
|
||||
startActivity(EnergyCenterActivity.Companion.getIntent(this));
|
||||
SPUtils.setBoolean(Constants.SP_SHOW_TASK_FLOAT, false);
|
||||
mWM.removeView(mTaskBackView);
|
||||
mHasAddTaskFloat = false;
|
||||
});
|
||||
setFloatTouchListener();
|
||||
mWM.addView(mTaskBackView, mWmParams);
|
||||
}
|
||||
|
||||
private void setFloatTouchListener() {
|
||||
int screenHeight = getResources().getDisplayMetrics().heightPixels;
|
||||
|
||||
mTaskBackView.setOnTouchListener(new View.OnTouchListener() {
|
||||
|
||||
private int intervalY;
|
||||
private int startY;
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
final int y = (int) event.getRawY();
|
||||
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
intervalY = y;
|
||||
startY = y;
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
mWmParams.y -= (y - intervalY);
|
||||
if (mWmParams.y < 0) {
|
||||
mWmParams.y = 0;
|
||||
}
|
||||
|
||||
if (mWmParams.y > screenHeight) {
|
||||
mWmParams.y = screenHeight;
|
||||
}
|
||||
|
||||
if (mWM != null && mTaskBackView != null && mHasAddTaskFloat) {
|
||||
mWM.updateViewLayout(mTaskBackView, mWmParams);
|
||||
}
|
||||
|
||||
intervalY = y;
|
||||
return true;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
// 滑动距离少于10视为点击,返回false,否则视为拖动,返回true
|
||||
if (Math.abs(y - startY) <= 10) {
|
||||
return false;
|
||||
} else {
|
||||
// 记录位置
|
||||
SPUtils.setInt(Constants.SP_TASK_FLOAT_LAST_Y, mWmParams.y);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 此回调可用于确认当前 activity 已经执行了 finish() 方法并处于 isFinishing 状态
|
||||
*/
|
||||
protected void onFinish() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode,
|
||||
@NonNull String[] permissions,
|
||||
@NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPermissionsDenied(int requestCode, List<String> perms) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPermissionsGranted(int requestCode, List<String> perms) {
|
||||
|
||||
}
|
||||
|
||||
protected void setStatusBarColor(int color) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
Window window = getWindow();
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
|
||||
window.setStatusBarColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提供当前 activity 的中文名 (不重载的话为类名)
|
||||
*/
|
||||
public String getActivityNameInChinese() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param entrance 上一个页面的链式入口名称
|
||||
* @param path 当前页面名称
|
||||
* @return 完整的链式入口名称
|
||||
*/
|
||||
public static String mergeEntranceAndPath(String entrance, String path) {
|
||||
if (TextUtils.isEmpty(entrance) && TextUtils.isEmpty(path)) return "";
|
||||
if (TextUtils.isEmpty(entrance) && !TextUtils.isEmpty(path)) {
|
||||
return StringUtils.buildString("(", path, ")");
|
||||
}
|
||||
if (!TextUtils.isEmpty(entrance) && TextUtils.isEmpty(path)) {
|
||||
return entrance;
|
||||
}
|
||||
return StringUtils.buildString(entrance, "+(", path, ")");
|
||||
}
|
||||
|
||||
protected boolean useEventBus() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean useButterKnife() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resources getResources() {
|
||||
Resources resources = super.getResources();
|
||||
if (resources.getConfiguration().fontScale != 1.0f) {
|
||||
Configuration configuration = resources.getConfiguration();
|
||||
configuration.fontScale = 1.0f;
|
||||
resources.updateConfiguration(configuration, resources.getDisplayMetrics());
|
||||
}
|
||||
return resources;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ActivityThread每次调用onSaveInstanceState时outState大小都会累加,最终会导致{@link TransactionTooLargeException}异常
|
||||
* 解决方案:判断每次获取到的outState大小,当达到300k时手动clear掉
|
||||
*/
|
||||
@Override
|
||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
|
||||
if (preventRecreateFragmentByFragmentManager()) {
|
||||
outState = discardFragmentFromSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
long bundleSize = getBundleSize(outState);
|
||||
if (bundleSize > MAX_BUNDLE_SIZE * 1024) {
|
||||
outState.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否停用 Activity 重建时 FragmentManager 根据 saveState 自动重建保存的 Fragment 的功能
|
||||
*/
|
||||
protected boolean preventRecreateFragmentByFragmentManager() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private Bundle discardFragmentFromSaveInstanceState(Bundle outState) {
|
||||
if (outState != null) {
|
||||
outState.remove("android:support:fragments");
|
||||
}
|
||||
return outState;
|
||||
}
|
||||
|
||||
private long getBundleSize(Bundle bundle) {
|
||||
long dataSize;
|
||||
Parcel obtain = Parcel.obtain();
|
||||
try {
|
||||
obtain.writeBundle(bundle);
|
||||
dataSize = obtain.dataSize();
|
||||
} finally {
|
||||
obtain.recycle();
|
||||
}
|
||||
return dataSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<String, String> getBusinessId() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -1,133 +0,0 @@
|
||||
package com.gh.base;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import com.gh.base.adapter.FragmentAdapter;
|
||||
import com.gh.base.fragment.BaseFragment_TabLayout;
|
||||
import com.gh.common.view.TabIndicatorView;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.lightgame.view.NoScrollableViewPager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import butterknife.BindView;
|
||||
|
||||
/**
|
||||
* Created by khy on 15/03/18.
|
||||
*/
|
||||
|
||||
public abstract class BaseActivity_TabLayout extends ToolBarActivity implements ViewPager.OnPageChangeListener {
|
||||
|
||||
public static final String PAGE_INDEX = "PAGE_INDEX";
|
||||
|
||||
@BindView(R.id.activity_tab_layout)
|
||||
protected TabLayout mTabLayout;
|
||||
@BindView(R.id.activity_view_pager)
|
||||
protected NoScrollableViewPager mViewPager;
|
||||
@BindView(R.id.activity_tab_indicator)
|
||||
protected TabIndicatorView mTabIndicatorView;
|
||||
|
||||
protected List<Fragment> mFragmentsList;
|
||||
|
||||
protected List<String> mTabTitleList;
|
||||
|
||||
protected int mCheckedIndex = 0;
|
||||
|
||||
protected abstract void initFragmentList(List<Fragment> fragments);
|
||||
|
||||
protected abstract void initTabTitleList(List<String> tabTitleList);
|
||||
|
||||
protected int provideIndicatorWidth() {
|
||||
return 20;
|
||||
}
|
||||
|
||||
protected View provideTabView(int position, String tabTitle) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getLayoutId() {
|
||||
return R.layout.activity_tablayout_viewpager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
List<Fragment> fragments = getSupportFragmentManager().getFragments();
|
||||
if (fragments != null) {
|
||||
for (Fragment fragment : fragments) {
|
||||
fragment.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (getIntent() != null) mCheckedIndex = getIntent().getIntExtra(PAGE_INDEX, 0);
|
||||
mTabTitleList = new ArrayList<>();
|
||||
initTabTitleList(mTabTitleList);
|
||||
mFragmentsList = new ArrayList<>(restoreFragments());
|
||||
if (mFragmentsList.isEmpty() || mFragmentsList.size() != mTabTitleList.size()) {
|
||||
mFragmentsList.clear();
|
||||
initFragmentList(mFragmentsList);
|
||||
}
|
||||
|
||||
mViewPager.setOffscreenPageLimit(mFragmentsList.size());
|
||||
mViewPager.addOnPageChangeListener(this);
|
||||
mViewPager.setAdapter(new FragmentAdapter(getSupportFragmentManager(), mFragmentsList, mTabTitleList));
|
||||
mViewPager.setCurrentItem(mCheckedIndex);
|
||||
mTabLayout.setupWithViewPager(mViewPager);
|
||||
mTabIndicatorView.setupWithTabLayout(mTabLayout);
|
||||
mTabIndicatorView.setupWithViewPager(mViewPager);
|
||||
mTabIndicatorView.setIndicatorWidth(provideIndicatorWidth());
|
||||
|
||||
for (int i = 0; i < mTabLayout.getTabCount(); i++) {
|
||||
TabLayout.Tab tab = mTabLayout.getTabAt(i);
|
||||
if (tab == null) continue;
|
||||
String tabTitle = tab.getText() != null ? tab.getText().toString() : "";
|
||||
View tabView = provideTabView(i, tabTitle);
|
||||
if (tabView == null)
|
||||
tabView = BaseFragment_TabLayout.createDefaultTabCustomView(tabTitle);
|
||||
tab.setCustomView(tabView);
|
||||
}
|
||||
|
||||
BaseFragment_TabLayout.initTabStyle(mTabLayout, mCheckedIndex);
|
||||
}
|
||||
|
||||
private ArrayList<Fragment> restoreFragments() {
|
||||
String tag = "android:switcher:" + mViewPager.getId() + ":";
|
||||
ArrayList<Fragment> fragments = new ArrayList<>();
|
||||
int childCount = mTabTitleList.size();
|
||||
for (int index = 0; index < childCount; index++) {
|
||||
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag + index);
|
||||
if (fragment != null) {
|
||||
fragments.add(fragment);
|
||||
}
|
||||
}
|
||||
|
||||
return fragments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
package com.gh.base
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.ClipboardManager
|
||||
@ -9,70 +10,85 @@ import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import android.webkit.JavascriptInterface
|
||||
import android.widget.CheckBox
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import butterknife.OnClick
|
||||
import com.gh.common.AppExecutor
|
||||
import com.gh.common.util.*
|
||||
import androidx.lifecycle.Observer
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.common.view.RichEditor
|
||||
import com.gh.gamecenter.CropImageActivity
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.entity.MyVideoEntity
|
||||
import com.gh.gamecenter.qa.article.edit.ArticleEditActivity
|
||||
import com.gh.gamecenter.qa.editor.GameActivity
|
||||
import com.gh.gamecenter.qa.editor.InsertAnswerWrapperActivity
|
||||
import com.gh.gamecenter.qa.editor.InsertArticleWrapperActivity
|
||||
import com.gh.gamecenter.qa.editor.VideoActivity
|
||||
import com.gh.gamecenter.common.base.activity.ToolBarActivity
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.AppExecutor
|
||||
import com.gh.gamecenter.core.runOnIoThread
|
||||
import com.gh.gamecenter.core.utils.*
|
||||
import com.gh.gamecenter.entity.*
|
||||
import com.gh.gamecenter.qa.editor.*
|
||||
import com.gh.gamecenter.qa.entity.AnswerEntity
|
||||
import com.gh.gamecenter.qa.entity.ArticleEntity
|
||||
import com.gh.gamecenter.qa.entity.EditorInsertEntity
|
||||
import com.gh.gamecenter.video.poster.PosterEditActivity
|
||||
import com.gh.gamecenter.video.upload.UploadManager
|
||||
import com.google.gson.JsonObject
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Util_System_Keyboard
|
||||
import com.lightgame.utils.Utils
|
||||
import com.lightgame.view.CheckableImageView
|
||||
import kotterknife.bindView
|
||||
import io.reactivex.disposables.Disposable
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import java.io.File
|
||||
|
||||
abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
// TODO: 移动到module_bbs模块
|
||||
abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> : ToolBarActivity(),
|
||||
KeyboardHeightObserver, UploadVideoListener {
|
||||
|
||||
val mRichEditor by bindView<RichEditor>(R.id.rich_editor)
|
||||
lateinit var mRichEditor: RichEditor
|
||||
|
||||
private val mEditorTextNumTv by bindView<TextView>(R.id.editorTextNumTv)
|
||||
private val mEditorFont by bindView<CheckableImageView>(R.id.editor_font)
|
||||
private val mEditorLink by bindView<CheckableImageView>(R.id.editor_link)
|
||||
private lateinit var mEditorTextNumTv: TextView
|
||||
private lateinit var mEditorFont: CheckableImageView
|
||||
private lateinit var mEditorLink: CheckableImageView
|
||||
|
||||
private val mEditorFontBold by bindView<CheckableImageView>(R.id.editor_font_bold)
|
||||
private val mEditorFontItalic by bindView<CheckableImageView>(R.id.editor_font_italic)
|
||||
private val mEditorFontStrikeThrough by bindView<CheckableImageView>(R.id.editor_font_strikethrough)
|
||||
private val mEditorFontUnderline by bindView<CheckableImageView>(R.id.editor_font_underline)
|
||||
private val mEditorParagraphH1 by bindView<CheckableImageView>(R.id.editor_paragraph_h1)
|
||||
private val mEditorParagraphH2 by bindView<CheckableImageView>(R.id.editor_paragraph_h2)
|
||||
private val mEditorParagraphH3 by bindView<CheckableImageView>(R.id.editor_paragraph_h3)
|
||||
private val mEditorParagraphH4 by bindView<CheckableImageView>(R.id.editor_paragraph_h4)
|
||||
private val mEditorParagraphQuote by bindView<CheckableImageView>(R.id.editor_paragraph_quote)
|
||||
private val mEditorFontContainer by bindView<View>(R.id.editor_font_container)
|
||||
private val mEditorParagraphContainer by bindView<View>(R.id.editor_paragraph_container)
|
||||
private val mEditorLinkContainer by bindView<View>(R.id.editor_link_container)
|
||||
private val mEditorInsertDetailContainer by bindView<View>(R.id.editor_insert_detail_container)
|
||||
val mAddLabelContainer by bindView<View>(R.id.add_label_container)
|
||||
val mAddLabelTv by bindView<TextView>(R.id.add_label_tv)
|
||||
val mLabelNumTv by bindView<TextView>(R.id.label_num_tv)
|
||||
val mLabelArrowIv by bindView<ImageView>(R.id.label_arrow)
|
||||
val mTagsContainer by bindView<FrameLayout>(R.id.tagsContainer)
|
||||
private lateinit var mEditorFontBold: CheckableImageView
|
||||
private lateinit var mEditorFontItalic: CheckableImageView
|
||||
private lateinit var mEditorFontStrikeThrough: CheckableImageView
|
||||
private lateinit var mEditorFontUnderline: CheckableImageView
|
||||
private lateinit var mEditorParagraphH1: CheckableImageView
|
||||
private lateinit var mEditorParagraphH2: CheckableImageView
|
||||
private lateinit var mEditorParagraphH3: CheckableImageView
|
||||
private lateinit var mEditorParagraphH4: CheckableImageView
|
||||
private lateinit var mEditorParagraphQuote: CheckableImageView
|
||||
private lateinit var mEditorFontContainer: View
|
||||
private lateinit var mEditorParagraphContainer: View
|
||||
private lateinit var mEditorLinkContainer: View
|
||||
private lateinit var mEditorInsertDetailContainer: View
|
||||
private lateinit var mTagsContainer: FrameLayout
|
||||
private lateinit var mUploadVideoGuideContainer: View
|
||||
protected lateinit var mOriginalCb: CheckBox
|
||||
private lateinit var mOriginalTipsContainer: View
|
||||
private lateinit var mOriginalTipsClose: TextView
|
||||
|
||||
private var mCurrentParagraphStyle = ""
|
||||
private var mIsExtendedKeyboardShow = false
|
||||
|
||||
private var mAgreePostPic: Boolean = false
|
||||
private var mGuideDisposable: Disposable? = null
|
||||
protected lateinit var mViewModel: VM
|
||||
protected var mIsKeyBoardShow = false
|
||||
private var mKeyboardHeightProvider: KeyboardHeightProvider? = null
|
||||
private var mMaxUploadVideoGuideCount = 2
|
||||
val FILE_HOST = "file:///"
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
DialogUtils.fixWebViewKeyboardNotWorking(this)
|
||||
if (resultCode != Activity.RESULT_OK) return
|
||||
var insertData: EditorInsertEntity? = null
|
||||
val insertData: EditorInsertEntity?
|
||||
when (requestCode) {
|
||||
INSERT_ANSWER_CODE -> {
|
||||
val answer = data?.getParcelableExtra<AnswerEntity>(AnswerEntity::class.java.simpleName)
|
||||
val answer =
|
||||
data?.getParcelableExtra<AnswerEntity>(AnswerEntity::class.java.simpleName)
|
||||
if (answer != null) {
|
||||
mRichEditor.focusEditor()
|
||||
insertData = EditorInsertEntity.transform(answer)
|
||||
@ -80,7 +96,8 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
}
|
||||
}
|
||||
INSERT_ARTICLE_CODE -> {
|
||||
val article = data?.getParcelableExtra<ArticleEntity>(ArticleEntity::class.java.simpleName)
|
||||
val article =
|
||||
data?.getParcelableExtra<ArticleEntity>(ArticleEntity::class.java.simpleName)
|
||||
if (article != null) {
|
||||
mRichEditor.focusEditor()
|
||||
insertData = EditorInsertEntity.transform(article)
|
||||
@ -95,11 +112,39 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
mRichEditor.insertCustomStyleLink(insertData)
|
||||
}
|
||||
}
|
||||
VideoActivity.INSERT_VIDEO_CODE -> {
|
||||
val video = data?.getParcelableExtra<MyVideoEntity>(MyVideoEntity::class.java.simpleName)
|
||||
if (video != null) {
|
||||
INSERT_GAME_COLLECTION_CODE -> {
|
||||
val gameCollectionEntity =
|
||||
data?.getParcelableExtra<GamesCollectionEntity>(GamesCollectionEntity::class.java.simpleName)
|
||||
if (gameCollectionEntity != null) {
|
||||
mRichEditor.focusEditor()
|
||||
mRichEditor.insertCustomVideo(video)
|
||||
insertData = EditorInsertEntity.transform(gameCollectionEntity)
|
||||
mRichEditor.insertCustomStyleLink(insertData)
|
||||
}
|
||||
}
|
||||
REQUEST_CODE_IMAGE -> {
|
||||
if (data != null) mViewModel.uploadPic(data)
|
||||
}
|
||||
INSERT_MEDIA_VIDEO_CODE -> {
|
||||
val localVideoList =
|
||||
data?.getParcelableArrayListExtra<LocalVideoEntity>(LocalVideoEntity::class.java.name)
|
||||
?: arrayListOf()
|
||||
if (localVideoList.isNotEmpty()) {
|
||||
mRichEditor.focusEditor()
|
||||
uploadVideo(localVideoList)
|
||||
}
|
||||
}
|
||||
REQUEST_CODE_IMAGE_CROP -> {
|
||||
val imagePath = data?.getStringExtra(CropImageActivity.RESULT_CLIP_PATH)
|
||||
if (!imagePath.isNullOrEmpty()) {
|
||||
mViewModel.uploadPoster(imagePath)
|
||||
}
|
||||
}
|
||||
INSERT_VIDEO_CODE -> {
|
||||
val videoEntity = data?.getParcelableExtra<MyVideoEntity>(MyVideoEntity::class.java.simpleName)
|
||||
if (videoEntity != null) {
|
||||
mRichEditor.focusEditor()
|
||||
insertData = EditorInsertEntity.transform(videoEntity)
|
||||
mRichEditor.insertCustomStyleLink(insertData)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -107,19 +152,82 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
AppExecutor.uiExecutor.executeWithDelay(Runnable {
|
||||
Util_System_Keyboard.showSoftKeyboard(this)
|
||||
}, 100)
|
||||
}
|
||||
|
||||
private fun uploadVideo(localVideoList: ArrayList<LocalVideoEntity>) {
|
||||
mViewModel.localVideoList.addAll(localVideoList)
|
||||
runOnIoThread {
|
||||
localVideoList.forEach {
|
||||
if (it.poster.startsWith("http")) {
|
||||
runOnUiThread {
|
||||
mRichEditor.focusEditor()
|
||||
mRichEditor.insertPlaceholderVideo(it.id, it.poster)
|
||||
}
|
||||
} else {
|
||||
val videoThumbnail = BitmapUtils.getVideoThumbnail(it.filePath)
|
||||
val filePath = "${cacheDir.absolutePath}${File.separator}${it.id}.webp"
|
||||
BitmapUtils.saveBitmap(videoThumbnail, filePath)
|
||||
it.poster = filePath
|
||||
runOnUiThread {
|
||||
mRichEditor.focusEditor()
|
||||
mRichEditor.insertPlaceholderVideo(it.id, "$FILE_HOST${it.poster}")
|
||||
}
|
||||
}
|
||||
}
|
||||
mViewModel.uploadVideo()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun findView() {
|
||||
mRichEditor = findViewById(R.id.rich_editor)
|
||||
mEditorTextNumTv = findViewById(R.id.editorTextNumTv)
|
||||
mEditorFont = findViewById(R.id.editor_font)
|
||||
mEditorLink = findViewById(R.id.editor_link)
|
||||
mEditorFontBold = findViewById(R.id.editor_font_bold)
|
||||
mEditorFontItalic = findViewById(R.id.editor_font_italic)
|
||||
mEditorFontStrikeThrough = findViewById(R.id.editor_font_strikethrough)
|
||||
mEditorFontUnderline = findViewById(R.id.editor_font_underline)
|
||||
mEditorParagraphH1 = findViewById(R.id.editor_paragraph_h1)
|
||||
mEditorParagraphH2 = findViewById(R.id.editor_paragraph_h2)
|
||||
mEditorParagraphH3 = findViewById(R.id.editor_paragraph_h3)
|
||||
mEditorParagraphH4 = findViewById(R.id.editor_paragraph_h4)
|
||||
mEditorParagraphQuote = findViewById(R.id.editor_paragraph_quote)
|
||||
mEditorFontContainer = findViewById(R.id.editor_font_container)
|
||||
mEditorParagraphContainer = findViewById(R.id.editor_paragraph_container)
|
||||
mEditorLinkContainer = findViewById(R.id.editor_link_container)
|
||||
mEditorInsertDetailContainer = findViewById(R.id.editor_insert_detail_container)
|
||||
mTagsContainer = findViewById(R.id.tagsContainer)
|
||||
mUploadVideoGuideContainer = findViewById(R.id.uploadVideoGuideContainer)
|
||||
mOriginalCb = findViewById(R.id.originalCb)
|
||||
mOriginalTipsContainer = findViewById(R.id.originalTipsContainer)
|
||||
mOriginalTipsClose = findViewById(R.id.originalTipsClose)
|
||||
}
|
||||
|
||||
@SuppressLint("AddJavascriptInterface", "ClickableViewAccessibility")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
mAddLabelContainer.visibility = if (this is ArticleEditActivity) View.VISIBLE else View.GONE
|
||||
mRichEditor.setPadding(20, 15, 20, 15)
|
||||
findView()
|
||||
onRichClick()
|
||||
mViewModel = provideViewModel()
|
||||
mViewModel.setUploadVideoListener(this)
|
||||
mKeyboardHeightProvider = KeyboardHeightProvider(this)
|
||||
mRichEditor.post { mKeyboardHeightProvider?.start() }
|
||||
mRichEditor.enableForceDark(DarkModeUtils.isDarkModeOn(this))
|
||||
// 防止个别手机在Js里无法获取粘贴内容
|
||||
mRichEditor.addJavascriptInterface(OnPasteListener(), "onPasteListener")
|
||||
mRichEditor.addJavascriptInterface(OnCursorChangeListener(), "OnCursorChangeListener")
|
||||
mRichEditor.addJavascriptInterface(OnEditorTextChangeListener(), "OnEditorTextChangeListener")
|
||||
mRichEditor.addJavascriptInterface(
|
||||
OnEditorTextChangeListener(),
|
||||
"OnEditorTextChangeListener"
|
||||
)
|
||||
mRichEditor.addJavascriptInterface(OnVideoListener(), "onVideoListener")
|
||||
mRichEditor.addJavascriptInterface(
|
||||
OnQuoteCountChangeListener(),
|
||||
"OnQuoteCountChangeListener"
|
||||
)
|
||||
mRichEditor.setInputEnabled(true)
|
||||
mRichEditor.setPadding(16, 12, 16, 12)
|
||||
|
||||
mRichEditor.setOnTouchListener { _, _ ->
|
||||
if (mIsExtendedKeyboardShow) {
|
||||
@ -129,14 +237,46 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
mRichEditor.hasFocus()
|
||||
} else false
|
||||
}
|
||||
mOriginalCb.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (isChecked) {
|
||||
mOriginalTipsContainer.alpha = 0f
|
||||
mOriginalTipsContainer.visibility = View.VISIBLE
|
||||
ObjectAnimator.ofFloat(mOriginalTipsContainer, "alpha", 0f, 1f).setDuration(200).start()
|
||||
}
|
||||
}
|
||||
observeData()
|
||||
}
|
||||
|
||||
private fun observeData() {
|
||||
mViewModel.chooseImagesUpload.observe(this, Observer {
|
||||
mRichEditor.focusEditor()
|
||||
for (key in it.keys) {
|
||||
mRichEditor.insertPlaceholderImage(key)
|
||||
}
|
||||
})
|
||||
mViewModel.chooseImagesUploadSuccess.observe(this, Observer {
|
||||
val jsonArray = JSONArray()
|
||||
for (key in it.keys) {
|
||||
val jsonObject = JSONObject()
|
||||
jsonObject.put("id", key)
|
||||
jsonObject.put("url", it[key])
|
||||
jsonArray.put(jsonObject)
|
||||
}
|
||||
mRichEditor.replacePlaceholderImage(jsonArray.toString())
|
||||
})
|
||||
}
|
||||
|
||||
override fun onKeyboardHeightChanged(height: Int, orientation: Int) {
|
||||
mIsKeyBoardShow = height > 0
|
||||
if (height > 0) {
|
||||
closeExtendedKeyboard()
|
||||
}
|
||||
}
|
||||
|
||||
fun closeExtendedKeyboard() {
|
||||
mEditorInsertDetailContainer.visibility = View.GONE
|
||||
mEditorFont.isChecked = false
|
||||
mEditorLink.isChecked = false
|
||||
mAddLabelContainer.isSelected = false
|
||||
mIsExtendedKeyboardShow = false
|
||||
}
|
||||
|
||||
@ -144,155 +284,221 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
mEditorFont.isEnabled = isEnabled
|
||||
}
|
||||
|
||||
fun changeAddLabel(isLabelContainerShow: Boolean) {
|
||||
if (isLabelContainerShow) {
|
||||
mLabelNumTv.visibility = View.GONE
|
||||
mLabelArrowIv.visibility = View.VISIBLE
|
||||
mAddLabelTv.setTextColor(ContextCompat.getColor(this, R.color.theme_font))
|
||||
mAddLabelTv.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null)
|
||||
mAddLabelContainer.background = ContextCompat.getDrawable(this, R.drawable.bg_editor_insert_add_label)
|
||||
} else {
|
||||
val selectedLabel = getSelectedLabel()
|
||||
if (selectedLabel == 0) {
|
||||
mAddLabelTv.text = "添加标签"
|
||||
mLabelNumTv.visibility = View.GONE
|
||||
mAddLabelTv.setTextColor(ContextCompat.getColor(this, R.color.text_666666))
|
||||
mAddLabelTv.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(this, R.drawable.ic_add_label), null, null, null)
|
||||
} else {
|
||||
mAddLabelTv.text = "标签"
|
||||
mLabelNumTv.visibility = View.VISIBLE
|
||||
mLabelNumTv.text = selectedLabel.toString()
|
||||
mAddLabelTv.setTextColor(ContextCompat.getColor(this, R.color.theme_font))
|
||||
mAddLabelTv.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null)
|
||||
private fun onRichClick() {
|
||||
mEditorFont.setOnClickListener {
|
||||
controlEditorFontContainer()
|
||||
}
|
||||
mEditorLink.setOnClickListener {
|
||||
controlEditorLinkContainer()
|
||||
}
|
||||
mEditorFontBold.setOnClickListener {
|
||||
mEditorFontBold.isChecked = !mEditorFontBold.isChecked
|
||||
mRichEditor.setBold()
|
||||
if (mEditorFontBold.isChecked) {
|
||||
MtaHelper.onEvent(mtaEventName(), "文字样式", "文字样式-加粗")
|
||||
}
|
||||
mLabelArrowIv.visibility = View.GONE
|
||||
mAddLabelContainer.background = ContextCompat.getDrawable(this, R.drawable.border_round_stroke_eee_999)
|
||||
}
|
||||
mEditorFontItalic.setOnClickListener {
|
||||
mEditorFontItalic.isChecked = !mEditorFontItalic.isChecked
|
||||
mRichEditor.setItalic()
|
||||
if (mEditorFontItalic.isChecked) {
|
||||
MtaHelper.onEvent(mtaEventName(), "文字样式", "文字样式-斜体")
|
||||
}
|
||||
}
|
||||
mEditorFontStrikeThrough.setOnClickListener {
|
||||
mEditorFontStrikeThrough.isChecked = !mEditorFontStrikeThrough.isChecked
|
||||
mRichEditor.setStrikeThrough()
|
||||
|
||||
if (mEditorFontStrikeThrough.isChecked) {
|
||||
MtaHelper.onEvent(mtaEventName(), "文字样式", "文字样式-删除线")
|
||||
}
|
||||
}
|
||||
mEditorFontUnderline.setOnClickListener {
|
||||
mEditorFontUnderline.isChecked = !mEditorFontUnderline.isChecked
|
||||
mRichEditor.setUnderline()
|
||||
|
||||
if (mEditorFontUnderline.isChecked) {
|
||||
MtaHelper.onEvent(mtaEventName(), "文字样式", "文字样式-下滑线")
|
||||
}
|
||||
}
|
||||
mEditorParagraphH1.setOnClickListener {
|
||||
if (mEditorParagraphH1.isChecked) {
|
||||
mRichEditor.formatBlock()
|
||||
} else {
|
||||
MtaHelper.onEvent(mtaEventName(), "段落样式", "段落样式-1级标题")
|
||||
mRichEditor.setHeading(1)
|
||||
}
|
||||
mEditorParagraphH1.isChecked = !mEditorParagraphH1.isChecked
|
||||
}
|
||||
mEditorParagraphH2.setOnClickListener {
|
||||
if (mEditorParagraphH2.isChecked) {
|
||||
mRichEditor.formatBlock()
|
||||
} else {
|
||||
MtaHelper.onEvent(mtaEventName(), "段落样式", "段落样式-2级标题")
|
||||
mRichEditor.setHeading(2)
|
||||
}
|
||||
mEditorParagraphH2.isChecked = !mEditorParagraphH2.isChecked
|
||||
}
|
||||
mEditorParagraphH3.setOnClickListener {
|
||||
if (mEditorParagraphH3.isChecked) {
|
||||
mRichEditor.formatBlock()
|
||||
} else {
|
||||
MtaHelper.onEvent(mtaEventName(), "段落样式", "段落样式-3级标题")
|
||||
mRichEditor.setHeading(3)
|
||||
}
|
||||
mEditorParagraphH3.isChecked = !mEditorParagraphH3.isChecked
|
||||
}
|
||||
mEditorParagraphH4.setOnClickListener {
|
||||
if (mEditorParagraphH4.isChecked) {
|
||||
mRichEditor.formatBlock()
|
||||
} else {
|
||||
MtaHelper.onEvent(mtaEventName(), "段落样式", "段落样式-4级标题")
|
||||
mRichEditor.setHeading(4)
|
||||
}
|
||||
mEditorParagraphH4.isChecked = !mEditorParagraphH4.isChecked
|
||||
}
|
||||
mEditorParagraphQuote.setOnClickListener {
|
||||
if (mEditorParagraphQuote.isChecked) {
|
||||
mRichEditor.formatBlock()
|
||||
} else {
|
||||
MtaHelper.onEvent(mtaEventName(), "段落样式", "段落样式-引用")
|
||||
mRichEditor.setBlockquote()
|
||||
}
|
||||
mEditorParagraphQuote.isChecked = !mEditorParagraphQuote.isChecked
|
||||
}
|
||||
findViewById<View>(R.id.editor_link_answer).setOnClickListener {
|
||||
MtaHelper.onEvent(mtaEventName(), "插入链接", "插入链接-回答")
|
||||
startActivityForResult(
|
||||
InsertAnswerWrapperActivity.getIntent(this),
|
||||
INSERT_ANSWER_CODE
|
||||
)
|
||||
}
|
||||
findViewById<View>(R.id.editor_link_article).setOnClickListener {
|
||||
MtaHelper.onEvent(mtaEventName(), "插入链接", "插入链接-文章")
|
||||
startActivityForResult(
|
||||
InsertArticleWrapperActivity.getIntent(this),
|
||||
INSERT_ARTICLE_CODE
|
||||
)
|
||||
}
|
||||
findViewById<View>(R.id.editor_link_game).setOnClickListener {
|
||||
MtaHelper.onEvent(mtaEventName(), "插入链接", "插入链接-游戏")
|
||||
startActivityForResult(
|
||||
GameActivity.getIntent(this, GameActivity.INSERT_GAME_TITLE),
|
||||
INSERT_GAME_CODE
|
||||
)
|
||||
}
|
||||
findViewById<View>(R.id.editor_link_video).setOnClickListener {
|
||||
startActivityForResult(
|
||||
InsertVideoWrapperActivity.getIntent(this),
|
||||
INSERT_VIDEO_CODE
|
||||
)
|
||||
}
|
||||
findViewById<View>(R.id.editor_link_game_collection).setOnClickListener {
|
||||
startActivityForResult(
|
||||
InsertGameCollectionWrapperActivity.getIntent(this),
|
||||
INSERT_GAME_COLLECTION_CODE
|
||||
)
|
||||
}
|
||||
findViewById<View>(R.id.editor_video).setOnClickListener {
|
||||
chooseVideo()
|
||||
}
|
||||
findViewById<View>(R.id.editor_image).setOnClickListener {
|
||||
if (!mAgreePostPic && !NetworkUtils.isWifiOr4GOr3GConnected(this)) {
|
||||
mAgreePostPic = true
|
||||
DialogHelper.showDialog(
|
||||
this,
|
||||
"警告",
|
||||
"当前使用移动网络,上传图片会消耗手机流量",
|
||||
"我知道了", "", { chooseImage() },
|
||||
extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
return@setOnClickListener
|
||||
}
|
||||
chooseImage()
|
||||
NewLogUtils.logChooseMedia(
|
||||
"view_media",
|
||||
if (mtaEventName() == "提问帖") "提问帖" else "帖子",
|
||||
"图片"
|
||||
)
|
||||
}
|
||||
findViewById<View>(R.id.uploadVideoGuideClose).setOnClickListener {
|
||||
hideUploadVideoGuide()
|
||||
if (mGuideDisposable != null && !mGuideDisposable!!.isDisposed) {
|
||||
mGuideDisposable!!.dispose()
|
||||
mGuideDisposable = null
|
||||
}
|
||||
}
|
||||
findViewById<View>(R.id.originalTipsClose).setOnClickListener {
|
||||
val animator = ObjectAnimator.ofFloat(mOriginalTipsContainer, "alpha", 1f, 0f).setDuration(200)
|
||||
animator.doOnEnd {
|
||||
mOriginalTipsContainer.visibility = View.GONE
|
||||
}
|
||||
animator.start()
|
||||
}
|
||||
}
|
||||
|
||||
open fun getSelectedLabel(): Int = 0
|
||||
private fun chooseVideo() {
|
||||
MtaHelper.onEvent(mtaEventName(), "插入链接", "插入链接-视频")
|
||||
val videoCount = mViewModel.quoteCountEntity.videoCount
|
||||
if (videoCount >= MAX_MEDIA_COUNT) {
|
||||
toast(R.string.answer_edit_max_video_hint)
|
||||
return
|
||||
}
|
||||
try {
|
||||
PermissionHelper.checkStoragePermissionBeforeAction(this,
|
||||
object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
val maxChooseCount = if (videoCount + 3 <= MAX_MEDIA_COUNT) 3 else MAX_MEDIA_COUNT - videoCount
|
||||
startActivityForResult(
|
||||
LocalMediaActivity.getIntent(
|
||||
this@BaseRichEditorActivity,
|
||||
LocalMediaActivity.ChooseType.VIDEO,
|
||||
maxChooseCount,
|
||||
if (mtaEventName() == "提问帖") "发提问帖" else "发帖子"
|
||||
), INSERT_MEDIA_VIDEO_CODE
|
||||
)
|
||||
NewLogUtils.logChooseMedia(
|
||||
"view_media",
|
||||
if (mtaEventName() == "提问帖") "提问帖" else "帖子",
|
||||
"视频"
|
||||
)
|
||||
}
|
||||
})
|
||||
} catch (e: Exception) {
|
||||
toast(R.string.media_image_hint)
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@OnClick(R.id.editor_image, R.id.editor_font, R.id.editor_link, R.id.add_label_container, R.id.editor_font_underline,
|
||||
R.id.editor_font_bold, R.id.editor_font_italic, R.id.editor_font_strikethrough,
|
||||
R.id.editor_paragraph_h1, R.id.editor_paragraph_h2, R.id.editor_paragraph_h3,
|
||||
R.id.editor_paragraph_h4, R.id.editor_font_container, R.id.editor_paragraph_container,
|
||||
R.id.editor_paragraph_quote, R.id.editor_link_answer, R.id.editor_link_article,
|
||||
R.id.editor_link_game, R.id.editor_link_video)
|
||||
fun onRichClick(view: View) {
|
||||
when (view.id) {
|
||||
R.id.editor_font -> {
|
||||
controlEditorFontContainer()
|
||||
}
|
||||
R.id.editor_link -> {
|
||||
controlEditorLinkContainer()
|
||||
}
|
||||
R.id.add_label_container -> {
|
||||
controlAddLabelContainer()
|
||||
}
|
||||
R.id.editor_font_bold -> {
|
||||
mEditorFontBold.isChecked = !mEditorFontBold.isChecked
|
||||
mRichEditor.setBold()
|
||||
if (mEditorFontBold.isChecked) {
|
||||
MtaHelper.onEvent(mtaEventName(), "文字样式", "文字样式-加粗")
|
||||
private fun chooseImage() {
|
||||
MtaHelper.onEvent(mtaEventName(), "插入图片", "插入图片")
|
||||
val imageCount = mViewModel.quoteCountEntity.imageCount
|
||||
if (imageCount >= MAX_MEDIA_COUNT) {
|
||||
toast(R.string.answer_edit_max_img_hint)
|
||||
return
|
||||
}
|
||||
try {
|
||||
PermissionHelper.checkStoragePermissionBeforeAction(this, object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
val maxChooseCount = if (imageCount + 10 <= MAX_MEDIA_COUNT) 10 else MAX_MEDIA_COUNT - imageCount
|
||||
val intent = LocalMediaActivity.getIntent(
|
||||
this@BaseRichEditorActivity,
|
||||
LocalMediaActivity.ChooseType.IMAGE,
|
||||
maxChooseCount,
|
||||
if (mtaEventName() == "提问帖") "发提问帖" else "发帖子"
|
||||
)
|
||||
startActivityForResult(intent, REQUEST_CODE_IMAGE)
|
||||
}
|
||||
}
|
||||
R.id.editor_font_italic -> {
|
||||
mEditorFontItalic.isChecked = !mEditorFontItalic.isChecked
|
||||
mRichEditor.setItalic()
|
||||
if (mEditorFontItalic.isChecked) {
|
||||
MtaHelper.onEvent(mtaEventName(), "文字样式", "文字样式-斜体")
|
||||
}
|
||||
}
|
||||
R.id.editor_font_strikethrough -> {
|
||||
mEditorFontStrikeThrough.isChecked = !mEditorFontStrikeThrough.isChecked
|
||||
mRichEditor.setStrikeThrough()
|
||||
|
||||
if (mEditorFontStrikeThrough.isChecked) {
|
||||
MtaHelper.onEvent(mtaEventName(), "文字样式", "文字样式-删除线")
|
||||
}
|
||||
}
|
||||
R.id.editor_font_underline -> {
|
||||
mEditorFontUnderline.isChecked = !mEditorFontUnderline.isChecked
|
||||
mRichEditor.setUnderline()
|
||||
|
||||
if (mEditorFontUnderline.isChecked) {
|
||||
MtaHelper.onEvent(mtaEventName(), "文字样式", "文字样式-下滑线")
|
||||
}
|
||||
}
|
||||
R.id.editor_paragraph_h1 -> {
|
||||
if (mEditorParagraphH1.isChecked) {
|
||||
mRichEditor.formatBlock()
|
||||
} else {
|
||||
MtaHelper.onEvent(mtaEventName(), "段落样式", "段落样式-1级标题")
|
||||
mRichEditor.setHeading(1)
|
||||
}
|
||||
mEditorParagraphH1.isChecked = !mEditorParagraphH1.isChecked
|
||||
}
|
||||
R.id.editor_paragraph_h2 -> {
|
||||
if (mEditorParagraphH2.isChecked) {
|
||||
mRichEditor.formatBlock()
|
||||
} else {
|
||||
MtaHelper.onEvent(mtaEventName(), "段落样式", "段落样式-2级标题")
|
||||
mRichEditor.setHeading(2)
|
||||
}
|
||||
mEditorParagraphH2.isChecked = !mEditorParagraphH2.isChecked
|
||||
}
|
||||
R.id.editor_paragraph_h3 -> {
|
||||
if (mEditorParagraphH3.isChecked) {
|
||||
mRichEditor.formatBlock()
|
||||
} else {
|
||||
MtaHelper.onEvent(mtaEventName(), "段落样式", "段落样式-3级标题")
|
||||
mRichEditor.setHeading(3)
|
||||
}
|
||||
mEditorParagraphH3.isChecked = !mEditorParagraphH3.isChecked
|
||||
}
|
||||
R.id.editor_paragraph_h4 -> {
|
||||
if (mEditorParagraphH4.isChecked) {
|
||||
mRichEditor.formatBlock()
|
||||
} else {
|
||||
MtaHelper.onEvent(mtaEventName(), "段落样式", "段落样式-4级标题")
|
||||
mRichEditor.setHeading(4)
|
||||
}
|
||||
mEditorParagraphH4.isChecked = !mEditorParagraphH4.isChecked
|
||||
}
|
||||
R.id.editor_paragraph_quote -> {
|
||||
if (mEditorParagraphQuote.isChecked) {
|
||||
mRichEditor.formatBlock()
|
||||
} else {
|
||||
MtaHelper.onEvent(mtaEventName(), "段落样式", "段落样式-引用")
|
||||
mRichEditor.setBlockquote()
|
||||
}
|
||||
mEditorParagraphQuote.isChecked = !mEditorParagraphQuote.isChecked
|
||||
}
|
||||
R.id.editor_link_answer -> {
|
||||
MtaHelper.onEvent(mtaEventName(), "插入链接", "插入链接-回答")
|
||||
startActivityForResult(InsertAnswerWrapperActivity.getIntent(this), INSERT_ANSWER_CODE)
|
||||
}
|
||||
R.id.editor_link_article -> {
|
||||
MtaHelper.onEvent(mtaEventName(), "插入链接", "插入链接-文章")
|
||||
startActivityForResult(InsertArticleWrapperActivity.getIntent(this), INSERT_ARTICLE_CODE)
|
||||
}
|
||||
R.id.editor_link_game -> {
|
||||
MtaHelper.onEvent(mtaEventName(), "插入链接", "插入链接-游戏")
|
||||
startActivityForResult(GameActivity.getIntent(this, GameActivity.INSERT_GAME_TITLE), INSERT_GAME_CODE)
|
||||
}
|
||||
R.id.editor_link_video -> {
|
||||
PermissionHelper.checkStoragePermissionBeforeAction(this,
|
||||
object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
MtaHelper.onEvent(mtaEventName(), "插入链接", "插入链接-视频")
|
||||
startActivityForResult(VideoActivity.getIntent(this@BaseRichEditorActivity), VideoActivity.INSERT_VIDEO_CODE)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
} catch (e: Exception) {
|
||||
toast(R.string.media_image_hint)
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
private fun controlEditorFontContainer() {
|
||||
mEditorFont.isChecked = !mEditorFont.isChecked
|
||||
mEditorLink.isChecked = false
|
||||
mAddLabelContainer.isSelected = false
|
||||
val isShouldDelay = if (mEditorFont.isChecked) {
|
||||
Util_System_Keyboard.hideSoftKeyboard(this)
|
||||
true
|
||||
@ -301,20 +507,20 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
false
|
||||
}
|
||||
mEditorInsertDetailContainer.postDelayed({
|
||||
mEditorInsertDetailContainer.visibility = if (mEditorFont.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorInsertDetailContainer.visibility =
|
||||
if (mEditorFont.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorFontContainer.visibility = if (mEditorFont.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorParagraphContainer.visibility = if (mEditorFont.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorParagraphContainer.visibility =
|
||||
if (mEditorFont.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorLinkContainer.visibility = View.GONE
|
||||
mTagsContainer.visibility = View.GONE
|
||||
mIsExtendedKeyboardShow = mEditorFont.isChecked
|
||||
changeAddLabel(false)
|
||||
}, if (isShouldDelay) 200 else 0L)
|
||||
}
|
||||
|
||||
private fun controlEditorLinkContainer() {
|
||||
mEditorLink.isChecked = !mEditorLink.isChecked
|
||||
mEditorFont.isChecked = false
|
||||
mAddLabelContainer.isSelected = false
|
||||
val isShouldDelay = if (mEditorLink.isChecked) {
|
||||
Util_System_Keyboard.hideSoftKeyboard(this)
|
||||
true
|
||||
@ -323,38 +529,16 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
false
|
||||
}
|
||||
mEditorInsertDetailContainer.postDelayed({
|
||||
mEditorInsertDetailContainer.visibility = if (mEditorLink.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorInsertDetailContainer.visibility =
|
||||
if (mEditorLink.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorLinkContainer.visibility = if (mEditorLink.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorFontContainer.visibility = View.GONE
|
||||
mEditorParagraphContainer.visibility = View.GONE
|
||||
mTagsContainer.visibility = View.GONE
|
||||
mIsExtendedKeyboardShow = mEditorLink.isChecked
|
||||
changeAddLabel(false)
|
||||
}, if (isShouldDelay) 200 else 0L)
|
||||
}
|
||||
|
||||
fun controlAddLabelContainer() {
|
||||
mEditorLink.isChecked = false
|
||||
mEditorFont.isChecked = false
|
||||
mAddLabelContainer.isSelected = !mAddLabelContainer.isSelected
|
||||
val isShouldDelay = if (mAddLabelContainer.isSelected) {
|
||||
Util_System_Keyboard.hideSoftKeyboard(this)
|
||||
changeAddLabel(true)
|
||||
true
|
||||
} else {
|
||||
Util_System_Keyboard.showSoftKeyboard(this)
|
||||
changeAddLabel(false)
|
||||
false
|
||||
}
|
||||
mEditorInsertDetailContainer.postDelayed({
|
||||
mEditorInsertDetailContainer.visibility = if (mAddLabelContainer.isSelected) View.VISIBLE else View.GONE
|
||||
mTagsContainer.visibility = if (mAddLabelContainer.isSelected) View.VISIBLE else View.GONE
|
||||
mEditorLinkContainer.visibility = View.GONE
|
||||
mEditorFontContainer.visibility = View.GONE
|
||||
mEditorParagraphContainer.visibility = View.GONE
|
||||
mIsExtendedKeyboardShow = mAddLabelContainer.isSelected
|
||||
}, if (isShouldDelay) 200 else 0L)
|
||||
}
|
||||
|
||||
override fun handleBackPressed(): Boolean {
|
||||
if (mIsExtendedKeyboardShow) {
|
||||
@ -364,6 +548,53 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
return super.handleBackPressed()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
mKeyboardHeightProvider?.setKeyboardHeightObserver(this)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
mKeyboardHeightProvider?.setKeyboardHeightObserver(null)
|
||||
}
|
||||
|
||||
//视频上传功能引导
|
||||
fun showUploadVideoGuide() {
|
||||
mUploadVideoGuideContainer.postDelayed({
|
||||
val count = SPUtils.getInt(getVideoGuideKey(), 0)
|
||||
if (count >= mMaxUploadVideoGuideCount) return@postDelayed
|
||||
mUploadVideoGuideContainer.alpha = 0f
|
||||
mUploadVideoGuideContainer.visibility = View.VISIBLE
|
||||
mUploadVideoGuideContainer.animate().alpha(1f).setDuration(200).start()
|
||||
mGuideDisposable = countDownTimer(3) { finish, _ ->
|
||||
if (finish) {
|
||||
hideUploadVideoGuide()
|
||||
}
|
||||
}
|
||||
SPUtils.setInt(getVideoGuideKey(), count + 1)
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
fun hideUploadVideoGuide() {
|
||||
val animate = mUploadVideoGuideContainer.animate().alpha(0f).setDuration(200)
|
||||
animate.doOnEnd {
|
||||
mUploadVideoGuideContainer.visibility = View.GONE
|
||||
}
|
||||
animate.start()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
mKeyboardHeightProvider?.close()
|
||||
val path = mViewModel.currentUploadingVideo?.filePath
|
||||
if (path != null && UploadManager.isUploading(path)) {
|
||||
UploadManager.cancelTask(path)
|
||||
}
|
||||
if (mGuideDisposable != null && !mGuideDisposable!!.isDisposed) {
|
||||
mGuideDisposable!!.dispose()
|
||||
mGuideDisposable = null
|
||||
}
|
||||
}
|
||||
|
||||
private inner class OnCursorChangeListener {
|
||||
@JavascriptInterface
|
||||
@ -397,11 +628,12 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
@JavascriptInterface
|
||||
fun onPaste() {
|
||||
val clipboard =
|
||||
HaloApp.getInstance().application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
HaloApp.getInstance().application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clipText = clipboard.text.toString()
|
||||
if (!TextUtils.isEmpty(clipText)) {
|
||||
// 替换换行符号否则 插入失败
|
||||
val text = clipText.replace("[ ]".toRegex(), " ").replace("[\r\n]".toRegex(), "<br/>")
|
||||
val text = clipText.replace("[ ]".toRegex(), " ")
|
||||
.replace("[\r\n]".toRegex(), "<br/>")
|
||||
mBaseHandler.post { mRichEditor.insertHtml(text) }
|
||||
}
|
||||
}
|
||||
@ -413,11 +645,112 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
val num = if (count > MAX_INPUT_TEXT_NUM) MAX_INPUT_TEXT_NUM - count else count
|
||||
mEditorTextNumTv.post {
|
||||
mEditorTextNumTv.text = num.toString()
|
||||
mViewModel.quoteCountEntity.textCount = num
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inner class OnQuoteCountChangeListener {
|
||||
@JavascriptInterface
|
||||
fun onQuoteCountChange(
|
||||
imageCount: Int,
|
||||
articleCount: Int,
|
||||
answerCount: Int,
|
||||
videoCount: Int,
|
||||
gameCount: Int
|
||||
) {
|
||||
mEditorTextNumTv.post {
|
||||
mViewModel.quoteCountEntity.apply {
|
||||
this.imageCount = imageCount
|
||||
this.articleCount = articleCount
|
||||
this.answerCount = answerCount
|
||||
this.videoCount = videoCount
|
||||
this.gameCount = gameCount
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inner class OnVideoListener {
|
||||
@JavascriptInterface
|
||||
fun showDeleteDialog(id: String) {
|
||||
DialogHelper.showDialog(this@BaseRichEditorActivity, "提示", "确定删除吗?", "确定", "取消", {
|
||||
runOnUiThread {
|
||||
mRichEditor.delPlaceholderVideo(id)
|
||||
mViewModel.deleteVideo(id)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun updatePoster(id: String, videoId: String, url: String) {
|
||||
mViewModel.id = id
|
||||
mViewModel.videoId = videoId
|
||||
val videoEntity = VideoEntity(url = url)
|
||||
val intent =
|
||||
PosterEditActivity.getIntentByVideo(this@BaseRichEditorActivity, videoEntity)
|
||||
startActivityForResult(intent, REQUEST_CODE_IMAGE_CROP)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun deleteUploadingVideo(id: String) {
|
||||
mViewModel.deleteVideo(id)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun reUploadVideo(id: String) {
|
||||
val video = mViewModel.uploadVideoErrorList.find { it.id == id }
|
||||
if (video != null) {
|
||||
mViewModel.localVideoList.add(video)
|
||||
mViewModel.uploadVideoErrorList.remove(video)
|
||||
mViewModel.uploadVideo()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun insertPlaceholderVideo(id: String, poster: String) {
|
||||
mRichEditor.insertPlaceholderVideo(id, poster)
|
||||
}
|
||||
|
||||
override fun updateVideoProgress(id: String, progress: String) {
|
||||
mRichEditor.updateVideoProgress(id, progress)
|
||||
}
|
||||
|
||||
override fun videoUploadFinished(id: String, url: String, msg: JsonObject) {
|
||||
try {
|
||||
val obj = JSONObject()
|
||||
obj.put("poster", msg.get("poster").asString)
|
||||
obj.put("url", msg.get("url").asString)
|
||||
obj.put("duration", RichEditor.formatVideoDuration(msg.get("length").asLong))
|
||||
obj.put("id", msg.get("_id").asString)
|
||||
obj.put("status", "pending")
|
||||
mRichEditor.videoUploadFinished(id, url, obj.toString())
|
||||
} catch (e: java.lang.Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
override fun changePoster(id: String, poster: String) {
|
||||
mRichEditor.changePoster(id, poster)
|
||||
}
|
||||
|
||||
override fun videoUploadFailed(id: String) {
|
||||
mRichEditor.videoUploadFailed(id)
|
||||
}
|
||||
|
||||
open fun getSelectedLabel(): Int = 0
|
||||
open fun onActivityDialogResult(requestCode: Int, resultCode: Int, data: Intent?) {}
|
||||
abstract fun mtaEventName(): String
|
||||
abstract fun provideViewModel(): VM
|
||||
abstract fun getVideoGuideKey(): String
|
||||
|
||||
override fun isAutoResetViewBackgroundEnabled(): Boolean = true
|
||||
|
||||
override fun onDarkModeChanged() {
|
||||
super.onDarkModeChanged()
|
||||
updateStatusBarColor(R.color.background_white, R.color.background_white)
|
||||
mRichEditor.enableForceDark(DarkModeUtils.isDarkModeOn(this))
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ELEMENT_NAME_BOLD = " b "
|
||||
@ -433,6 +766,13 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
const val INSERT_ANSWER_CODE = 411
|
||||
const val INSERT_ARTICLE_CODE = 412
|
||||
const val INSERT_GAME_CODE = 413
|
||||
const val INSERT_GAME_COLLECTION_CODE = 414
|
||||
const val INSERT_VIDEO_CODE = 415
|
||||
const val MAX_INPUT_TEXT_NUM = 10000
|
||||
const val MAX_MEDIA_COUNT = 20
|
||||
|
||||
const val REQUEST_CODE_IMAGE = 120
|
||||
const val INSERT_MEDIA_VIDEO_CODE = 121
|
||||
const val REQUEST_CODE_IMAGE_CROP = 122
|
||||
}
|
||||
}
|
||||
448
app/src/main/java/com/gh/base/BaseRichEditorViewModel.kt
Normal file
448
app/src/main/java/com/gh/base/BaseRichEditorViewModel.kt
Normal file
@ -0,0 +1,448 @@
|
||||
package com.gh.base
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.media.ThumbnailUtils
|
||||
import android.provider.MediaStore
|
||||
import android.text.TextUtils
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.MediatorLiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.gh.gamecenter.common.base.fragment.WaitingDialogFragment
|
||||
import com.gh.gamecenter.core.runOnUiThread
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.*
|
||||
import com.gh.gamecenter.entity.ErrorEntity
|
||||
import com.gh.gamecenter.entity.LocalVideoEntity
|
||||
import com.gh.gamecenter.entity.QuoteCountEntity
|
||||
import com.gh.gamecenter.qa.BbsType
|
||||
import com.gh.gamecenter.common.retrofit.Response
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.gh.gamecenter.retrofit.service.ApiService
|
||||
import com.gh.gamecenter.video.upload.OnUploadListener
|
||||
import com.gh.gamecenter.video.upload.UploadManager
|
||||
import com.google.gson.JsonObject
|
||||
import com.lightgame.utils.Utils
|
||||
import com.zhihu.matisse.Matisse
|
||||
import com.zhihu.matisse.internal.utils.PathUtils
|
||||
import io.reactivex.disposables.Disposable
|
||||
import okhttp3.ResponseBody
|
||||
import retrofit2.HttpException
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.collections.LinkedHashMap
|
||||
import kotlin.collections.List
|
||||
import kotlin.collections.Map
|
||||
import kotlin.collections.find
|
||||
import kotlin.collections.forEach
|
||||
import kotlin.collections.set
|
||||
|
||||
// TODO: 移动到module_bbs模块
|
||||
abstract class BaseRichEditorViewModel(application: Application) : AndroidViewModel(application) {
|
||||
val mApi: ApiService = RetrofitManager.getInstance().api
|
||||
val processDialog = MediatorLiveData<WaitingDialogFragment.WaitingDialogData>()
|
||||
val uploadingImage = ArrayList<LinkedHashMap<String, String>>()
|
||||
val chooseImagesUpload = MutableLiveData<LinkedHashMap<String, String>>()
|
||||
val chooseImagesUploadSuccess = MutableLiveData<LinkedHashMap<String, String>>()
|
||||
var uploadImageSubscription: Disposable? = null
|
||||
val mapImages = HashMap<String, String>()
|
||||
val localVideoList = ArrayList<LocalVideoEntity>()
|
||||
val uploadVideoErrorList = ArrayList<LocalVideoEntity>()
|
||||
var currentUploadingVideo: LocalVideoEntity? = null
|
||||
var type: String = "" //游戏论坛:game_bbs 官方论坛:official_bbs
|
||||
private var mUploadVideoListener: UploadVideoListener? = null
|
||||
val TITLE_MIN_LENGTH = 6
|
||||
val MIN_TEXT_LENGTH = 6
|
||||
val MAX_TEXT_LENGTH = 10000
|
||||
val FILE_HOST = "file:///"
|
||||
var id = ""//视频标记
|
||||
var videoId = ""//更改封面视频id
|
||||
val quoteCountEntity = QuoteCountEntity()//数据上报用
|
||||
|
||||
fun setUploadVideoListener(uploadVideoListener: UploadVideoListener) {
|
||||
this.mUploadVideoListener = uploadVideoListener
|
||||
}
|
||||
|
||||
//检查图片是否符合规则并上传图片
|
||||
fun uploadPic(data: Intent) {
|
||||
val uris = Matisse.obtainResult(data)
|
||||
val pictureList = ArrayList<String>()
|
||||
for (uri in uris) {
|
||||
val picturePath = PathUtils.getPath(getApplication(), uri)
|
||||
if (picturePath != null) {
|
||||
if (File(picturePath).length() > ImageUtils.getUploadFileMaxSize()) {
|
||||
val count = ImageUtils.getUploadFileMaxSize() / 1024 / 1024
|
||||
val application: Application = getApplication()
|
||||
Utils.toast(
|
||||
getApplication(),
|
||||
application.getString(R.string.pic_max_hint, count)
|
||||
)
|
||||
continue
|
||||
}
|
||||
Utils.log("picturePath = $picturePath")
|
||||
pictureList.add(picturePath)
|
||||
} else {
|
||||
Utils.log("picturePath is null")
|
||||
}
|
||||
}
|
||||
if (pictureList.size == 0) return
|
||||
val imageType = when (getRichType()) {
|
||||
RichType.ARTICLE -> UploadImageUtils.UploadType.community_article
|
||||
RichType.QUESTION -> UploadImageUtils.UploadType.question
|
||||
else -> UploadImageUtils.UploadType.poster
|
||||
}
|
||||
uploadImageSubscription = UploadImageUtils.compressAndUploadImageList(
|
||||
imageType,
|
||||
pictureList,
|
||||
false,
|
||||
object : UploadImageUtils.OnUploadImageListListener {
|
||||
override fun onProgress(total: Long, progress: Long) {}
|
||||
|
||||
override fun onCompressSuccess(imageUrls: List<String>) {
|
||||
val chooseImageMd5Map = LinkedHashMap<String, String>()
|
||||
imageUrls.forEach {
|
||||
chooseImageMd5Map[MD5Utils.getUrlMD5(it)] = ""
|
||||
}
|
||||
uploadingImage.add(chooseImageMd5Map)
|
||||
chooseImagesUpload.postValue(chooseImageMd5Map)
|
||||
}
|
||||
|
||||
override fun onSingleSuccess(imageUrl: Map<String, String>) {
|
||||
val map = LinkedHashMap<String, String>()
|
||||
for (key in imageUrl.keys) {
|
||||
map[MD5Utils.getUrlMD5(key)] = FILE_HOST + key.decodeURI()
|
||||
mapImages[TextUtils.htmlEncode(key).decodeURI()] = imageUrl[key] ?: ""
|
||||
}
|
||||
chooseImagesUploadSuccess.postValue(map)
|
||||
}
|
||||
|
||||
override fun onSuccess(
|
||||
imageUrl: LinkedHashMap<String, String>,
|
||||
errorMap: Map<String, Exception>
|
||||
) {
|
||||
val uploadMap = uploadingImage.find {
|
||||
it.containsKey(
|
||||
MD5Utils.getUrlMD5(
|
||||
imageUrl.entries.iterator().next().key
|
||||
)
|
||||
)
|
||||
}
|
||||
uploadMap?.let {
|
||||
uploadingImage.remove(uploadMap)
|
||||
}
|
||||
|
||||
val errorSize = pictureList.size - imageUrl.size
|
||||
if (errorSize > 0) {
|
||||
val map = LinkedHashMap<String, String>()
|
||||
for (key in errorMap.keys) {
|
||||
map[MD5Utils.getUrlMD5(key)] = ""
|
||||
}
|
||||
//value为空会删除PlaceholderImage
|
||||
chooseImagesUploadSuccess.postValue(map)
|
||||
|
||||
for (error in errorMap.values) {
|
||||
if (error is HttpException && error.code() == 403) {
|
||||
Utils.toast(getApplication(), errorSize.toString() + "张违规图片上传失败")
|
||||
return
|
||||
}
|
||||
}
|
||||
Utils.toast(getApplication(), errorSize.toString() + "张图片上传失败")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(errorMap: Map<String, Exception>) {
|
||||
val errorSize = errorMap.size
|
||||
if (errorSize > 0) {
|
||||
val map = LinkedHashMap<String, String>()
|
||||
for (key in errorMap.keys) {
|
||||
map[MD5Utils.getUrlMD5(key)] = ""
|
||||
}
|
||||
//value为空会删除PlaceholderImage
|
||||
chooseImagesUploadSuccess.postValue(map)
|
||||
}
|
||||
|
||||
for (error in errorMap.values) {
|
||||
if (error is HttpException && error.code() == 403) {
|
||||
val e = error.response()?.errorBody()?.string()?.toObject<ErrorEntity>()
|
||||
if (e != null && e.code == 403017) {
|
||||
Utils.toast(
|
||||
getApplication(),
|
||||
errorSize.toString() + "张图片的宽或高超过限制,请裁剪后上传"
|
||||
)
|
||||
} else {
|
||||
Utils.toast(getApplication(), errorSize.toString() + "张违规图片上传失败")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
if (errorSize == 1) {
|
||||
Utils.toast(getApplication(), "图片上传失败")
|
||||
} else {
|
||||
Utils.toast(getApplication(), errorSize.toString() + "张图片上传失败")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun uploadPoster(picturePath: String) {
|
||||
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("封面上传中...", true))
|
||||
uploadImageSubscription =
|
||||
UploadImageUtils.compressAndUploadImage(
|
||||
UploadImageUtils.UploadType.poster,
|
||||
picturePath,
|
||||
false,
|
||||
object : UploadImageUtils.OnUploadImageListener {
|
||||
override fun onSuccess(imageUrl: String) {
|
||||
patchVideoPoster(imageUrl)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable?) {
|
||||
handleUploadPosterResult(true)
|
||||
}
|
||||
|
||||
override fun onProgress(total: Long, progress: Long) {
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun patchVideoPoster(poster: String) {
|
||||
if (id.isEmpty() || videoId.isEmpty()) return
|
||||
val map = hashMapOf("poster" to poster, "type" to getVideoType())
|
||||
mApi.patchInsertVideo(videoId, map.toRequestBody())
|
||||
.compose(observableToMain())
|
||||
.subscribe(object : Response<ResponseBody>() {
|
||||
override fun onResponse(response: ResponseBody?) {
|
||||
super.onResponse(response)
|
||||
mUploadVideoListener?.changePoster(id, poster)
|
||||
handleUploadPosterResult(false)
|
||||
}
|
||||
|
||||
override fun onFailure(e: HttpException?) {
|
||||
super.onFailure(e)
|
||||
handleUploadPosterResult(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun handleUploadPosterResult(isFailure: Boolean = false) {
|
||||
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("封面上传中...", false))
|
||||
if (isFailure) {
|
||||
ToastUtils.showToast("封面更改失败")
|
||||
}
|
||||
id = ""
|
||||
videoId = ""
|
||||
}
|
||||
|
||||
fun deleteVideo(id: String) {
|
||||
if (localVideoList.isNotEmpty()) {
|
||||
val video = localVideoList.find { it.id == id }
|
||||
if (video != null) {
|
||||
if (UploadManager.isUploading(video.filePath)) {
|
||||
UploadManager.cancelTask(video.filePath)
|
||||
}
|
||||
localVideoList.remove(video)
|
||||
}
|
||||
}
|
||||
if (uploadVideoErrorList.isNotEmpty()) {
|
||||
val video = uploadVideoErrorList.find { it.id == id }
|
||||
if (video != null) {
|
||||
uploadVideoErrorList.remove(video)
|
||||
}
|
||||
}
|
||||
if (currentUploadingVideo?.id == id) {
|
||||
currentUploadingVideo = null
|
||||
uploadVideo()
|
||||
}
|
||||
}
|
||||
|
||||
fun uploadVideo() {
|
||||
if (currentUploadingVideo != null) return
|
||||
if (localVideoList.isEmpty()) return
|
||||
currentUploadingVideo = localVideoList[0]
|
||||
UploadManager.createUploadTask(currentUploadingVideo?.filePath
|
||||
?: "", object : OnUploadListener {
|
||||
override fun onProgressChanged(
|
||||
uploadFilePath: String,
|
||||
currentSize: Long,
|
||||
totalSize: Long,
|
||||
speed: Long
|
||||
) {
|
||||
runOnUiThread {
|
||||
val percent = (currentSize * 100 / totalSize.toFloat()).roundTo(1)
|
||||
currentUploadingVideo?.id?.let {
|
||||
mUploadVideoListener?.updateVideoProgress(it, percent.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUploadSuccess(uploadFilePath: String, url: String) {
|
||||
if (currentUploadingVideo != null) {
|
||||
postVideoPosterAndInfo(uploadFilePath, url)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUploadFailure(uploadFilePath: String, errorMsg: String) {
|
||||
uploadVideoFailure()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun postVideoPosterAndInfo(uploadFilePath: String, url: String) {
|
||||
val localVideoPoster =
|
||||
getApplication<Application>().cacheDir.absolutePath + File.separator + System.currentTimeMillis() + ".jpg"
|
||||
try {
|
||||
val bmp = ThumbnailUtils.createVideoThumbnail(
|
||||
uploadFilePath,
|
||||
MediaStore.Images.Thumbnails.MINI_KIND
|
||||
)
|
||||
// bmp 可能为空
|
||||
FileOutputStream(localVideoPoster).use { out ->
|
||||
bmp?.compress(Bitmap.CompressFormat.PNG, 100, out)
|
||||
}
|
||||
} catch (e: java.lang.Exception) {
|
||||
e.printStackTrace()
|
||||
ToastUtils.showToast("视频封面操作失败")
|
||||
uploadVideoFailure()
|
||||
return
|
||||
}
|
||||
uploadImageSubscription =
|
||||
UploadImageUtils.compressAndUploadImage(
|
||||
UploadImageUtils.UploadType.poster,
|
||||
localVideoPoster,
|
||||
false,
|
||||
object : UploadImageUtils.OnUploadImageListener {
|
||||
override fun onSuccess(imageUrl: String) {
|
||||
postVideoInfo(url, imageUrl)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable?) {
|
||||
uploadVideoFailure()
|
||||
}
|
||||
|
||||
override fun onProgress(total: Long, progress: Long) {
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun postVideoInfo(url: String, poster: String) {
|
||||
val map = HashMap<String, Any>().apply {
|
||||
put("poster", poster)
|
||||
put("url", url)
|
||||
put("format", currentUploadingVideo?.format ?: "")
|
||||
put("size", currentUploadingVideo?.size ?: 0)
|
||||
put("length", (currentUploadingVideo?.duration ?: 0) / 1000)
|
||||
put("type", getVideoType())
|
||||
}
|
||||
val requestBody = map.toRequestBody()
|
||||
mApi.insertVideo(requestBody)
|
||||
.compose(observableToMain())
|
||||
.subscribe(object : Response<JsonObject>() {
|
||||
override fun onResponse(response: JsonObject?) {
|
||||
super.onResponse(response)
|
||||
if (response != null) {
|
||||
uploadVideoSuccess(poster, url, response)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(e: HttpException?) {
|
||||
super.onFailure(e)
|
||||
uploadVideoFailure()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun uploadVideoSuccess(poster: String, url: String, data: JsonObject) {
|
||||
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("封面上传中...", false))
|
||||
currentUploadingVideo?.let {
|
||||
mUploadVideoListener?.changePoster(it.id, poster)
|
||||
mUploadVideoListener?.videoUploadFinished(it.id, url, data)
|
||||
UploadManager.cancelTask(it.filePath)
|
||||
localVideoList.remove(it)
|
||||
}
|
||||
currentUploadingVideo = null
|
||||
uploadVideo()
|
||||
}
|
||||
|
||||
private fun uploadVideoFailure() {
|
||||
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("封面上传中...", false))
|
||||
currentUploadingVideo?.let {
|
||||
runOnUiThread {
|
||||
mUploadVideoListener?.videoUploadFailed(it.id)
|
||||
}
|
||||
uploadVideoErrorList.add(it)
|
||||
localVideoList.remove(it)
|
||||
UploadManager.cancelTask(it.filePath)
|
||||
}
|
||||
currentUploadingVideo = null
|
||||
uploadVideo()
|
||||
}
|
||||
|
||||
fun checkIsAllUploadedAndToast(): Boolean {
|
||||
if (localVideoList.isNotEmpty() || uploadVideoErrorList.isNotEmpty()) {
|
||||
ToastUtils.showToast("视频未上传完成,视频内容保存失败")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun getVideoType(): String {
|
||||
return when (type) {
|
||||
BbsType.GAME_BBS.value -> {
|
||||
when (getRichType()) {
|
||||
RichType.ARTICLE -> BbsType.GAME_BBS_ARTICLE_INSERT.value
|
||||
RichType.QUESTION -> BbsType.GAME_BBS_QUESTION_INSERT.value
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
BbsType.OFFICIAL_BBS.value -> {
|
||||
when (getRichType()) {
|
||||
RichType.ARTICLE -> BbsType.OFFICIAL_BBS_ARTICLE_INSERT.value
|
||||
RichType.QUESTION -> BbsType.OFFICIAL_BBS_QUESTION_INSERT.value
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun getRichType(): RichType
|
||||
}
|
||||
|
||||
interface UploadVideoListener {
|
||||
/**
|
||||
* 插入视频占位图
|
||||
*/
|
||||
fun insertPlaceholderVideo(id: String, poster: String)
|
||||
|
||||
/**
|
||||
* 更新视频进度条
|
||||
*/
|
||||
fun updateVideoProgress(id: String, progress: String)
|
||||
|
||||
/**
|
||||
* 上传视频完成
|
||||
*/
|
||||
fun videoUploadFinished(id: String, url: String, msg: JsonObject)
|
||||
|
||||
/**
|
||||
* 更换封面图
|
||||
*/
|
||||
fun changePoster(id: String, poster: String)
|
||||
|
||||
/**
|
||||
* 上传失败
|
||||
*/
|
||||
fun videoUploadFailed(id: String)
|
||||
}
|
||||
|
||||
enum class RichType {
|
||||
ARTICLE,
|
||||
QUESTION,
|
||||
ANSWER
|
||||
}
|
||||
86
app/src/main/java/com/gh/base/DarkModeSwitchHelper.kt
Normal file
86
app/src/main/java/com/gh/base/DarkModeSwitchHelper.kt
Normal file
@ -0,0 +1,86 @@
|
||||
package com.gh.base
|
||||
|
||||
import android.view.Gravity
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.DarkModeUtils
|
||||
import com.gh.gamecenter.common.utils.DialogHelper
|
||||
import com.gh.gamecenter.common.utils.PackageFlavorHelper
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.lzf.easyfloat.EasyFloat
|
||||
import com.lzf.easyfloat.enums.ShowPattern
|
||||
import com.lzf.easyfloat.enums.SidePattern
|
||||
|
||||
object DarkModeSwitchHelper {
|
||||
|
||||
fun showDarkModeSwitchFloatingView(activity: AppCompatActivity) {
|
||||
if (PackageFlavorHelper.IS_TEST_FLAVOR) {
|
||||
EasyFloat.with(activity)
|
||||
.setLayout(R.layout.layout_day_mode_night_mode_switch)
|
||||
.setTag("night_mode_switch_floating_view")
|
||||
.setAnimator(null)
|
||||
.setGravity(Gravity.TOP.xor(Gravity.END), 0, 114F.dip2px())
|
||||
.setSidePattern(SidePattern.RESULT_SIDE)
|
||||
.setDragEnable(true)
|
||||
.setShowPattern(ShowPattern.CURRENT_ACTIVITY)
|
||||
.registerCallback {
|
||||
createResult { _, _, view ->
|
||||
view?.setOnClickListener {
|
||||
showDarkModeSwitchDialog(activity)
|
||||
}
|
||||
}
|
||||
}
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
fun dismissDarkModeSwitchFloatingView() {
|
||||
if (PackageFlavorHelper.IS_TEST_FLAVOR) {
|
||||
EasyFloat.dismiss("night_mode_switch_floating_view")
|
||||
}
|
||||
}
|
||||
|
||||
private fun showDarkModeSwitchDialog(activity: AppCompatActivity) {
|
||||
if (PackageFlavorHelper.IS_TEST_FLAVOR) {
|
||||
//切换深色模式
|
||||
var mode = "普通模式"
|
||||
var positive = "跟随系统模式"
|
||||
var negative = "深色模式"
|
||||
if (DarkModeUtils.isFollowSystemDarkModeFromSp()) {
|
||||
mode = "跟随系统模式"
|
||||
positive = "普通模式"
|
||||
negative = "深色模式"
|
||||
} else if (DarkModeUtils.isAppDarkModeEnabledFromSp()) {
|
||||
mode = "深色模式"
|
||||
positive = "跟随系统模式"
|
||||
negative = "普通模式"
|
||||
}
|
||||
DialogHelper.showDialog(
|
||||
context = activity,
|
||||
title = "选择模式",
|
||||
content = "当前为 $mode",
|
||||
confirmText = positive,
|
||||
cancelText = negative,
|
||||
confirmClickCallback = {
|
||||
if (DarkModeUtils.isFollowSystemDarkModeFromSp()) {
|
||||
DarkModeUtils.updateAppDarkModeStatusToSp(false)
|
||||
DarkModeUtils.updateFollowSystemDarkModeToSp(false)
|
||||
} else {
|
||||
DarkModeUtils.updateFollowSystemDarkModeToSp(true)
|
||||
}
|
||||
DarkModeUtils.initDarkMode()
|
||||
},
|
||||
cancelClickCallback = {
|
||||
if (DarkModeUtils.isFollowSystemDarkModeFromSp()) {
|
||||
DarkModeUtils.updateAppDarkModeStatusToSp(true)
|
||||
} else {
|
||||
DarkModeUtils.updateAppDarkModeStatusToSp(!DarkModeUtils.isAppDarkModeEnabledFromSp())
|
||||
}
|
||||
DarkModeUtils.updateFollowSystemDarkModeToSp(false)
|
||||
DarkModeUtils.initDarkMode()
|
||||
},
|
||||
extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
112
app/src/main/java/com/gh/base/DownloadToolbarActivity.kt
Normal file
112
app/src/main/java/com/gh/base/DownloadToolbarActivity.kt
Normal file
@ -0,0 +1,112 @@
|
||||
package com.gh.base
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.DownloadManagerActivity
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.activity.ToolBarActivity
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.utils.viewModelProvider
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.core.utils.SPUtils.getBoolean
|
||||
import com.gh.gamecenter.entity.GameUpdateEntity
|
||||
import com.gh.gamecenter.eventbus.EBDownloadStatus
|
||||
import com.gh.gamecenter.packagehelper.PackageViewModel
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
// TODO:移动到module_download模块中
|
||||
abstract class DownloadToolbarActivity : ToolBarActivity() {
|
||||
|
||||
private var mDownloadCountHint: TextView? = null
|
||||
private var mPackageViewModel: PackageViewModel? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
if (!getBoolean(Constants.SP_TEENAGER_MODE) && showDownloadMenu()) {
|
||||
mPackageViewModel = viewModelProvider(PackageViewModel.Factory())
|
||||
mPackageViewModel?.filterSameUpdateLiveData?.observe(this) { updateList: List<GameUpdateEntity> ->
|
||||
updateDownloadCountHint(updateList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun setToolbarMenu(res: Int) {
|
||||
// 青少年模式下要隐藏下载按钮
|
||||
if (getBoolean(Constants.SP_TEENAGER_MODE) && res == R.menu.menu_download) return
|
||||
super.setToolbarMenu(res)
|
||||
}
|
||||
|
||||
override fun inflateMenu(res: Int) {
|
||||
super.inflateMenu(res)
|
||||
if (showDownloadMenu()) {
|
||||
createDownloadMenu(res)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createDownloadMenu(res: Int) {
|
||||
if (res != R.menu.menu_download) {
|
||||
menuInflater.inflate(R.menu.menu_download, mActionMenuView.menu)
|
||||
}
|
||||
if (mPackageViewModel != null) {
|
||||
updateDownloadCountHint(mPackageViewModel?.filterSameUpdateLiveData?.value)
|
||||
}
|
||||
val downloadMenuView = mActionMenuView.menu.findItem(R.id.menu_download).actionView
|
||||
mDownloadCountHint = downloadMenuView?.findViewById(R.id.menu_download_count_hint)
|
||||
}
|
||||
|
||||
override fun onMenuItemClick(item: MenuItem?): Boolean {
|
||||
if (item!!.itemId == R.id.menu_download) {
|
||||
// MtaHelper.onEvent("下载管理", "下载管理入口", getActivityNameInChinese());
|
||||
val intent = DownloadManagerActivity.getDownloadMangerIntent(this, mEntrance)
|
||||
startActivity(intent)
|
||||
return true
|
||||
}
|
||||
return super.onMenuItemClick(item)
|
||||
}
|
||||
|
||||
private fun updateDownloadCountHint(updateList: List<GameUpdateEntity>?) {
|
||||
if (mDownloadCountHint == null) return
|
||||
val count = DownloadManager.getInstance().getDownloadOrUpdateCount(updateList)
|
||||
if (count != null) {
|
||||
mDownloadCountHint!!.visibility = View.VISIBLE
|
||||
mDownloadCountHint!!.text = count
|
||||
val params = mDownloadCountHint!!.layoutParams
|
||||
if (TextUtils.isEmpty(count)) {
|
||||
params.width = DisplayUtils.dip2px(6f)
|
||||
params.height = DisplayUtils.dip2px(6f)
|
||||
} else {
|
||||
params.width = DisplayUtils.dip2px(12f)
|
||||
params.height = DisplayUtils.dip2px(12f)
|
||||
}
|
||||
mDownloadCountHint!!.layoutParams = params
|
||||
} else {
|
||||
mDownloadCountHint!!.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun showDownloadMenu(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(status: EBDownloadStatus?) {
|
||||
if (!getBoolean(Constants.SP_TEENAGER_MODE) && showDownloadMenu() && mPackageViewModel != null) {
|
||||
updateDownloadCountHint(mPackageViewModel?.filterSameUpdateLiveData?.value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDarkModeChanged() {
|
||||
super.onDarkModeChanged()
|
||||
if (showDownloadMenu() && getMenuItem(R.id.menu_download) != null) {
|
||||
(getMenuItem(R.id.menu_download).actionView?.findViewById(R.id.menu_download_iv) as ImageView).setImageResource(
|
||||
R.drawable.toolbar_download
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,80 +0,0 @@
|
||||
package com.gh.base;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Application.ActivityLifecycleCallbacks;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.gh.common.notifier.Notifier;
|
||||
import com.gh.common.util.DataUtils;
|
||||
import com.gh.download.DownloadManager;
|
||||
import com.gh.gamecenter.SplashScreenActivity;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.utils.AppManager;
|
||||
|
||||
/**
|
||||
* 1、写点针对生命周期的统计代码
|
||||
* 2、写点通用的逻辑
|
||||
* 3、接口解耦
|
||||
*
|
||||
* @author CsHeng
|
||||
* @Date 09/05/2017
|
||||
* @Time 6:22 PM
|
||||
*/
|
||||
public class GHActivityLifecycleCallbacksImpl implements ActivityLifecycleCallbacks {
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
|
||||
|
||||
AppManager.getInstance().addActivity(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityStarted(Activity activity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResumed(Activity activity) {
|
||||
CurrentActivityHolder.getActivitySet().add(activity);
|
||||
|
||||
if (HaloApp.isUserAcceptPrivacyPolicy(activity)) {
|
||||
DataUtils.onResume(activity);
|
||||
//FIXME 这里应该只是部分Activity需要
|
||||
try {
|
||||
// 初始化gameMap
|
||||
if (!(activity instanceof SplashScreenActivity)) {
|
||||
DownloadManager.getInstance(activity).initGameMap();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityPaused(Activity activity) {
|
||||
CurrentActivityHolder.getActivitySet().remove(activity);
|
||||
|
||||
if (HaloApp.isUserAcceptPrivacyPolicy(activity)) {
|
||||
DataUtils.onPause(activity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityStopped(Activity activity) {
|
||||
Notifier.hide();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityDestroyed(Activity activity) {
|
||||
if (activity.isFinishing()) {
|
||||
AppManager.getInstance().finishActivity(activity);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,229 +0,0 @@
|
||||
//package com.gh.base
|
||||
//
|
||||
//import android.app.Notification
|
||||
//import android.app.NotificationChannel
|
||||
//import android.app.NotificationManager
|
||||
//import android.app.PendingIntent
|
||||
//import android.content.Context
|
||||
//import android.content.Intent
|
||||
//import android.os.Build
|
||||
//import android.os.Bundle
|
||||
//import android.preference.PreferenceManager
|
||||
//import android.text.TextUtils
|
||||
//import android.view.View
|
||||
//import androidx.core.app.NotificationCompat
|
||||
//import androidx.core.text.htmlEncode
|
||||
//import com.gh.common.notifier.Notifier
|
||||
//import com.gh.common.util.*
|
||||
//import com.gh.gamecenter.R
|
||||
//import com.gh.gamecenter.entity.PushEntity
|
||||
//import com.gh.gamecenter.entity.PushMessageEntity
|
||||
//import com.gh.gamecenter.entity.PushMessageUnreadEntity
|
||||
//import com.gh.gamecenter.entity.PushNotificationEntity
|
||||
//import com.gh.gamecenter.manager.UserManager
|
||||
//import com.gh.gamecenter.message.MessageUnreadRepository
|
||||
//import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity
|
||||
//import com.gh.gamecenter.receiver.UmengMessageReceiver
|
||||
//import com.gh.gamecenter.receiver.UmengMessageReceiver.Companion.TYPE_CLICK
|
||||
//import com.gh.gamecenter.receiver.UmengMessageReceiver.Companion.TYPE_REMOVE
|
||||
//import com.gh.gamecenter.retrofit.Response
|
||||
//import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
//import com.google.gson.Gson
|
||||
//import com.umeng.message.UmengMessageService
|
||||
//import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
//import io.reactivex.schedulers.Schedulers
|
||||
//import okhttp3.MediaType
|
||||
//import okhttp3.RequestBody
|
||||
//import okhttp3.ResponseBody
|
||||
//import org.android.agoo.common.AgooConstants
|
||||
//import org.json.JSONObject
|
||||
//import retrofit2.HttpException
|
||||
//import java.util.*
|
||||
//
|
||||
//class GHUmengNotificationService : UmengMessageService() {
|
||||
//
|
||||
// companion object {
|
||||
// const val ACTION_UMENG = "com.gh.gamecenter.UMENG"
|
||||
// const val MESSAGE_FROM_SYSTEM = "message_from_system"
|
||||
// const val HALO_MESSAGE_DIALOG = "HALO_MESSAGE_DIALOG"
|
||||
// const val HALO_MESSAGE_CENTER = "HALO_MESSAGE_CENTER"
|
||||
// const val ANSWER = "answer"
|
||||
// const val FOLLOW_QUESTION = "follow_question"
|
||||
// const val NOTIFICATION_ID = 2015
|
||||
// const val DISPLAY_TYPE_NOTIFICATION = "notification"
|
||||
// const val DISPLAY_TYPE_CUSTOM = "custom"
|
||||
// const val MESSAGE_ID = "message_id"
|
||||
// const val NOTIFICATION_MESSAGE_ID = "notification_message_id" // 通知中心消息 ID
|
||||
// const val PUSH_ID = "push_id"
|
||||
// }
|
||||
//
|
||||
// val notificationTags = arrayOf("GH_UMENG_TAG_1", "GH_UMENG_TAG_2", "GH_UMENG_TAG_3")
|
||||
// val gson = Gson()
|
||||
//
|
||||
// override fun onMessage(context: Context, intent: Intent) {
|
||||
// val message = intent.getStringExtra(AgooConstants.MESSAGE_BODY)
|
||||
// val isMessageFromSystem = intent.getBooleanExtra(MESSAGE_FROM_SYSTEM, false)
|
||||
//
|
||||
// try {
|
||||
// val pushData = message.toObject<PushEntity>()
|
||||
// pushData?.let { handlePushData(context, it, message, isMessageFromSystem) }
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private fun handlePushData(context: Context, pushData: PushEntity, message: String, isMessageFromSystem: Boolean) {
|
||||
// val notificationManager = context.applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
//
|
||||
// if (pushData.displayType == DISPLAY_TYPE_NOTIFICATION) {
|
||||
// // 其它类型的透传信息
|
||||
// // 显示到通知栏
|
||||
// val msg = message.toObject<PushNotificationEntity>()
|
||||
// val data = msg?.extra?.data
|
||||
//
|
||||
// // 系统推送(非自定义信息),直接处理跳转
|
||||
// if (isMessageFromSystem) {
|
||||
// val intent = Intent()
|
||||
// intent.setClass(context, UmengMessageReceiver::class.java)
|
||||
// intent.putExtra(EntranceUtils.KEY_DATA, data?.link)
|
||||
// intent.putExtra(EntranceUtils.KEY_TYPE, UmengMessageReceiver.DIRECT_ONLY)
|
||||
// intent.putExtra(EntranceUtils.KEY_MESSAGE, message)
|
||||
// intent.putExtra(NOTIFICATION_MESSAGE_ID, data?.messageId)
|
||||
// context.sendBroadcast(intent)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // 用户未登录的情况下不生成消息中心通知,避免用户掉登录了还收到跳转至消息中心的通知
|
||||
// if (data != null
|
||||
// && data.link?.link == "system"
|
||||
// && !UserManager.getInstance().isLoggedIn) {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// val clickIntent = Intent()
|
||||
// val removeIntent = Intent()
|
||||
//
|
||||
// clickIntent.setClass(context, UmengMessageReceiver::class.java)
|
||||
// clickIntent.putExtra(EntranceUtils.KEY_DATA, data?.link)
|
||||
// clickIntent.putExtra(EntranceUtils.KEY_MESSAGE, message)
|
||||
// clickIntent.putExtra(MESSAGE_ID, msg?.msgId)
|
||||
// clickIntent.putExtra(PUSH_ID, data?.pushId)
|
||||
// clickIntent.putExtra(NOTIFICATION_MESSAGE_ID, data?.messageId)
|
||||
// clickIntent.putExtra(EntranceUtils.KEY_TYPE, TYPE_CLICK)
|
||||
//
|
||||
// removeIntent.setClass(context, UmengMessageReceiver::class.java)
|
||||
// removeIntent.putExtra(EntranceUtils.KEY_TYPE, TYPE_REMOVE)
|
||||
// removeIntent.putExtra(EntranceUtils.KEY_MESSAGE, message)
|
||||
//
|
||||
// val clickPendingIntent = PendingIntent.getBroadcast(context, System.currentTimeMillis().toInt(),
|
||||
// clickIntent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
//
|
||||
// val deletePendingIntent = PendingIntent.getBroadcast(context, System.currentTimeMillis().toInt() + 1,
|
||||
// removeIntent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
//
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// val channel = NotificationChannel("Halo_Push", "Halo_Push", NotificationManager.IMPORTANCE_DEFAULT)
|
||||
// notificationManager.createNotificationChannel(channel)
|
||||
// }
|
||||
//
|
||||
// val notification = NotificationCompat.Builder(context, "Halo_Push")
|
||||
// .setSmallIcon(R.drawable.ic_notification)
|
||||
// .setTicker(pushData.body?.ticker)
|
||||
// .setContentTitle(pushData.body?.title)
|
||||
// .setContentText(pushData.body?.text?.fromHtml())
|
||||
// .setContentIntent(clickPendingIntent)
|
||||
// .setDeleteIntent(deletePendingIntent)
|
||||
// .build()
|
||||
// notification.flags = notification.flags or Notification.FLAG_AUTO_CANCEL
|
||||
//
|
||||
// notificationManager.notify(getNotificationTag(context), NOTIFICATION_ID, notification)
|
||||
// } else {
|
||||
// if (UserManager.getInstance().isLoggedIn &&
|
||||
// HALO_MESSAGE_DIALOG == pushData.body?.custom &&
|
||||
// MessageUnreadRepository.unreadLiveData.value != null) {
|
||||
// // 回答了问题或者关注了问题的消息
|
||||
// val msg = gson.fromJson(message, PushMessageEntity::class.java)
|
||||
// val data = msg?.extra?.data
|
||||
//
|
||||
// val type = if (ANSWER == data?.type) {
|
||||
// "回答了你的问题"
|
||||
// } else {
|
||||
// "回答了你关注的问题"
|
||||
// }
|
||||
//
|
||||
// val userName = StringUtils.shrinkStringWithDot(data?.userEntity?.name, 8)
|
||||
// val displayText = userName + type
|
||||
//
|
||||
// if (Notifier.isActivityValid(CurrentActivityHolder.getCurrentActivity()) &&
|
||||
// Notifier.shouldShowNotifier(data?.answer?.id + displayText)) {
|
||||
// Notifier.create(CurrentActivityHolder.getCurrentActivity())
|
||||
// .setText(displayText)
|
||||
// .setDuration(5000)
|
||||
// .setIcon(data?.userEntity?.icon)
|
||||
// .setOnClickListener(View.OnClickListener {
|
||||
// val bundle = Bundle()
|
||||
// bundle.putString(EntranceUtils.KEY_ANSWER_ID, data?.answer?.id)
|
||||
// bundle.putString(EntranceUtils.KEY_ENTRANCE, EntranceUtils.ENTRANCE_UMENG)
|
||||
// bundle.putString(EntranceUtils.KEY_TO, AnswerDetailActivity::class.java.name)
|
||||
// EntranceUtils.jumpActivity(context, bundle)
|
||||
//
|
||||
// MtaHelper.onEvent("消息弹窗", type, "Does not contains any parameter.")
|
||||
//
|
||||
// // 标记已读
|
||||
// val jsonObject = JSONObject()
|
||||
// jsonObject.put("type", type)
|
||||
// val body = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
|
||||
//
|
||||
// RetrofitManager.getInstance(application).api.postMessageRead(UserManager.getInstance().userId, data?.id, body)
|
||||
// .subscribeOn(Schedulers.io())
|
||||
// .observeOn(AndroidSchedulers.mainThread())
|
||||
// .subscribe(object : Response<ResponseBody>() {
|
||||
// override fun onResponse(response: ResponseBody?) {
|
||||
// super.onResponse(response)
|
||||
// MessageUnreadRepository.loadMessageUnreadData()
|
||||
// }
|
||||
//
|
||||
// override fun onFailure(e: HttpException?) {
|
||||
// e?.printStackTrace()
|
||||
// }
|
||||
// })
|
||||
// Notifier.hide()
|
||||
// })
|
||||
// .show(false)
|
||||
// Notifier.tagNotifierAsShowed(data?.answer?.id + displayText)
|
||||
// }
|
||||
// } else if (HALO_MESSAGE_CENTER == pushData.body?.custom) {
|
||||
// // 消息中心逻辑
|
||||
// val msg = gson.fromJson(message, PushMessageUnreadEntity::class.java)
|
||||
// val data = msg?.extra?.data
|
||||
// data?.let { MessageUnreadRepository.loadMessageUnreadData() }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 规则:最多三条消息,以旧换新
|
||||
// *
|
||||
// * @return NotificationTag
|
||||
// */
|
||||
// private fun getNotificationTag(context: Context): String {
|
||||
// val sp = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
// val edit = sp.edit()
|
||||
//
|
||||
// val timeTagMap = HashMap<Long, String>()
|
||||
// for (tag in notificationTags) {
|
||||
// val time = sp.getLong(tag, 0)
|
||||
// if (time == 0L) {
|
||||
// edit.putLong(tag, System.currentTimeMillis()).apply()
|
||||
// return tag
|
||||
// } else {
|
||||
// timeTagMap[time] = tag
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// val minTime = Collections.min(timeTagMap.keys)
|
||||
// val tag = timeTagMap[minTime]
|
||||
// edit.putLong(tag, System.currentTimeMillis()).apply()
|
||||
// return if (TextUtils.isEmpty(tag)) notificationTags[0] else tag!!
|
||||
// }
|
||||
//}
|
||||
@ -0,0 +1,96 @@
|
||||
package com.gh.base
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Application
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.gh.common.util.FloatingBackViewManager
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.MainActivity
|
||||
import com.gh.gamecenter.SplashScreenActivity
|
||||
import com.gh.gamecenter.common.utils.PackageFlavorHelper
|
||||
import com.gh.gamecenter.forum.detail.ForumDetailActivity
|
||||
import com.gh.gamecenter.forum.list.ForumListActivity
|
||||
import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity
|
||||
import com.gh.gamecenter.qa.questions.newdetail.NewQuestionDetailActivity
|
||||
import com.gh.gamecenter.qa.video.detail.ForumVideoDetailActivity
|
||||
import com.gh.vspace.VHelper
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
// TODO:移动到对应的模块
|
||||
class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
|
||||
|
||||
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
override fun onActivityStarted(activity: Activity) {
|
||||
GlobalActivityManager.currentActivity = activity
|
||||
}
|
||||
|
||||
override fun onActivityResumed(activity: Activity) {
|
||||
// 判断是否需要显示或隐藏返回小浮窗
|
||||
if (FloatingBackViewManager.getType().isNotEmpty()) {
|
||||
if ((activity::class.java.name == "EnergyCenterActivity")
|
||||
&& FloatingBackViewManager.getType() == FloatingBackViewManager.TYPE_TASK
|
||||
) {
|
||||
FloatingBackViewManager.disableBackView()
|
||||
} else if (!shouldShowActivityBackView(activity)
|
||||
&& FloatingBackViewManager.getType() == FloatingBackViewManager.TYPE_ACTIVITY
|
||||
) {
|
||||
FloatingBackViewManager.disableBackView()
|
||||
} else {
|
||||
FloatingBackViewManager.showBackView(activity)
|
||||
}
|
||||
}
|
||||
|
||||
if (HaloApp.isUserAcceptPrivacyPolicy(activity)) {
|
||||
// FIXME 这里应该只是部分Activity需要
|
||||
try {
|
||||
// 初始化gameMap
|
||||
if (activity !is SplashScreenActivity) {
|
||||
DownloadManager.getInstance().initGameMap()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
if (PackageFlavorHelper.IS_TEST_FLAVOR && activity is AppCompatActivity) {
|
||||
DarkModeSwitchHelper.showDarkModeSwitchFloatingView(activity)
|
||||
}
|
||||
|
||||
if (activity is AppCompatActivity && activity !is SplashScreenActivity) {
|
||||
VHelper.showFeedbackDialogIfLastSuccessfulLaunchedGameExitUnexpectedly(activity)
|
||||
}
|
||||
}
|
||||
|
||||
private fun shouldShowActivityBackView(activity: Activity): Boolean {
|
||||
return (activity is MainActivity
|
||||
|| activity is ArticleDetailActivity
|
||||
|| activity is ForumVideoDetailActivity
|
||||
|| activity is ForumDetailActivity
|
||||
|| activity is ForumListActivity
|
||||
|| activity is NewQuestionDetailActivity)
|
||||
}
|
||||
|
||||
override fun onActivityPaused(activity: Activity) {
|
||||
FloatingBackViewManager.dismissBackView()
|
||||
if (PackageFlavorHelper.IS_TEST_FLAVOR && activity is AppCompatActivity) {
|
||||
DarkModeSwitchHelper.dismissDarkModeSwitchFloatingView()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityStopped(activity: Activity) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
override fun onActivityDestroyed(activity: Activity) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
}
|
||||
14
app/src/main/java/com/gh/base/GlobalActivityManager.kt
Normal file
14
app/src/main/java/com/gh/base/GlobalActivityManager.kt
Normal file
@ -0,0 +1,14 @@
|
||||
package com.gh.base
|
||||
|
||||
import android.app.Activity
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
object GlobalActivityManager {
|
||||
private var mCurrentActivityWeakRef: WeakReference<Activity>? = null
|
||||
|
||||
var currentActivity: Activity?
|
||||
get() = mCurrentActivityWeakRef?.get()
|
||||
set(activity) {
|
||||
mCurrentActivityWeakRef = WeakReference<Activity>(activity)
|
||||
}
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
package com.gh.base;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Created by khy on 26/09/17.
|
||||
*/
|
||||
|
||||
public interface OnListClickListener {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param view
|
||||
* @param position list position
|
||||
* @param data list data (直接强转 如果列表传入不同数据类型 请做好判断)
|
||||
* @param <T>
|
||||
*/
|
||||
<T> void onListClick(View view, int position, T data);
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
package com.gh.base;
|
||||
|
||||
/**
|
||||
* Created by Administrator on 2016/9/8.
|
||||
*
|
||||
* 逐步移除
|
||||
*/
|
||||
|
||||
@Deprecated
|
||||
public interface OnRequestCallBackListener<T> {
|
||||
|
||||
void loadDone();
|
||||
|
||||
void loadDone(T obj);
|
||||
|
||||
void loadError();
|
||||
|
||||
void loadEmpty();
|
||||
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
package com.gh.base;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
public interface OnViewClickListener<T> {
|
||||
void onClick(View v, T data);
|
||||
}
|
||||
@ -1,262 +0,0 @@
|
||||
package com.gh.base;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.download.DownloadManager;
|
||||
import com.gh.gamecenter.DownloadManagerActivity;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.entity.GameUpdateEntity;
|
||||
import com.gh.gamecenter.eventbus.EBDownloadStatus;
|
||||
import com.gh.gamecenter.normal.ToolbarController;
|
||||
import com.gh.gamecenter.packagehelper.PackageViewModel;
|
||||
import com.lightgame.OnTitleClickListener;
|
||||
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 需要用到工具栏的页面使用
|
||||
* <p>
|
||||
* 特殊页面请参考{@link BaseActivity}
|
||||
*/
|
||||
|
||||
public abstract class ToolBarActivity extends BaseActivity implements ToolbarController, Toolbar.OnMenuItemClickListener {
|
||||
|
||||
@Nullable
|
||||
private PackageViewModel mPackageViewModel;
|
||||
|
||||
protected View mToolbarContainer;
|
||||
|
||||
protected Toolbar mToolbar;
|
||||
|
||||
protected TextView mTitleTv;
|
||||
|
||||
@Nullable
|
||||
private TextView mDownloadCountHint;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setStatusBarDarkMode(true, this);
|
||||
initToolbar();
|
||||
|
||||
if (showDownloadMenu()) {
|
||||
mPackageViewModel = ViewModelProviders.of(this, new PackageViewModel.Factory()).get(PackageViewModel.class);
|
||||
mPackageViewModel.getFilterSameUpdateLiveData().observe(this, this::updateDownloadCountHint);
|
||||
}
|
||||
}
|
||||
|
||||
// 小米沉浸式黑色字体
|
||||
@SuppressLint("PrivateApi")
|
||||
public void setStatusBarDarkMode(boolean darkmode, Activity activity) {
|
||||
Class<? extends Window> clazz = activity.getWindow().getClass();
|
||||
try {
|
||||
Class<?> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
|
||||
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
|
||||
int darkModeFlag = field.getInt(layoutParams);
|
||||
Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
|
||||
extraFlagField.invoke(activity.getWindow(), darkmode ? darkModeFlag : 0, darkModeFlag);
|
||||
} catch (Exception ignore) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void initToolbar() {
|
||||
mToolbarContainer = findViewById(R.id.normal_toolbar_container);
|
||||
mToolbar = findViewById(R.id.normal_toolbar);
|
||||
mTitleTv = findViewById(R.id.normal_title);
|
||||
if (mToolbar != null) {
|
||||
// setSupportActionBar(mToolbar); // 替换actionBar后 toolBar无法控制
|
||||
mToolbar.setNavigationIcon(provideNavigationIcon());
|
||||
mToolbar.setNavigationOnClickListener(provideNavigationItemClickListener());
|
||||
if (mTitleTv != null) {
|
||||
mTitleTv.setOnClickListener(view -> {
|
||||
final List<Fragment> fragmentList = getSupportFragmentManager().getFragments();
|
||||
for (Fragment fragment : fragmentList) {
|
||||
if (fragment instanceof OnTitleClickListener) {
|
||||
((OnTitleClickListener) fragment).onTitleClick();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DrawableRes
|
||||
public int provideNavigationIcon() {
|
||||
return R.drawable.ic_bar_back; // default navigation icon
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNavigationTitle(String title) {
|
||||
if (mTitleTv != null) mTitleTv.setText(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNavigationTitle(@StringRes int res) {
|
||||
setNavigationTitle(getString(res));
|
||||
}
|
||||
|
||||
/**
|
||||
* 重写此方法以将标题靠左显示
|
||||
*/
|
||||
public boolean showToolbarAtLeft() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setToolbarMenu(int res) {
|
||||
if (mToolbar == null) return;
|
||||
mToolbar.inflateMenu(res);
|
||||
mToolbar.setOnMenuItemClickListener(this);
|
||||
|
||||
if (showDownloadMenu()) {
|
||||
createDownloadMenu(res);
|
||||
}
|
||||
|
||||
Menu menu = mToolbar.getMenu();
|
||||
for (int i = 0; i < menu.size(); i++) {
|
||||
MenuItem menuItem = menu.getItem(i);
|
||||
// menu设置actionLayout后,无法捕捉点击事件,以icon为tag,如果icon is null 手动设置menuItem点击事件
|
||||
if (menuItem != null && menuItem.getIcon() == null) {
|
||||
if (menuItem.getActionView() != null) {
|
||||
menuItem.getActionView().setOnClickListener((v) -> this.onMenuItemClick(menuItem));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 限制标题实际宽度 防止标题挡住toolbar menu按钮
|
||||
if (menu.size() > 2 && mTitleTv != null) {
|
||||
ViewGroup.LayoutParams layoutParams = mTitleTv.getLayoutParams();
|
||||
if (layoutParams instanceof RelativeLayout.LayoutParams) {
|
||||
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) layoutParams;
|
||||
if (showToolbarAtLeft()) {
|
||||
params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
|
||||
params.addRule(RelativeLayout.CENTER_VERTICAL);
|
||||
params.setMargins(DisplayUtils.dip2px(55), 0, DisplayUtils.dip2px(48 * menu.size()), 0);
|
||||
} else {
|
||||
params.setMargins(DisplayUtils.dip2px(90), 0, DisplayUtils.dip2px(90), 0);
|
||||
}
|
||||
mTitleTv.setLayoutParams(params);
|
||||
}
|
||||
} else {
|
||||
if (showToolbarAtLeft()) {
|
||||
ViewGroup.LayoutParams layoutParams = mTitleTv.getLayoutParams();
|
||||
if (layoutParams instanceof RelativeLayout.LayoutParams) {
|
||||
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) layoutParams;
|
||||
params.addRule(RelativeLayout.CENTER_VERTICAL);
|
||||
params.setMargins(DisplayUtils.dip2px(55), 0, DisplayUtils.dip2px(48 * menu.size()), 0);
|
||||
mTitleTv.setLayoutParams(params);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createDownloadMenu(int res) {
|
||||
if (res != R.menu.menu_download) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.menu_download, mToolbar.getMenu());
|
||||
}
|
||||
|
||||
if (mPackageViewModel != null) {
|
||||
updateDownloadCountHint(mPackageViewModel.getFilterSameUpdateLiveData().getValue());
|
||||
}
|
||||
|
||||
View downloadMenuView = mToolbar.getMenu().findItem(R.id.menu_download).getActionView();
|
||||
mDownloadCountHint = downloadMenuView.findViewById(R.id.menu_download_count_hint);
|
||||
}
|
||||
|
||||
private void updateDownloadCountHint(List<GameUpdateEntity> updateList) {
|
||||
if (mDownloadCountHint == null) return;
|
||||
|
||||
String count = DownloadManager.getInstance(getApplicationContext()).getDownloadOrUpdateCount(updateList);
|
||||
if (count != null) {
|
||||
mDownloadCountHint.setVisibility(View.VISIBLE);
|
||||
mDownloadCountHint.setText(count);
|
||||
|
||||
ViewGroup.LayoutParams params = mDownloadCountHint.getLayoutParams();
|
||||
if (TextUtils.isEmpty(count)) {
|
||||
params.width = DisplayUtils.dip2px(6);
|
||||
params.height = DisplayUtils.dip2px(6);
|
||||
} else {
|
||||
params.width = DisplayUtils.dip2px(12);
|
||||
params.height = DisplayUtils.dip2px(12);
|
||||
}
|
||||
mDownloadCountHint.setLayoutParams(params);
|
||||
} else {
|
||||
mDownloadCountHint.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onEventMainThread(EBDownloadStatus status) {
|
||||
if (showDownloadMenu() && mPackageViewModel != null) {
|
||||
updateDownloadCountHint(mPackageViewModel.getFilterSameUpdateLiveData().getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem getMenuItem(int res) {
|
||||
if (mToolbar == null) return null; //后续页面做好判断
|
||||
return mToolbar.getMenu().findItem(res);
|
||||
}
|
||||
|
||||
public void clearMenu() {
|
||||
if (mToolbar != null) {
|
||||
mToolbar.getMenu().clear();
|
||||
}
|
||||
}
|
||||
|
||||
public Menu getMenu() {
|
||||
return mToolbar.getMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
if (item.getItemId() == R.id.menu_download) {
|
||||
// MtaHelper.onEvent("下载管理", "下载管理入口", getActivityNameInChinese());
|
||||
Intent intent = DownloadManagerActivity.getDownloadMangerIntent(this, mEntrance);
|
||||
startActivity(intent);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected View.OnClickListener provideNavigationItemClickListener() {
|
||||
return view -> onBackPressed();
|
||||
}
|
||||
|
||||
protected boolean showDownloadMenu() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideToolbar(boolean isHide) {
|
||||
if (mToolbarContainer != null) {
|
||||
mToolbarContainer.setVisibility(isHide ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,123 +0,0 @@
|
||||
package com.gh.base.fragment
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.viewpager.widget.PagerAdapter
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import butterknife.BindView
|
||||
import com.gh.base.adapter.FragmentAdapter
|
||||
import com.gh.common.view.TabIndicatorView
|
||||
import com.gh.gamecenter.R
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.lightgame.view.NoScrollableViewPager
|
||||
import java.util.*
|
||||
|
||||
abstract class BaseLazyTabFragment : BaseLazyFragment(), ViewPager.OnPageChangeListener {
|
||||
|
||||
@BindView(R.id.fragment_tab_layout)
|
||||
lateinit var mTabLayout: TabLayout
|
||||
|
||||
@BindView(R.id.fragment_view_pager)
|
||||
lateinit var mViewPager: NoScrollableViewPager
|
||||
|
||||
@BindView(R.id.fragment_tab_indicator)
|
||||
lateinit var mTabIndicatorView: TabIndicatorView
|
||||
|
||||
var mFragmentsList: MutableList<Fragment> = arrayListOf()
|
||||
|
||||
var mTabTitleList: MutableList<String> = arrayListOf()
|
||||
|
||||
var mCheckedIndex = 0
|
||||
|
||||
abstract fun initFragmentList(fragments: MutableList<Fragment>)
|
||||
|
||||
abstract fun initTabTitleList(tabTitleList: MutableList<String>)
|
||||
|
||||
protected open fun provideIndicatorWidth(): Int {
|
||||
return 20
|
||||
}
|
||||
|
||||
protected open fun provideTabView(position: Int, tabTitle: String?): View? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getLayoutId(): Int {
|
||||
return R.layout.fragment_tablayout_viewpager
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
val fragments = childFragmentManager.fragments
|
||||
if (fragments != null) {
|
||||
for (fragment in fragments) {
|
||||
fragment.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
if (arguments != null) mCheckedIndex = requireArguments().getInt(PAGE_INDEX, 0)
|
||||
}
|
||||
|
||||
open fun providePagerAdapter(): PagerAdapter? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onFragmentFirstVisible() {
|
||||
super.onFragmentFirstVisible()
|
||||
mTabTitleList.clear()
|
||||
mFragmentsList.clear()
|
||||
|
||||
initTabTitleList(mTabTitleList)
|
||||
mFragmentsList.addAll(restoreFragments())
|
||||
if (mFragmentsList.isEmpty() || mFragmentsList.size != mTabTitleList.size) {
|
||||
mFragmentsList.clear()
|
||||
initFragmentList(mFragmentsList)
|
||||
}
|
||||
|
||||
mViewPager.offscreenPageLimit = mFragmentsList.size
|
||||
mViewPager.addOnPageChangeListener(this)
|
||||
mViewPager.adapter = providePagerAdapter()
|
||||
?: FragmentAdapter(childFragmentManager, mFragmentsList, mTabTitleList)
|
||||
mViewPager.currentItem = mCheckedIndex
|
||||
mTabLayout.setupWithViewPager(mViewPager)
|
||||
mTabIndicatorView.setupWithTabLayout(mTabLayout)
|
||||
mTabIndicatorView.setupWithViewPager(mViewPager)
|
||||
mTabIndicatorView.setIndicatorWidth(provideIndicatorWidth())
|
||||
for (i in 0 until mTabLayout.tabCount) {
|
||||
val tab = mTabLayout.getTabAt(i) ?: continue
|
||||
val tabTitle = if (tab.text != null) tab.text.toString() else ""
|
||||
var tabView = provideTabView(i, tabTitle)
|
||||
if (tabView == null) tabView = BaseFragment_TabLayout.createDefaultTabCustomView(tabTitle)
|
||||
tab.customView = tabView
|
||||
}
|
||||
BaseFragment_TabLayout.initTabStyle(mTabLayout, mCheckedIndex)
|
||||
}
|
||||
|
||||
private fun restoreFragments(): ArrayList<Fragment> {
|
||||
val tag = "android:switcher:${mViewPager.id}:"
|
||||
val fragments = ArrayList<Fragment>()
|
||||
val childCount = mTabTitleList.size
|
||||
for (index in 0 until childCount) {
|
||||
val fragment = childFragmentManager.findFragmentByTag("$tag$index")
|
||||
if (fragment != null) {
|
||||
fragments.add(fragment)
|
||||
}
|
||||
}
|
||||
return fragments
|
||||
}
|
||||
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
|
||||
|
||||
override fun onPageSelected(position: Int) {}
|
||||
|
||||
override fun onPageScrollStateChanged(state: Int) {}
|
||||
|
||||
companion object {
|
||||
const val PAGE_INDEX = "PAGE_INDEX"
|
||||
}
|
||||
}
|
||||
@ -1,68 +0,0 @@
|
||||
package com.gh.base.fragment
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewStub
|
||||
import com.gh.gamecenter.R
|
||||
|
||||
/**
|
||||
* 这是在 BaseLazyFragment 之上添加了一些通用功能的抽象类
|
||||
*
|
||||
* 怎么将一个已有的 fragment 转化为懒加载 (延迟渲染) 的 fragment 呢?
|
||||
* (继承 ListFragment 的类请改为继承 LazyListFragment)
|
||||
*
|
||||
* 0. 删掉旧的 getInflatedLayout() 的代码,现在由 getLayoutId() 提供 Stub 布局 (默认为 R.layout.fragment_stub,若重写请注意提供 id 为 stub 的 ViewStub)
|
||||
* 1. 重写 getRealLayoutId(),提供实际要延迟渲染的 layout Id
|
||||
* 1. 将原有在 onCreate() 的代码移动到 onFragmentFirstVisible()
|
||||
* 2. 将原有在 onViewCreated() 的代码移动到 initRealView()
|
||||
* (注意,initRealView() 在 onFragmentFirstVisible() 中被调用,如果要初始化 viewModel 等非 UI 对象请在 super.onFragmentVisible() 调用)
|
||||
* 3. 如需使用 ViewBinding ,在 onRealLayoutInflated() 的回调中初始化 ViewBinding 即可
|
||||
* 4. onResume() 的代码移动到 onFragmentResume(),onPause() 的代码移动到 onFragmentPause()
|
||||
* 5. Done!
|
||||
*/
|
||||
abstract class LazyFragment : BaseLazyFragment() {
|
||||
|
||||
// ViewStub + ViewBinding 有莫名的 bug,语法上没问题,但编译时通不过。
|
||||
private var mViewStub: ViewStub? = null
|
||||
|
||||
override fun getLayoutId() = R.layout.fragment_stub
|
||||
|
||||
override fun useButterKnife() = false
|
||||
|
||||
override fun initView(view: View?) {
|
||||
super.initView(view)
|
||||
mViewStub = mCachedView.findViewById(R.id.stub)
|
||||
}
|
||||
|
||||
override fun onFragmentFirstVisible() {
|
||||
super.onFragmentFirstVisible()
|
||||
inflateRealView()
|
||||
initRealView()
|
||||
}
|
||||
|
||||
/**
|
||||
* 真正 inflate View 的地方
|
||||
*/
|
||||
protected open fun inflateRealView() {
|
||||
mViewStub?.layoutResource = getRealLayoutId()
|
||||
mViewStub?.setOnInflateListener { _, inflatedView -> onRealLayoutInflated(inflatedView) }
|
||||
mCachedView = mViewStub?.inflate()
|
||||
}
|
||||
|
||||
/**
|
||||
* 请在这个方法之后获取初始化后的各种 view
|
||||
*
|
||||
* 替换旧 fragment 实现时,等同于 onViewCreated
|
||||
*/
|
||||
protected open fun initRealView() {}
|
||||
|
||||
/**
|
||||
* 提供要 stub inflate 的 layout
|
||||
*/
|
||||
protected abstract fun getRealLayoutId(): Int
|
||||
|
||||
/**
|
||||
* 真实 layout inflate 完成的回调,可用于 viewBinding
|
||||
*/
|
||||
protected open fun onRealLayoutInflated(inflatedView: View) {}
|
||||
|
||||
}
|
||||
@ -1,5 +0,0 @@
|
||||
package com.gh.base.fragment;
|
||||
|
||||
public interface OnDialogBackListener {
|
||||
void onBack();
|
||||
}
|
||||
@ -1,71 +0,0 @@
|
||||
package com.gh.common
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import com.gh.base.GHThreadFactory
|
||||
import com.gh.common.AppExecutor.ioExecutor
|
||||
import com.gh.common.AppExecutor.lightWeightIoExecutor
|
||||
import com.gh.common.AppExecutor.logExecutor
|
||||
import com.gh.common.AppExecutor.uiExecutor
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import java.util.concurrent.*
|
||||
|
||||
/**
|
||||
* APP 线程池管理类
|
||||
*
|
||||
* [ioExecutor] 是一个最大线程数固定的线程池,较为繁重的 IO 任务可以交给它
|
||||
* [uiExecutor] 是主线程的包裹,需要切换至主线程执行可以用它
|
||||
* [lightWeightIoExecutor] 是一个单线程的线程池,轻量级且需要保证同一线程的 IO 任务可以交给它
|
||||
* [logExecutor] 只为上传 log 而使用的线程池
|
||||
*/
|
||||
object AppExecutor {
|
||||
|
||||
private val mCoreSize = Runtime.getRuntime().availableProcessors()
|
||||
private val mMinimumPoolSize = 16.coerceAtLeast(mCoreSize * 4)
|
||||
private val mMaximumPoolSize = 64.coerceAtLeast(mCoreSize * 16)
|
||||
|
||||
// TODO 因为 LinkedBlockingQueue 过大导致 MaximumPoolSize 的值几乎无效,下版本改造 [PackageRepository] 启动请求一堆游戏摘要信息的接口?
|
||||
|
||||
@JvmStatic
|
||||
val uiExecutor by lazy { MainThreadExecutor() }
|
||||
|
||||
@JvmStatic
|
||||
val lightWeightIoExecutor by lazy { Executors.newSingleThreadExecutor(GHThreadFactory("GH_LIGHT_WEIGHT_IO_THREAD")) }
|
||||
|
||||
@JvmStatic
|
||||
val logExecutor by lazy { Executors.newSingleThreadExecutor(GHThreadFactory("GH_LOG_THREAD")) }
|
||||
|
||||
@JvmStatic
|
||||
val ioExecutor = ThreadPoolExecutor(
|
||||
mMinimumPoolSize,
|
||||
mMaximumPoolSize,
|
||||
20L, TimeUnit.SECONDS,
|
||||
LinkedBlockingQueue<Runnable>(1000),
|
||||
GHThreadFactory("GH_IO_THREAD"))
|
||||
|
||||
val cachedScheduler by lazy { Schedulers.from(ioExecutor) }
|
||||
|
||||
class MainThreadExecutor : Executor {
|
||||
private val mainThreadHandler = Handler(Looper.getMainLooper())
|
||||
|
||||
override fun execute(command: Runnable) {
|
||||
mainThreadHandler.post(command)
|
||||
}
|
||||
|
||||
fun executeWithDelay(command: Runnable, delay: Long) {
|
||||
mainThreadHandler.postDelayed(command, delay)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun runOnIoThread(isLightWeightTask: Boolean = false, f: () -> Unit) {
|
||||
if (isLightWeightTask) {
|
||||
AppExecutor.lightWeightIoExecutor.execute(f)
|
||||
} else {
|
||||
AppExecutor.ioExecutor.execute(f)
|
||||
}
|
||||
}
|
||||
|
||||
fun runOnUiThread(f: () -> Unit) {
|
||||
AppExecutor.uiExecutor.execute(f)
|
||||
}
|
||||
@ -1,5 +0,0 @@
|
||||
package com.gh.common
|
||||
|
||||
object Base64ImageHolder {
|
||||
var image: String = ""
|
||||
}
|
||||
@ -3,43 +3,51 @@ package com.gh.common
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.util.Base64
|
||||
import android.webkit.JavascriptInterface
|
||||
import androidx.annotation.Keep
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.gh.base.CurrentActivityHolder
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.loghub.LoghubUtils
|
||||
import com.gh.common.tracker.Tracker
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.view.dsbridge.CompletionHandler
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.ImageViewerActivity
|
||||
import com.gh.gamecenter.LoginActivity
|
||||
import com.gh.gamecenter.WebActivity
|
||||
import com.gh.gamecenter.energy.EnergyCenterActivity
|
||||
import com.gh.gamecenter.energy.EnergyHouseActivity
|
||||
import com.gh.gamecenter.entity.Badge
|
||||
import com.gh.common.util.LogUtils
|
||||
import com.gh.gamecenter.*
|
||||
import com.gh.gamecenter.common.callback.BiCallback
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.entity.NotificationUgc
|
||||
import com.gh.gamecenter.common.loghub.LoghubUtils
|
||||
import com.gh.gamecenter.common.tracker.Tracker
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.common.view.dsbridge.CompletionHandler
|
||||
import com.gh.gamecenter.core.AppExecutor
|
||||
import com.gh.gamecenter.core.runOnIoThread
|
||||
import com.gh.gamecenter.core.runOnUiThread
|
||||
import com.gh.gamecenter.core.utils.CurrentActivityHolder
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.core.utils.MtaHelper
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.energy.EnergyBridge
|
||||
import com.gh.gamecenter.entity.MtaEvent
|
||||
import com.gh.gamecenter.entity.NotificationUgc
|
||||
import com.gh.gamecenter.help.QaFeedbackDialogFragment
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.login.entity.Badge
|
||||
import com.gh.gamecenter.login.user.LoginTag
|
||||
import com.gh.gamecenter.login.view.LoginActivity
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import com.gh.gamecenter.personalhome.border.AvatarBorderActivity
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.gh.gamecenter.security.BindPhoneActivity
|
||||
import com.gh.gamecenter.user.LoginTag
|
||||
import com.gh.gamecenter.user.UserRepository
|
||||
import com.gh.gamecenter.login.user.UserRepository
|
||||
import com.gh.gamecenter.login.utils.LoginHelper
|
||||
import com.gh.gamecenter.login.utils.QuickLoginHelper
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.ResponseBody
|
||||
import org.json.JSONObject
|
||||
import retrofit2.HttpException
|
||||
import java.io.BufferedOutputStream
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class DefaultJsApi(var context: Context) {
|
||||
class DefaultJsApi(var context: Context, val entrance: String = "") {
|
||||
|
||||
private var mLoginHandler: CompletionHandler<Any>? = null
|
||||
|
||||
@JavascriptInterface
|
||||
fun isGhzs(msg: Any): String {
|
||||
@ -102,7 +110,7 @@ class DefaultJsApi(var context: Context) {
|
||||
|
||||
@JavascriptInterface
|
||||
fun getAppVersionCode(msg: Any): Int {
|
||||
return PackageUtils.getVersionCode()
|
||||
return PackageUtils.getGhVersionCode()
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
@ -118,36 +126,39 @@ class DefaultJsApi(var context: Context) {
|
||||
wechatLoginInfoMap["access_token"] = jsonContent.getString("access_token")
|
||||
wechatLoginInfoMap["refresh_token"] = jsonContent.getString("refresh_token")
|
||||
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application)
|
||||
.api
|
||||
.postBindWechat(wechatLoginInfoMap.createRequestBody())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
EnergyTaskHelper.postEnergyTask("bind_wechat")
|
||||
handler.complete(true)
|
||||
}
|
||||
WechatBindHelper.bindWechat(wechatLoginInfoMap, object : BiCallback<Boolean, Boolean> {
|
||||
override fun onFirst(first: Boolean) {
|
||||
EnergyBridge.postEnergyTask("bind_wechat")
|
||||
handler.complete(true)
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
handler.complete(false)
|
||||
if (exception is HttpException) {
|
||||
ErrorHelper.handleError(HaloApp.getInstance().application, exception.response().errorBody()?.string())
|
||||
}
|
||||
}
|
||||
})
|
||||
override fun onSecond(second: Boolean) {
|
||||
handler.complete(false)
|
||||
}
|
||||
})
|
||||
|
||||
LoginHelper.unregisterCallback()
|
||||
}
|
||||
|
||||
override fun onLoginFailure(loginType: LoginTag, error: String) {
|
||||
handler.complete(false)
|
||||
|
||||
LoginHelper.unregisterCallback()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun refreshWechatBindData(msg: Any) {
|
||||
WechatBindHelper.getWechatConfig(null)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun copyText(msg: Any) {
|
||||
msg.toString().copyTextAndToast()
|
||||
runOnUiThread {
|
||||
msg.toString().copyTextAndToast()
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
@ -183,7 +194,7 @@ class DefaultJsApi(var context: Context) {
|
||||
fun openBase64Image(event: Any) {
|
||||
val context = CurrentActivityHolder.getCurrentActivity()
|
||||
|
||||
Base64ImageHolder.image = event.toString()
|
||||
ImageViewerActivity.base64Image = event.toString()
|
||||
|
||||
context?.startActivity(ImageViewerActivity.getBase64Intent(context, true))
|
||||
}
|
||||
@ -209,7 +220,7 @@ class DefaultJsApi(var context: Context) {
|
||||
@JavascriptInterface
|
||||
fun updateRegulationTestStatus(msg: Any) {
|
||||
if (msg.toString().toLowerCase(Locale.getDefault()) == "pass") {
|
||||
EnergyTaskHelper.postEnergyTask("finish_etiquette_exam")
|
||||
EnergyBridge.postEnergyTask("finish_etiquette_exam")
|
||||
SPUtils.setString(Constants.SP_REGULATION_TEST_PASS_STATUS, "pass")
|
||||
}
|
||||
}
|
||||
@ -234,7 +245,7 @@ class DefaultJsApi(var context: Context) {
|
||||
fun shareBase64Image(event: Any) {
|
||||
val imageShareEvent = event.toString().toObject() ?: ImageShareEvent()
|
||||
val context = CurrentActivityHolder.getCurrentActivity()
|
||||
Base64ImageHolder.image = imageShareEvent.image.run {
|
||||
ImageViewerActivity.base64Image = imageShareEvent.image.run {
|
||||
if (this.startsWith("data:image/png;base64")) this.split(",")[1] else this
|
||||
}
|
||||
MessageShareUtils.getInstance(context).shareFromWeb(context, imageShareEvent.type)
|
||||
@ -245,7 +256,7 @@ class DefaultJsApi(var context: Context) {
|
||||
val inviteEvent = event.toString().toObject() ?: InviteFriendsEvent()
|
||||
val context = CurrentActivityHolder.getCurrentActivity()
|
||||
if ("poster" == inviteEvent.type) {
|
||||
Base64ImageHolder.image = inviteEvent.poster.run {
|
||||
ImageViewerActivity.base64Image = inviteEvent.poster.run {
|
||||
if (this.startsWith("data:image/png;base64")) this.split(",")[1] else this
|
||||
}
|
||||
MessageShareUtils.getInstance(context).shareInviteFriends(context, inviteEvent.way)
|
||||
@ -269,7 +280,7 @@ class DefaultJsApi(var context: Context) {
|
||||
|
||||
@JavascriptInterface
|
||||
fun logoutExitWebViewAndRedirectToLogin() {
|
||||
UserRepository.getInstance(context).logout()
|
||||
UserRepository.getInstance().logout()
|
||||
if (context is Activity) {
|
||||
AppExecutor.uiExecutor.executeWithDelay(Runnable {
|
||||
context.ifLogin("内部网页")
|
||||
@ -280,22 +291,22 @@ class DefaultJsApi(var context: Context) {
|
||||
|
||||
@JavascriptInterface
|
||||
fun openInNewWebview(url: Any) {
|
||||
runOnUiThread { DirectUtils.directToWebView(context, url.toString(), "内部网页") }
|
||||
runOnUiThread { DirectUtils.directToWebView(context, url.toString(), entrance.ifBlank { "内部网页" }) }
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun postWearBadgeTask(msg: Any) {
|
||||
EnergyTaskHelper.postEnergyTask("wear_badge")
|
||||
EnergyBridge.postEnergyTask("wear_badge")
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun startEnergyCenter(msg: Any) {
|
||||
context.startActivity(EnergyCenterActivity.getIntent(context))
|
||||
context.startActivity(EnergyBridge.getEnergyCenterIntent(context))
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun startEnergyHouse(msg: Any) {
|
||||
context.startActivity(EnergyHouseActivity.getIntent(context))
|
||||
context.startActivity(EnergyBridge.getEnergyHouseIntent(context, null))
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
@ -342,6 +353,92 @@ class DefaultJsApi(var context: Context) {
|
||||
return NetworkUtils.isWifiConnected(context)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun enableBackToActivity(msg: Any) {
|
||||
FloatingBackViewManager.enableBackView(FloatingBackViewManager.TYPE_ACTIVITY, msg.toString())
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun startBBSStayTimeCount(msg: Any) {
|
||||
BbsStayTimeHelper.enableStayTimeCount(msg.toString().toInt())
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun saveBase64ImageToGallery(msg: Any) {
|
||||
val base64StringData = msg.toString()
|
||||
runOnUiThread {
|
||||
(context as? FragmentActivity)?.checkStoragePermissionBeforeAction {
|
||||
runOnIoThread {
|
||||
val base64String = base64StringData.replace("data:image/png;base64", "")
|
||||
tryWithDefaultCatch {
|
||||
val imageFile =
|
||||
File(HaloApp.getInstance().cacheDir.absolutePath + File.separator + System.currentTimeMillis() + ".png")
|
||||
val decodedString = Base64.decode(base64String, Base64.DEFAULT)
|
||||
val bos = BufferedOutputStream(FileOutputStream(imageFile))
|
||||
bos.write(decodedString)
|
||||
bos.flush()
|
||||
bos.close()
|
||||
|
||||
ImageUtils.saveImageToFile(imageFile, "", true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun loginWithCallback(msg: Any, handler: CompletionHandler<Any>) {
|
||||
mLoginHandler = handler
|
||||
login(msg)
|
||||
}
|
||||
|
||||
fun onLogin() {
|
||||
mLoginHandler?.complete(true)
|
||||
mLoginHandler = null
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun openInNewFullWebview(url: Any) {
|
||||
runOnUiThread { DirectUtils.directToFullScreenWebPage(context, url.toString(), true, entrance) }
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun startGameCollectionSquareBrowseTask(event: Any) {
|
||||
val browseTimeEvent = event.toString().toObject() ?: BrowseTaskEvent()
|
||||
GameCollectionSquareBrowseTaskHelper.enableBrowseTimeCount(
|
||||
browseTimeEvent.timeout.toInt(),
|
||||
browseTimeEvent.isFinished == "true"
|
||||
)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun checkUpdateGhzs(msg: Any) {
|
||||
context.startActivity(AboutActivity.getIntent(context, true))
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public fun clickGameActivityDownloadBtn(event: Any) {
|
||||
val gameActivityEvent = event.toString().toObject() ?: GameActivityEvent()
|
||||
GameActivityDownloadHelper.start(context, gameActivityEvent)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun isGameActivityTaskCompleted(event: Any, handler: CompletionHandler<Any>) {
|
||||
val gameActivityEvent = event.toString().toObject() ?: GameActivityEvent()
|
||||
GameActivityDownloadHelper.checkTaskComplete(context, gameActivityEvent, handler)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun postGameActivityExposureEvent(event: Any) {
|
||||
val gameActivityEvent = event.toString().toObject() ?: GameActivityEvent()
|
||||
GameActivityDownloadHelper.postExposureEvent(gameActivityEvent)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun getEntrance(msg: Any): String {
|
||||
return entrance
|
||||
}
|
||||
|
||||
@Keep
|
||||
internal data class ImageEvent(var imageList: ArrayList<String> = arrayListOf(), var position: Int = 0)
|
||||
|
||||
@ -349,11 +446,24 @@ class DefaultJsApi(var context: Context) {
|
||||
internal data class ImageShareEvent(var image: String = "", var type: String = "")
|
||||
|
||||
@Keep
|
||||
internal data class InviteFriendsEvent(var type: String = "",
|
||||
var way: String = "",
|
||||
var url: String = "",
|
||||
var poster: String = "")
|
||||
internal data class InviteFriendsEvent(
|
||||
var type: String = "",
|
||||
var way: String = "",
|
||||
var url: String = "",
|
||||
var poster: String = ""
|
||||
)
|
||||
|
||||
@Keep
|
||||
internal data class LogEvent(var jsonString: String = "", var logStore: String = "")
|
||||
|
||||
@Keep
|
||||
internal data class BrowseTaskEvent(var timeout: String = "", var isFinished: String = "")
|
||||
|
||||
@Keep
|
||||
data class GameActivityEvent(
|
||||
var gameId: String = "",
|
||||
var activityTitle: String = "",
|
||||
var activityId: String = "",
|
||||
var platform: String = ""
|
||||
)
|
||||
}
|
||||
|
||||
@ -5,20 +5,32 @@ import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.text.TextUtils
|
||||
import android.util.Base64
|
||||
import com.gh.gamecenter.core.utils.CurrentActivityHolder
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.util.DirectUtils.directToFeedback
|
||||
import com.gh.common.util.DirectUtils.directToGameDetailVideoStreaming
|
||||
import com.gh.common.util.DirectUtils.directToGameServerCalendar
|
||||
import com.gh.common.util.DirectUtils.directToGameVideo
|
||||
import com.gh.common.util.DirectUtils.directToLegacyVideoDetail
|
||||
import com.gh.common.util.DirectUtils.directToLinkPage
|
||||
import com.gh.common.util.DirectUtils.directToQa
|
||||
import com.gh.common.util.DirectUtils.directToVideoDetail
|
||||
import com.gh.common.util.GsonUtils.gson
|
||||
import com.gh.gamecenter.core.utils.GsonUtils.gson
|
||||
import com.gh.gamecenter.LibaoDetailActivity
|
||||
import com.gh.gamecenter.MainActivity
|
||||
import com.gh.gamecenter.NewsDetailActivity
|
||||
import com.gh.gamecenter.WebActivity
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.core.AppExecutor
|
||||
import com.gh.gamecenter.common.utils.DialogHelper
|
||||
import com.gh.gamecenter.common.utils.EnvHelper
|
||||
import com.gh.gamecenter.core.utils.ToastUtils
|
||||
import com.gh.gamecenter.entity.*
|
||||
import com.gh.gamecenter.gamecollection.publish.GameCollectionEditActivity
|
||||
import com.gh.gamecenter.qa.BbsType
|
||||
import com.gh.gamecenter.qa.video.publish.VideoPublishActivity
|
||||
import com.gh.gamecenter.subject.SubjectActivity
|
||||
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
|
||||
import com.lightgame.utils.Utils
|
||||
@ -28,6 +40,14 @@ object DefaultUrlHandler {
|
||||
|
||||
@JvmStatic
|
||||
fun interceptUrl(context: Context, url: String, entrance: String): Boolean {
|
||||
return interceptUrl(context, url, entrance, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bringAppToFront 是否需要在不匹配 host 的时候把 APP 调回到前台 (如微信调起)
|
||||
*/
|
||||
@JvmStatic
|
||||
fun interceptUrl(context: Context, url: String, entrance: String, bringAppToFront: Boolean = false): Boolean {
|
||||
val uri = Uri.parse(url)
|
||||
if ("ghzhushou" == uri.scheme) {
|
||||
Utils.log("url = $url")
|
||||
@ -38,13 +58,29 @@ object DefaultUrlHandler {
|
||||
if (!TextUtils.isEmpty(path)) {
|
||||
id = path!!.substring(1)
|
||||
}
|
||||
if (TextUtils.isEmpty(id)) {
|
||||
id = uri.getQueryParameter("id") ?: ""
|
||||
}
|
||||
|
||||
val intent: Intent
|
||||
when (host) {
|
||||
"article" -> context.startActivity(NewsDetailActivity.getIntentById(context, id, entrance))
|
||||
|
||||
"game" -> DirectUtils.directToGameDetail(context, id = id, tab = uri.getQueryParameter("to"), autoDownload = uri.getQueryParameter("auto_download") == "true", entrance = entrance)
|
||||
"game" -> DirectUtils.directToGameDetail(
|
||||
context,
|
||||
id = id,
|
||||
tab = uri.getQueryParameter("to"),
|
||||
autoDownload = uri.getQueryParameter("auto_download") == "true",
|
||||
entrance = entrance
|
||||
)
|
||||
|
||||
"column" -> SubjectActivity.startSubjectActivity(context, id, uri.getQueryParameter("name"), false, entrance)
|
||||
"column" -> SubjectActivity.startSubjectActivity(
|
||||
context,
|
||||
id,
|
||||
uri.getQueryParameter("name"),
|
||||
false,
|
||||
entrance
|
||||
)
|
||||
|
||||
"libao" -> context.startActivity(LibaoDetailActivity.getIntentById(context, id, entrance))
|
||||
|
||||
@ -55,7 +91,7 @@ object DefaultUrlHandler {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_QQ_QUN -> {
|
||||
EntranceConsts.HOST_QQ_QUN -> {
|
||||
val key = uri.getQueryParameter("key")
|
||||
if (!DirectUtils.directToQqGroup(context, key)) {
|
||||
Utils.toast(context, "请检查是否已经安装手机QQ")
|
||||
@ -63,9 +99,7 @@ object DefaultUrlHandler {
|
||||
}
|
||||
|
||||
"inurl" -> {
|
||||
intent = Intent(context, WebActivity::class.java)
|
||||
intent.putExtra(EntranceUtils.KEY_URL, uri.getQueryParameter("url"))
|
||||
context.startActivity(intent)
|
||||
DirectUtils.directToWebView(context, uri.getQueryParameter("url") ?: "", entrance)
|
||||
}
|
||||
|
||||
"outurl" -> {
|
||||
@ -82,6 +116,8 @@ object DefaultUrlHandler {
|
||||
}
|
||||
"question" -> DirectUtils.directToQuestionDetail(context, id, entrance, "文章链接")
|
||||
|
||||
"real_name" -> DirectUtils.directToRealName(context)
|
||||
|
||||
"community" -> {
|
||||
val community = CommunityEntity()
|
||||
community.id = id
|
||||
@ -120,11 +156,12 @@ object DefaultUrlHandler {
|
||||
}
|
||||
if ("articles" == type) {
|
||||
DirectUtils.directToCommunityArticle(
|
||||
context, typeId, communityId,
|
||||
entrance, "文章链接")
|
||||
context, typeId, communityId,
|
||||
entrance, "文章链接"
|
||||
)
|
||||
}
|
||||
}
|
||||
EntranceUtils.HOST_UPLOAD_VIDEO -> {
|
||||
EntranceConsts.HOST_UPLOAD_VIDEO -> {
|
||||
val titleParameter = uri.getQueryParameter("title")
|
||||
val title = if (titleParameter.isNullOrEmpty()) "" else "#$titleParameter#"
|
||||
val categoryId = uri.getQueryParameter("category_id") ?: ""
|
||||
@ -135,15 +172,29 @@ object DefaultUrlHandler {
|
||||
val tagActivityName = uri.getQueryParameter("tagActivityName") ?: ""
|
||||
val linkEntity = VideoLinkEntity(title, categoryId, link, tagActivityId, tagActivityName)
|
||||
val simpleGameEntity = SimpleGameEntity(gameId, gameName)
|
||||
CheckLoginUtils.checkLogin(context, null, true, EntranceUtils.ENTRANCE_BROWSER) {
|
||||
DirectUtils.directToVideoManager(context, linkEntity, simpleGameEntity, EntranceUtils.ENTRANCE_BROWSER, "")
|
||||
CheckLoginUtils.checkLogin(context, null, true, EntranceConsts.ENTRANCE_BROWSER) {
|
||||
DirectUtils.directToVideoManager(
|
||||
context,
|
||||
linkEntity,
|
||||
simpleGameEntity,
|
||||
EntranceConsts.ENTRANCE_BROWSER,
|
||||
""
|
||||
)
|
||||
}
|
||||
}
|
||||
EntranceUtils.HOST_USERHOME -> {
|
||||
EntranceConsts.HOST_USERHOME -> {
|
||||
val position = uri.getQueryParameter("position")
|
||||
DirectUtils.directToHomeActivity(context, id, if (position.isNullOrEmpty()) -1 else position.toInt(), entrance, "")
|
||||
val subtype = uri.getQueryParameter("sub_type") ?: ""
|
||||
DirectUtils.directToHomeActivity(
|
||||
context,
|
||||
id,
|
||||
subtype,
|
||||
if (position.isNullOrEmpty()) -1 else position.toInt(),
|
||||
entrance,
|
||||
""
|
||||
)
|
||||
}
|
||||
EntranceUtils.HOST_VIDEO_MORE -> {
|
||||
EntranceConsts.HOST_VIDEO_MORE -> {
|
||||
val referer = uri.getQueryParameter("referer") ?: ""
|
||||
val type = uri.getQueryParameter("type") ?: ""
|
||||
val act = uri.getQueryParameter("act") ?: ""
|
||||
@ -151,7 +202,7 @@ object DefaultUrlHandler {
|
||||
val fieldId = uri.getQueryParameter("fieldId") ?: ""
|
||||
val sectionName = uri.getQueryParameter("sectionName") ?: ""
|
||||
val paginationType = uri.getQueryParameter("paginationType")
|
||||
?: "page"//活动分页方式 page filter
|
||||
?: "page"//活动分页方式 page filter
|
||||
val location = if (!TextUtils.isEmpty(act)) {
|
||||
VideoDetailContainerViewModel.Location.VIDEO_ACTIVITY.value
|
||||
} else if (!TextUtils.isEmpty(fieldId)) {
|
||||
@ -159,45 +210,64 @@ object DefaultUrlHandler {
|
||||
} else {
|
||||
id
|
||||
}
|
||||
directToVideoDetail(context, id, location, false, gameId, entrance, "", referer, type, act, paginationType, fieldId, sectionName)
|
||||
directToLegacyVideoDetail(
|
||||
context,
|
||||
id,
|
||||
location,
|
||||
false,
|
||||
gameId,
|
||||
entrance,
|
||||
"",
|
||||
referer,
|
||||
type,
|
||||
act,
|
||||
paginationType,
|
||||
fieldId,
|
||||
sectionName
|
||||
)
|
||||
}
|
||||
EntranceUtils.HOST_VIDEO_SINGLE -> {
|
||||
EntranceConsts.HOST_VIDEO_DETAIL -> {
|
||||
DirectUtils.directToVideoDetail(context, id, entrance, path)
|
||||
}
|
||||
EntranceConsts.HOST_VIDEO_SINGLE -> {
|
||||
val referer = uri.getQueryParameter("referer") ?: ""
|
||||
directToVideoDetail(context, id, VideoDetailContainerViewModel.Location.SINGLE_VIDEO.value,
|
||||
false, "", entrance, "", if (TextUtils.isEmpty(referer)) "" else referer)
|
||||
DirectUtils.directToVideoDetail(
|
||||
context, id, VideoDetailContainerViewModel.Location.SINGLE_VIDEO.value,
|
||||
false, "", entrance, "", if (TextUtils.isEmpty(referer)) "" else referer
|
||||
)
|
||||
}
|
||||
EntranceUtils.HOST_VIDEO_STREAMING_HOME -> {
|
||||
EntranceConsts.HOST_VIDEO_STREAMING_HOME -> {
|
||||
intent = Intent(context, MainActivity::class.java)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
intent.putExtra(MainActivity.SWITCH_TO_VIDEO, true)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
EntranceUtils.HOST_VIDEO_STREAMING_DESC -> {
|
||||
EntranceConsts.HOST_VIDEO_STREAMING_DESC -> {
|
||||
directToGameDetailVideoStreaming(context, id, entrance)
|
||||
}
|
||||
EntranceUtils.HOST_VIDEO_COLLECTION -> {
|
||||
EntranceConsts.HOST_VIDEO_COLLECTION -> {
|
||||
directToGameVideo(context, id, entrance, "")
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_CATEGORY -> {
|
||||
EntranceConsts.HOST_CATEGORY -> {
|
||||
val title = uri.getQueryParameter("title")
|
||||
DirectUtils.directCategoryDirectory(context, id, title ?: "", entrance, "")
|
||||
}
|
||||
EntranceUtils.HOST_COLUMN_COLLECTION -> {
|
||||
EntranceConsts.HOST_COLUMN_COLLECTION -> {
|
||||
val name = uri.getQueryParameter("name")
|
||||
DirectUtils.directToColumnCollection(context, id, -1, entrance, name ?: "")
|
||||
}
|
||||
EntranceUtils.HOST_COLUMN -> {
|
||||
DirectUtils.directToSubject(context, id, uri.getQueryParameter(EntranceUtils.KEY_NAME), entrance)
|
||||
EntranceConsts.HOST_COLUMN -> {
|
||||
DirectUtils.directToSubject(context, id, uri.getQueryParameter(EntranceConsts.KEY_NAME), entrance)
|
||||
}
|
||||
EntranceUtils.HOST_COMMUNITY_QUESTION_LABEL_DETAIL -> {
|
||||
EntranceConsts.HOST_COMMUNITY_QUESTION_LABEL_DETAIL -> {
|
||||
val community = CommunityEntity()
|
||||
community.id = uri.getQueryParameter("community_id") ?: ""
|
||||
community.name = uri.getQueryParameter("community_name") ?: ""
|
||||
val tag = uri.getQueryParameter("tag") ?: ""
|
||||
DirectUtils.directAskColumnLabelDetail(context, tag, community, entrance, "")
|
||||
}
|
||||
EntranceUtils.HOST_COMMUNITY_COLUMN_DETAIL -> {
|
||||
EntranceConsts.HOST_COMMUNITY_COLUMN_DETAIL -> {
|
||||
val community = CommunityEntity()
|
||||
community.id = uri.getQueryParameter("community_id") ?: ""
|
||||
community.name = uri.getQueryParameter("community_name") ?: ""
|
||||
@ -205,42 +275,42 @@ object DefaultUrlHandler {
|
||||
DirectUtils.directAskColumnDetail(context, columnId, community, entrance, "")
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_BLOCK -> {
|
||||
EntranceConsts.HOST_BLOCK -> {
|
||||
val name = uri.getQueryParameter("name")
|
||||
?: ""
|
||||
?: ""
|
||||
val entity = SubjectRecommendEntity(link = id, name = name, text = name)
|
||||
DirectUtils.directToBlock(context, entity, entrance)
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_SERVER_BLOCK -> {
|
||||
EntranceConsts.HOST_SERVER_BLOCK -> {
|
||||
DirectUtils.directToGameServers(context, entrance = entrance, path = "")
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_AMWAY_BLOCK -> {
|
||||
EntranceConsts.HOST_AMWAY_BLOCK -> {
|
||||
DirectUtils.directToAmway(context, entrance = entrance, path = "")
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_HELP -> {
|
||||
EntranceConsts.HOST_HELP -> {
|
||||
val name = uri.getQueryParameter("name")
|
||||
?: ""
|
||||
?: ""
|
||||
DirectUtils.directToQa(context, name, id)
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_HELP_COLLECTION -> {
|
||||
EntranceConsts.HOST_HELP_COLLECTION -> {
|
||||
val name = uri.getQueryParameter("name")
|
||||
?: ""
|
||||
?: ""
|
||||
DirectUtils.directToQaCollection(context, name, id)
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_GAME_UPLOAD -> {
|
||||
EntranceConsts.HOST_GAME_UPLOAD -> {
|
||||
DirectUtils.directGameUpload(context, entrance = entrance, path = "")
|
||||
}
|
||||
EntranceUtils.HOST_GAME_ZONE -> {
|
||||
EntranceConsts.HOST_GAME_ZONE -> {
|
||||
val zoneUrl = uri.getQueryParameter("url") ?: ""
|
||||
DirectUtils.directGameZone(context, id, zoneUrl, entrance)
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_LINK -> {
|
||||
EntranceConsts.HOST_LINK -> {
|
||||
try {
|
||||
val dataString = uri.getQueryParameter("data")
|
||||
if (!TextUtils.isEmpty(dataString)) {
|
||||
@ -254,61 +324,186 @@ object DefaultUrlHandler {
|
||||
}
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_GAME_NEWS -> {
|
||||
EntranceConsts.HOST_GAME_NEWS -> {
|
||||
DirectUtils.directToGameNews(
|
||||
context,
|
||||
uri.getQueryParameter(EntranceUtils.KEY_GAME_ID),
|
||||
uri.getQueryParameter(EntranceUtils.KEY_GAME_NAME),
|
||||
entrance);
|
||||
context,
|
||||
uri.getQueryParameter(EntranceConsts.KEY_GAME_ID),
|
||||
uri.getQueryParameter(EntranceConsts.KEY_GAME_NAME),
|
||||
entrance
|
||||
);
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_GAME_CALENDAR -> {
|
||||
directToGameServerCalendar(context, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID))
|
||||
EntranceConsts.HOST_GAME_CALENDAR -> {
|
||||
directToGameServerCalendar(context, uri.getQueryParameter(EntranceConsts.KEY_GAME_ID))
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_HISTORY_APK -> {
|
||||
DirectUtils.directToHistoryApk(context, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID))
|
||||
EntranceConsts.HOST_HISTORY_APK -> {
|
||||
DirectUtils.directToHistoryApk(context, uri.getQueryParameter(EntranceConsts.KEY_GAME_ID))
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_FORUM_DETAIL -> {
|
||||
EntranceConsts.HOST_FORUM_DETAIL -> {
|
||||
DirectUtils.directForumDetail(context, id, entrance)
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_GAME_RATING_DETAIL -> {
|
||||
DirectUtils.directToGameRatingDetail(context, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID), uri.getQueryParameter(EntranceUtils.KEY_COMMENT_ID), EntranceUtils.ENTRANCE_BROWSER)
|
||||
EntranceConsts.HOST_GAME_RATING_DETAIL -> {
|
||||
DirectUtils.directToGameRatingDetail(
|
||||
context,
|
||||
uri.getQueryParameter(EntranceConsts.KEY_GAME_ID),
|
||||
uri.getQueryParameter(EntranceConsts.KEY_COMMENT_ID),
|
||||
EntranceConsts.ENTRANCE_BROWSER
|
||||
)
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_FORUM -> {
|
||||
DirectUtils.directToForum(context)
|
||||
EntranceConsts.HOST_FORUM -> {
|
||||
val position = uri.getQueryParameter(EntranceConsts.KEY_POSITION)?.toInt()
|
||||
|
||||
DirectUtils.directToForum(context, position ?: 0)
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_SUGGESTION -> {
|
||||
val platform = uri.getQueryParameter(EntranceUtils.KEY_PLATFORM)
|
||||
EntranceConsts.HOST_UPLOAD_VIDEO_NEW -> {
|
||||
val activityName = uri.getQueryParameter("activity_name") ?: ""
|
||||
val activityId = uri.getQueryParameter("activity_id") ?: ""
|
||||
val original = uri.getQueryParameter("original") ?: ""
|
||||
val forumName = uri.getQueryParameter("forum_name") ?: ""
|
||||
val forumId = uri.getQueryParameter("forum_id") ?: ""
|
||||
val forumIcon = uri.getQueryParameter("forum_icon") ?: ""
|
||||
val forumType = uri.getQueryParameter("forum_type") ?: BbsType.OFFICIAL_BBS.value
|
||||
val gameId = uri.getQueryParameter("game_id") ?: ""
|
||||
val gameName = uri.getQueryParameter("game_name") ?: ""
|
||||
val icon = uri.getQueryParameter("game_icon") ?: ""
|
||||
val iconSubscript = uri.getQueryParameter("game_icon_subscript") ?: ""
|
||||
val gameEntity =
|
||||
if (forumType == BbsType.OFFICIAL_BBS.value && gameId.isNotEmpty() && gameName.isNotEmpty() && icon.isNotEmpty()) {
|
||||
GameEntity(id = gameId, mName = gameName, mIcon = icon, mIconSubscript = iconSubscript)
|
||||
} else null
|
||||
val activityLabelEntity = if (activityId.isNotEmpty() && activityName.isNotEmpty()) {
|
||||
ActivityLabelEntity(
|
||||
id = activityId,
|
||||
name = activityName,
|
||||
original = original.ifEmpty { "false" }.toBoolean()
|
||||
)
|
||||
} else null
|
||||
val communityEntity =
|
||||
if (forumId.isNotEmpty() && forumName.isNotEmpty() && forumIcon.isNotEmpty()) {
|
||||
CommunityEntity(id = forumId, name = forumName, icon = forumIcon)
|
||||
} else null
|
||||
|
||||
context.startActivity(
|
||||
VideoPublishActivity.getIntent(
|
||||
context,
|
||||
communityEntity,
|
||||
gameEntity,
|
||||
activityLabelEntity,
|
||||
forumType,
|
||||
disableForumSelection = false,
|
||||
isFromCommunityActivity = true,
|
||||
entrance,
|
||||
""
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
EntranceConsts.HOST_SUGGESTION -> {
|
||||
val platform = uri.getQueryParameter(EntranceConsts.KEY_PLATFORM)
|
||||
val platformName = PlatformUtils.getInstance(context).getPlatformName(platform)
|
||||
val gameId = uri.getQueryParameter(EntranceUtils.KEY_GAMEID)
|
||||
val packageMd5 = uri.getQueryParameter(EntranceUtils.KEY_PACKAGE_MD5)
|
||||
val isQaFeedback = uri.getQueryParameter(EntranceUtils.KEY_IS_QA_FEEDBACK) == "true"
|
||||
val content = if (TextUtils.isEmpty(gameId) || TextUtils.isEmpty(packageMd5)) String.format("%s-%s-V%s,",
|
||||
uri.getQueryParameter(EntranceUtils.KEY_GAME_NAME),
|
||||
if (TextUtils.isEmpty(platformName)) platform else platformName,
|
||||
uri.getQueryParameter(EntranceUtils.KEY_VERSION)) else String.format("%s-%s-V%s\n游戏ID:%s\n游戏包MD5:%s\n",
|
||||
uri.getQueryParameter(EntranceUtils.KEY_GAME_NAME),
|
||||
if (TextUtils.isEmpty(platformName)) platform else platformName,
|
||||
uri.getQueryParameter(EntranceUtils.KEY_VERSION), gameId, packageMd5)
|
||||
val gameId = uri.getQueryParameter(EntranceConsts.KEY_GAMEID)
|
||||
val packageMd5 = uri.getQueryParameter(EntranceConsts.KEY_PACKAGE_MD5)
|
||||
val isQaFeedback = uri.getQueryParameter(EntranceConsts.KEY_IS_QA_FEEDBACK) == "true"
|
||||
val content = if (TextUtils.isEmpty(gameId) || TextUtils.isEmpty(packageMd5)) String.format(
|
||||
"%s-%s-V%s,",
|
||||
uri.getQueryParameter(EntranceConsts.KEY_GAME_NAME),
|
||||
if (TextUtils.isEmpty(platformName)) platform else platformName,
|
||||
uri.getQueryParameter(EntranceConsts.KEY_VERSION)
|
||||
) else String.format(
|
||||
"%s-%s-V%s\n游戏ID:%s\n游戏包MD5:%s\n",
|
||||
uri.getQueryParameter(EntranceConsts.KEY_GAME_NAME),
|
||||
if (TextUtils.isEmpty(platformName)) platform else platformName,
|
||||
uri.getQueryParameter(EntranceConsts.KEY_VERSION), gameId, packageMd5
|
||||
)
|
||||
val qaId = uri.getQueryParameter("qa_id") ?: ""
|
||||
val qaTitle = uri.getQueryParameter(EntranceUtils.KEY_QA_TITLE)
|
||||
val qaContentId = uri.getQueryParameter(EntranceConsts.KEY_QA_CONTENT_ID) ?: ""
|
||||
val qaTitle = uri.getQueryParameter(EntranceConsts.KEY_QA_TITLE)
|
||||
if (!TextUtils.isEmpty(qaId)) {
|
||||
directToQa(context, qaTitle, qaId)
|
||||
} else {
|
||||
directToFeedback(context, content, null, isQaFeedback, EntranceUtils.ENTRANCE_BROWSER)
|
||||
directToFeedback(
|
||||
context,
|
||||
content,
|
||||
null,
|
||||
isQaFeedback,
|
||||
qaContentId,
|
||||
EntranceConsts.ENTRANCE_BROWSER
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_HELP_AND_FEEDBACK -> {
|
||||
EntranceConsts.HOST_HELP_AND_FEEDBACK -> {
|
||||
val position = uri.getQueryParameter("position") ?: ""
|
||||
DirectUtils.directToHelpAndFeedback(context, position.toInt())
|
||||
}
|
||||
else -> DialogHelper.showUpgradeDialog(context)
|
||||
|
||||
EntranceConsts.HOST_HELP_DETAIL -> {
|
||||
var url = uri.getQueryParameter("url")
|
||||
if (!url.isNullOrEmpty()) {
|
||||
context.startActivity(WebActivity.getIntent(context, url, false))
|
||||
} else {
|
||||
url = if (EnvHelper.isDevEnv) {
|
||||
Constants.HELP_ADDRESS_DEV
|
||||
} else {
|
||||
Constants.HELP_ADDRESS
|
||||
}
|
||||
val id = uri.getQueryParameter("id")
|
||||
val name = uri.getQueryParameter("name")
|
||||
val qaCollectionId = uri.getQueryParameter("collection_id")
|
||||
context.startActivity(
|
||||
WebActivity.getIntent(
|
||||
context,
|
||||
"$url$id",
|
||||
name,
|
||||
true,
|
||||
!qaCollectionId.isNullOrEmpty()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
EntranceConsts.HOST_GAME_COLLECTION_DETAIL -> {
|
||||
DirectUtils.directToGameCollectionDetail(context, id, entrance)
|
||||
}
|
||||
|
||||
EntranceConsts.HOST_GAME_COLLECTION_SQUARE -> {
|
||||
DirectUtils.directToGameCollectionSquare(context, entrance)
|
||||
}
|
||||
|
||||
EntranceConsts.HOST_GAME_COLLECTION_EDIT -> {
|
||||
val activityId = uri.getQueryParameter("activity_id") ?: ""
|
||||
val activityName = uri.getQueryParameter("activity_name") ?: ""
|
||||
val gameId = uri.getQueryParameter("game_id") ?: ""
|
||||
context.startActivity(
|
||||
GameCollectionEditActivity.getIntent(
|
||||
context,
|
||||
activityId,
|
||||
activityName,
|
||||
gameId,
|
||||
entrance
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
if (bringAppToFront) {
|
||||
DirectUtils.directToMainActivity(context)
|
||||
if (!TextUtils.isEmpty(host)) {
|
||||
AppExecutor.uiExecutor.executeWithDelay({
|
||||
CurrentActivityHolder.getCurrentActivity()?.let {
|
||||
DialogHelper.showUpgradeDialog(it)
|
||||
}
|
||||
}, 200)
|
||||
}
|
||||
} else {
|
||||
DialogHelper.showUpgradeDialog(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
} else if ("zhiqu" == uri.scheme) {
|
||||
@ -356,19 +551,32 @@ object DefaultUrlHandler {
|
||||
|
||||
@JvmStatic
|
||||
fun transformNormalScheme(context: Context, url: String, entrance: String): Boolean {
|
||||
val b = transformNewNormalScheme(context, url, entrance)
|
||||
if (b) return b
|
||||
return transformOldNormalScheme(context, url, entrance)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun transformOldNormalScheme(context: Context, url: String, entrance: String): Boolean {
|
||||
val uri = Uri.parse(url)
|
||||
if (uri.host == "www.ghzs666.com"
|
||||
|| uri.host == "www.ghzs.com"
|
||||
|| uri.host == "ask.ghzs.com"
|
||||
|| uri.host == "m.ghzs.com"
|
||||
|| uri.host == "m.ghzs666.com") {
|
||||
|| uri.host == "www.ghzs.com"
|
||||
|| uri.host == "ask.ghzs.com"
|
||||
|| uri.host == "m.ghzs.com"
|
||||
|| uri.host == "m.ghzs666.com"
|
||||
) {
|
||||
Utils.log(uri.path)
|
||||
uri.path?.apply {
|
||||
when {
|
||||
contains("game") -> {
|
||||
val gameId = uri.getQueryParameter("gameId") ?: uri.pathSegments.last()
|
||||
?: ""
|
||||
DirectUtils.directToGameDetail(context, gameId, entrance, autoDownload = false, traceEvent = null)
|
||||
val gameId = uri.getQueryParameter("gameId") ?: uri.pathSegments.last() ?: ""
|
||||
DirectUtils.directToGameDetail(
|
||||
context,
|
||||
gameId,
|
||||
entrance,
|
||||
autoDownload = false,
|
||||
traceEvent = null
|
||||
)
|
||||
}
|
||||
contains("question") -> {
|
||||
val questionId = split("/")[2]
|
||||
@ -384,7 +592,10 @@ object DefaultUrlHandler {
|
||||
var communityId = ""
|
||||
var type = ""
|
||||
var typeId = ""
|
||||
val split = replace("/communities", "").replace("/bbs", "").replace(".html", "").split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
val split =
|
||||
replace("/communities", "").replace("/bbs", "").replace(".html", "").split("/".toRegex())
|
||||
.dropLastWhile { it.isEmpty() }
|
||||
.toTypedArray()
|
||||
for (text in split) {
|
||||
if (TextUtils.isEmpty(communityId)) {
|
||||
communityId = text
|
||||
@ -400,8 +611,9 @@ object DefaultUrlHandler {
|
||||
}
|
||||
if ("articles" == type || "article" == type) {
|
||||
DirectUtils.directToCommunityArticle(
|
||||
context, typeId, communityId,
|
||||
entrance, "文章链接")
|
||||
context, typeId, communityId,
|
||||
entrance, "文章链接"
|
||||
)
|
||||
}
|
||||
}
|
||||
contains("article") -> {
|
||||
@ -418,14 +630,84 @@ object DefaultUrlHandler {
|
||||
val name = uri.getQueryParameter("communityName") ?: ""
|
||||
DirectUtils.directToCommunityColumn(context, CommunityEntity(id, name), columnsId, entrance, "")
|
||||
}
|
||||
contains("zone") -> {
|
||||
contains("zone") && split("/").size > 2 -> {
|
||||
val gameId = split("/")[2]
|
||||
DirectUtils.directGameZone(context, gameId, url, entrance)
|
||||
}
|
||||
else -> return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun transformNewNormalScheme(context: Context, url: String, entrance: String): Boolean {
|
||||
val uri = Uri.parse(url)
|
||||
if (uri.host == "www.ghzs666.com"
|
||||
|| uri.host == "www.ghzs.com"
|
||||
|| uri.host == "ask.ghzs.com"
|
||||
|| uri.host == "m.ghzs.com"
|
||||
|| uri.host == "m.ghzs666.com"
|
||||
|| uri.host == "dev-bbs-mobile.ghzs.com"
|
||||
) {
|
||||
Utils.log(uri.path)
|
||||
uri.path?.apply {
|
||||
val splits = split("/")
|
||||
when {
|
||||
//https://m.ghzs666.com/bbs/thread-帖子ID
|
||||
splits.size >= 3 && splits[1] == "bbs" && splits[2].startsWith("thread-") -> {
|
||||
val articleId = splits[2].substring(7)
|
||||
DirectUtils.directToCommunityArticle(
|
||||
context, articleId, "",
|
||||
entrance, "文章链接"
|
||||
)
|
||||
}
|
||||
//https://m.ghzs666.com/article/文章ID
|
||||
splits.size >= 3 && splits[1] == "article" -> {
|
||||
val articleId = splits[2]
|
||||
DirectUtils.directToArticle(context, articleId, entrance)
|
||||
}
|
||||
//https://m.ghzs666.com/column/专题ID
|
||||
splits.size >= 3 && splits[1] == "column" -> {
|
||||
val columnId = splits[2]
|
||||
DirectUtils.directToSubject(context, columnId, "", entrance)
|
||||
}
|
||||
//https://m.ghzs666.com/zone/游戏ID
|
||||
splits.size >= 3 && splits[1] == "zone" -> {
|
||||
DirectUtils.directToWebView(context, url, entrance)
|
||||
}
|
||||
//https://m.ghzs666.com/bbs/video-视频ID
|
||||
splits.size >= 3 && splits[1] == "bbs" && splits[2].startsWith("video-") -> {
|
||||
val videoId = splits[2].substring(6)
|
||||
DirectUtils.directToVideoDetail(context, videoId, entrance)
|
||||
}
|
||||
else -> return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 url 转换为 LinkEntity (实际只有 type 和 link 两个字段,仅供日志,不保证能用)
|
||||
*/
|
||||
fun urlToLinkEntity(url: String): LinkEntity? {
|
||||
val uri = Uri.parse(url)
|
||||
if ("ghzhushou" == uri.scheme) {
|
||||
Utils.log("url = $url")
|
||||
Utils.log("url = " + uri.scheme!!)
|
||||
val host = uri.host
|
||||
val path = uri.path
|
||||
var id = ""
|
||||
if (!TextUtils.isEmpty(path)) {
|
||||
id = path!!.substring(1)
|
||||
}
|
||||
return LinkEntity(type = host, link = id)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
@ -2,13 +2,14 @@ package com.gh.common
|
||||
|
||||
import com.gh.common.exposure.ExposureManager
|
||||
import com.gh.common.filter.RegionSettingHelper
|
||||
import com.gh.common.loghub.LoghubUtils
|
||||
import com.gh.common.util.doOnMainProcessOnly
|
||||
import com.gh.common.util.tryCatchInRelease
|
||||
import com.gh.gamecenter.common.loghub.LoghubUtils
|
||||
import com.gh.gamecenter.common.utils.doOnMainProcessOnly
|
||||
import com.gh.gamecenter.common.utils.tryCatchInRelease
|
||||
import com.gh.common.videolog.VideoRecordUtils
|
||||
import com.gh.download.DownloadDataHelper
|
||||
import com.gh.gamecenter.entity.TimeEntity
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
import com.gh.gamecenter.common.retrofit.Response
|
||||
import com.gh.gamecenter.core.runOnUiThread
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
@ -35,19 +36,23 @@ object FixedRateJobHelper {
|
||||
fixedRateTimer("Global-Fixed-Rate-Timer", initialDelay = 100, period = CHECKER_PERIOD) {
|
||||
// 时间校对,10分钟一次
|
||||
if ((mExecuteCount * CHECKER_PERIOD) % TIME_PERIOD == 0L) {
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application).api.time
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(object : Response<TimeEntity>() {
|
||||
override fun onResponse(response: TimeEntity?) {
|
||||
val serverTime = response?.time
|
||||
serverTime?.let { timeDeltaBetweenServerAndClient = it * 1000 - System.currentTimeMillis() }
|
||||
RetrofitManager.getInstance().api.time
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(object : Response<TimeEntity>() {
|
||||
override fun onResponse(response: TimeEntity?) {
|
||||
val serverTime = response?.time
|
||||
serverTime?.let {
|
||||
timeDeltaBetweenServerAndClient = it * 1000 - System.currentTimeMillis()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 提交曝光数据
|
||||
if ((mExecuteCount * CHECKER_PERIOD) % EXPOSURE_PERIOD == 0L) {
|
||||
ExposureManager.commitSavedExposureEvents(true)
|
||||
runOnUiThread {
|
||||
ExposureManager.commitSavedExposureEvents(true)
|
||||
}
|
||||
}
|
||||
|
||||
// 分片检测下载进度
|
||||
@ -60,7 +65,9 @@ object FixedRateJobHelper {
|
||||
|
||||
// 提交普通 loghub 数据
|
||||
if ((mExecuteCount * CHECKER_PERIOD) % LOGHUB_PERIOD == 0L) {
|
||||
LoghubUtils.commitSavedLoghubEvents()
|
||||
runOnUiThread {
|
||||
LoghubUtils.commitSavedLoghubEvents(true)
|
||||
}
|
||||
}
|
||||
|
||||
// 更新游戏屏蔽信息
|
||||
|
||||
@ -1,39 +0,0 @@
|
||||
//package com.gh.common
|
||||
//
|
||||
//import android.content.BroadcastReceiver
|
||||
//import android.content.Context
|
||||
//import android.content.Intent
|
||||
//import com.gh.common.im.ImManager
|
||||
//import com.gh.gamecenter.manager.UserManager
|
||||
//import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
//import com.halo.assistant.HaloApp
|
||||
//import com.m7.imkfsdk.chat.ChatActivity
|
||||
//import io.reactivex.schedulers.Schedulers
|
||||
//
|
||||
///**
|
||||
// * 可使用 [LocalBroadcastManager] 来进行简单的模块间消息通知
|
||||
// */
|
||||
//
|
||||
//class LocalBroadcastReceiver : BroadcastReceiver() {
|
||||
//
|
||||
// override fun onReceive(context: Context?, intent: Intent?) {
|
||||
// intent?.let {
|
||||
// when (intent.action) {
|
||||
// ChatActivity.ACTION_DISMISS_FLOATING_WINDOW -> {
|
||||
// ImManager.dismissFloatingWindow()
|
||||
//
|
||||
// RetrofitManager.getInstance(HaloApp.getInstance().application).api.postImEnding(UserManager.getInstance().userId)
|
||||
// .subscribeOn(Schedulers.io())
|
||||
// .subscribe()
|
||||
// }
|
||||
//
|
||||
// ChatActivity.ACTION_HIDE_UNREAD_DOT -> {
|
||||
// ImManager.updateShouldShowFloatingWindowDot(false)
|
||||
// }
|
||||
//
|
||||
// else -> return
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//}
|
||||
@ -1,117 +0,0 @@
|
||||
package com.gh.common
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import com.gh.gamecenter.entity.AliasEntity
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
object PushManager {
|
||||
|
||||
var deviceToken: String? = ""
|
||||
|
||||
private var mPreviousAlias: AliasEntity? = null
|
||||
private var mApplication = HaloApp.getInstance().application
|
||||
|
||||
const val SP_PUSH_ALIAS = "push_alias"
|
||||
|
||||
@JvmStatic
|
||||
fun init(channel: String) {
|
||||
// tryWithDefaultCatch {
|
||||
// //初始化友盟推送
|
||||
// UMConfigure.init(mApplication, Config.UMENG_APPKEY, channel, UMConfigure.DEVICE_TYPE_PHONE, Config.UMENG_MESSAGE_SECRET)
|
||||
//
|
||||
// val pushAgent = PushAgent.getInstance(mApplication)
|
||||
//
|
||||
// runOnIoThread { registerDevice() }
|
||||
//
|
||||
// // 注册小米、华为和魅族通道
|
||||
// MiPushRegistar.register(mApplication, Config.MIPUSH_APPID, Config.MIPUSH_APPKEY)
|
||||
// HuaWeiRegister.register(mApplication)
|
||||
// MeizuRegister.register(mApplication, BuildConfig.MEIZUPUSH_APPID, BuildConfig.MEIZUPUSH_APPKEY)
|
||||
//
|
||||
// val aliasInSp = PreferenceManager.getDefaultSharedPreferences(mApplication).getString(SP_PUSH_ALIAS, "")
|
||||
// mPreviousAlias = aliasInSp?.toObject()
|
||||
//
|
||||
// if (mPreviousAlias == null) {
|
||||
// getAndSetAlias()
|
||||
// }
|
||||
//
|
||||
// // 完全自定义处理(透传)
|
||||
// pushAgent.setPushIntentServiceClass(GHUmengNotificationService::class.java)
|
||||
// }
|
||||
}
|
||||
|
||||
private fun registerDevice() {
|
||||
// PushAgent.getInstance(mApplication).register(object : IUmengRegisterCallback {
|
||||
// override fun onSuccess(dToken: String) {
|
||||
// //注册成功会返回device token
|
||||
// deviceToken = dToken
|
||||
// getAndSetAlias()
|
||||
// Utils.log("deviceToken::$dToken")
|
||||
// }
|
||||
//
|
||||
// override fun onFailure(s: String, s1: String) {
|
||||
// Utils.log("deviceToken::" + "注册失败")
|
||||
// }
|
||||
// })
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
@JvmStatic
|
||||
fun getAndSetAlias() {
|
||||
// if (deviceToken.isNullOrEmpty()) {
|
||||
// registerDevice()
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// val meta = MetaUtil.getMeta()
|
||||
//
|
||||
// val jsonObject = JSONObject()
|
||||
// jsonObject.put("device_token", deviceToken)
|
||||
// jsonObject.put("imei", meta.imei)
|
||||
// jsonObject.put("android_id", meta.android_id)
|
||||
// jsonObject.put("model", meta.model)
|
||||
// jsonObject.put("manufacturer", meta.manufacturer)
|
||||
// jsonObject.put("os", meta.os)
|
||||
// jsonObject.put("os_version", meta.android_version)
|
||||
// jsonObject.put("mac", meta.mac)
|
||||
// jsonObject.put("gid", meta.gid)
|
||||
//
|
||||
// val body = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
|
||||
//
|
||||
// RetrofitManager.getInstance(mApplication).api.getAlias(body)
|
||||
// .subscribeOn(Schedulers.io())
|
||||
// .subscribe(
|
||||
// { setAlias(it) },
|
||||
// { it.printStackTrace() }
|
||||
// )
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setAlias(alias: AliasEntity) {
|
||||
// val pushAgent = PushAgent.getInstance(mApplication)
|
||||
//
|
||||
// mPreviousAlias = alias
|
||||
// PreferenceManager.getDefaultSharedPreferences(mApplication).edit {
|
||||
// putString(SP_PUSH_ALIAS, mPreviousAlias?.toJson())
|
||||
// }
|
||||
//
|
||||
// pushAgent.setAlias(alias.alias, alias.aliasType) { b, s ->
|
||||
// Utils.log("注册别名 $b + $s")
|
||||
// }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun deleteAlias() {
|
||||
// val pushAgent = PushAgent.getInstance(mApplication)
|
||||
//
|
||||
// mPreviousAlias?.let {
|
||||
// pushAgent.deleteAlias(it.alias, it.aliasType) { b, s ->
|
||||
// Utils.log("删除别名 $b + $s")
|
||||
// }
|
||||
// }
|
||||
// PreferenceManager.getDefaultSharedPreferences(mApplication).edit {
|
||||
// putString(SP_PUSH_ALIAS, "")
|
||||
// }
|
||||
// mPreviousAlias = null
|
||||
}
|
||||
}
|
||||
@ -1,123 +0,0 @@
|
||||
package com.gh.common
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Application
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import com.gh.base.GHThreadFactory
|
||||
import com.halo.assistant.HaloApp
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
/**
|
||||
* 统计用户在当前 Fragment/Activity 的停留时间,在 onViewDestroy 或 onDestroy 里获取 elapsedTime 即可,单位为秒
|
||||
*/
|
||||
class TimeElapsedHelper(val fragment: Fragment?, val activity: Activity?) {
|
||||
|
||||
constructor() : this(null, null)
|
||||
|
||||
constructor(fragment: Fragment) : this(fragment, null)
|
||||
|
||||
constructor(activity: Activity) : this(null, activity)
|
||||
|
||||
private var isWorking = false
|
||||
|
||||
var elapsedTime: Int = 0
|
||||
|
||||
var timeout: Int = 0
|
||||
var timeoutCallback: TimeoutCallback? = null
|
||||
|
||||
init {
|
||||
activity?.application?.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {
|
||||
override fun onActivityStarted(a: Activity) {
|
||||
}
|
||||
|
||||
override fun onActivitySaveInstanceState(a: Activity, outState: Bundle) {
|
||||
}
|
||||
|
||||
override fun onActivityStopped(a: Activity) {
|
||||
}
|
||||
|
||||
override fun onActivityCreated(a: Activity, savedInstanceState: Bundle?) {
|
||||
}
|
||||
|
||||
override fun onActivityPaused(a: Activity) {
|
||||
if (activity == a) {
|
||||
pauseCounting()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResumed(a: Activity) {
|
||||
if (activity == a) {
|
||||
resumeCounting()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityDestroyed(a: Activity) {
|
||||
if (activity == a) {
|
||||
HaloApp.getInstance().application.unregisterActivityLifecycleCallbacks(this)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
fragment?.fragmentManager?.registerFragmentLifecycleCallbacks(
|
||||
object : FragmentManager.FragmentLifecycleCallbacks() {
|
||||
override fun onFragmentResumed(fm: FragmentManager, f: Fragment) {
|
||||
if (f === fragment) {
|
||||
resumeCounting()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFragmentPaused(fm: FragmentManager, f: Fragment) {
|
||||
if (f === fragment) {
|
||||
pauseCounting()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFragmentViewDestroyed(fm: FragmentManager, f: Fragment) {
|
||||
if (f === fragment) {
|
||||
fragment.fragmentManager?.unregisterFragmentLifecycleCallbacks(this)
|
||||
}
|
||||
}
|
||||
}, false)
|
||||
}
|
||||
|
||||
fun resumeCounting() {
|
||||
isWorking = true
|
||||
TimeElapsedThreadHolder.threadService.execute {
|
||||
while (isWorking) {
|
||||
try {
|
||||
elapsedTime++
|
||||
if (timeout != 0 && timeout == elapsedTime) {
|
||||
timeoutCallback?.run {
|
||||
AppExecutor.uiExecutor.execute {
|
||||
onTimeout()
|
||||
}
|
||||
}
|
||||
}
|
||||
Thread.sleep(1000)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun resetCounting() {
|
||||
elapsedTime = 0
|
||||
}
|
||||
|
||||
fun pauseCounting() {
|
||||
isWorking = false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object TimeElapsedThreadHolder {
|
||||
val threadService: ExecutorService by lazy { Executors.newSingleThreadExecutor(GHThreadFactory("TIME_ELAPSED_THREAD")) }
|
||||
}
|
||||
|
||||
interface TimeoutCallback {
|
||||
fun onTimeout()
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
package com.gh.common
|
||||
|
||||
typealias OnFastClickListener = (isSuccess: Boolean) -> Unit
|
||||
@ -1,7 +0,0 @@
|
||||
package com.gh.common.avoidcallback
|
||||
|
||||
import android.content.Intent
|
||||
|
||||
interface Callback {
|
||||
fun onActivityResult(resultCode: Int, data: Intent?)
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package com.gh.common.chain
|
||||
|
||||
import android.content.Context
|
||||
import com.gh.download.server.BrowserInstallHelper
|
||||
import com.gh.gamecenter.core.utils.EmptyCallback
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
|
||||
class BrowserInstallHandler : ChainHandler() {
|
||||
|
||||
override fun handleRequest(context: Context, gameEntity: GameEntity) {
|
||||
BrowserInstallHelper.showBrowserInstallHintDialog(context, gameEntity.isVGame(), object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
if (hasNext()) {
|
||||
getNext()?.handleRequest(context, gameEntity)
|
||||
} else {
|
||||
processEndCallback?.invoke(null)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.gh.common.chain
|
||||
|
||||
import android.content.Context
|
||||
import com.gh.common.dialog.CertificationDialog
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
|
||||
class CertificationHandler : ChainHandler() {
|
||||
|
||||
override fun handleRequest(context: Context, gameEntity: GameEntity) {
|
||||
CertificationDialog.showCertificationDialog(context, gameEntity) {
|
||||
if (hasNext()) {
|
||||
getNext()?.handleRequest(context, gameEntity)
|
||||
} else {
|
||||
processEndCallback?.invoke(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
28
app/src/main/java/com/gh/common/chain/ChainBuilder.kt
Normal file
28
app/src/main/java/com/gh/common/chain/ChainBuilder.kt
Normal file
@ -0,0 +1,28 @@
|
||||
package com.gh.common.chain
|
||||
|
||||
class ChainBuilder {
|
||||
|
||||
private val handlers: MutableList<ChainHandler> = ArrayList()
|
||||
|
||||
private var processEndCallback: ((Any?) -> Unit)? = null
|
||||
|
||||
fun setProcessEndCallback(callback: (Any?) -> Unit): ChainBuilder {
|
||||
processEndCallback = callback
|
||||
return this
|
||||
}
|
||||
|
||||
fun addHandler(handler: ChainHandler): ChainBuilder {
|
||||
handlers.add(handler)
|
||||
return this
|
||||
}
|
||||
|
||||
fun buildHandlerChain(): ChainHandler? {
|
||||
for (i in handlers.indices) {
|
||||
handlers[i].processEndCallback = processEndCallback
|
||||
if (i + 1 < handlers.size) {
|
||||
handlers[i].setNext(handlers[i + 1])
|
||||
}
|
||||
}
|
||||
return if (handlers.isEmpty()) null else handlers[0]
|
||||
}
|
||||
}
|
||||
24
app/src/main/java/com/gh/common/chain/ChainHandler.kt
Normal file
24
app/src/main/java/com/gh/common/chain/ChainHandler.kt
Normal file
@ -0,0 +1,24 @@
|
||||
package com.gh.common.chain
|
||||
|
||||
import android.content.Context
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
|
||||
abstract class ChainHandler {
|
||||
private var next: ChainHandler? = null
|
||||
var processEndCallback: ((Any?) -> Unit)? = null
|
||||
|
||||
fun setNext(next: ChainHandler?) {
|
||||
this.next = next
|
||||
}
|
||||
|
||||
fun getNext(): ChainHandler? {
|
||||
return next
|
||||
}
|
||||
|
||||
fun hasNext(): Boolean {
|
||||
return next != null
|
||||
}
|
||||
|
||||
abstract fun handleRequest(context: Context, gameEntity: GameEntity)
|
||||
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package com.gh.common.chain
|
||||
|
||||
import android.content.Context
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.gamecenter.common.utils.safelyGetInRelease
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
|
||||
class CheckDownloadHandler : ChainHandler() {
|
||||
|
||||
override fun handleRequest(context: Context, gameEntity: GameEntity) {
|
||||
val apk = gameEntity.getApk().safelyGetInRelease(0) ?: return
|
||||
DialogUtils.checkDownload(context, apk.size) { isSubscribe: Boolean ->
|
||||
if (hasNext()) {
|
||||
getNext()?.handleRequest(context, gameEntity)
|
||||
} else {
|
||||
processEndCallback?.invoke(isSubscribe)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package com.gh.common.chain
|
||||
|
||||
import android.content.Context
|
||||
import com.gh.gamecenter.common.utils.PermissionHelper
|
||||
import com.gh.gamecenter.core.utils.EmptyCallback
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
|
||||
class CheckStoragePermissionHandler : ChainHandler() {
|
||||
|
||||
override fun handleRequest(context: Context, gameEntity: GameEntity) {
|
||||
PermissionHelper.checkStoragePermissionBeforeAction(context, object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
if (hasNext()) {
|
||||
getNext()?.handleRequest(context, gameEntity)
|
||||
} else {
|
||||
processEndCallback?.invoke(null)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package com.gh.common.chain
|
||||
|
||||
import android.content.Context
|
||||
import com.gh.common.util.DownloadDialogHelper
|
||||
import com.gh.gamecenter.common.utils.safelyGetInRelease
|
||||
import com.gh.gamecenter.core.utils.EmptyCallback
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
|
||||
class DownloadDialogHelperHandler : ChainHandler() {
|
||||
|
||||
override fun handleRequest(context: Context, gameEntity: GameEntity) {
|
||||
val apk = gameEntity.getApk().safelyGetInRelease(0) ?: return
|
||||
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
if (hasNext()) {
|
||||
getNext()?.handleRequest(context, gameEntity)
|
||||
} else {
|
||||
processEndCallback?.invoke(null)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.gh.common.chain
|
||||
|
||||
import android.content.Context
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment
|
||||
|
||||
class GamePermissionHandler : ChainHandler() {
|
||||
|
||||
override fun handleRequest(context: Context, gameEntity: GameEntity) {
|
||||
GamePermissionDialogFragment.show((context as AppCompatActivity), gameEntity, gameEntity.info) {
|
||||
if (hasNext()) {
|
||||
getNext()?.handleRequest(context, gameEntity)
|
||||
} else {
|
||||
processEndCallback?.invoke(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.gh.common.chain
|
||||
|
||||
import android.content.Context
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
|
||||
class OverseaDownloadHandler : ChainHandler() {
|
||||
|
||||
override fun handleRequest(context: Context, gameEntity: GameEntity) {
|
||||
DialogUtils.showOverseaDownloadDialog(context, gameEntity) {
|
||||
if (hasNext()) {
|
||||
getNext()?.handleRequest(context, gameEntity)
|
||||
} else {
|
||||
processEndCallback?.invoke(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
app/src/main/java/com/gh/common/chain/PackageCheckHandler.kt
Normal file
19
app/src/main/java/com/gh/common/chain/PackageCheckHandler.kt
Normal file
@ -0,0 +1,19 @@
|
||||
package com.gh.common.chain
|
||||
|
||||
import android.content.Context
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.gh.common.dialog.PackageCheckDialogFragment
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
|
||||
class PackageCheckHandler : ChainHandler() {
|
||||
|
||||
override fun handleRequest(context: Context, gameEntity: GameEntity) {
|
||||
PackageCheckDialogFragment.show((context as AppCompatActivity), gameEntity) {
|
||||
if (hasNext()) {
|
||||
getNext()?.handleRequest(context, gameEntity)
|
||||
} else {
|
||||
processEndCallback?.invoke(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package com.gh.common.chain
|
||||
|
||||
import android.content.Context
|
||||
import com.gh.common.simulator.NewSimulatorGameManager
|
||||
import com.gh.common.simulator.SimulatorGameManager
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
|
||||
class UpdateNewSimulatorHandler: ChainHandler() {
|
||||
|
||||
override fun handleRequest(context: Context, gameEntity: GameEntity) {
|
||||
if (SimulatorGameManager.isSimulatorGame(gameEntity)) {
|
||||
if (NewSimulatorGameManager.shouldShowUpdateNewSimulatorAlert(context)) {
|
||||
NewSimulatorGameManager.showUpdateNewsSimulator(context) {
|
||||
if (hasNext()) {
|
||||
getNext()?.handleRequest(context, gameEntity)
|
||||
} else {
|
||||
processEndCallback?.invoke(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (hasNext()) {
|
||||
getNext()?.handleRequest(context, gameEntity)
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (hasNext()) {
|
||||
getNext()?.handleRequest(context, gameEntity)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.gh.common.chain
|
||||
|
||||
import android.content.Context
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.vspace.VHelper
|
||||
|
||||
class ValidateVSpaceHandler : ChainHandler() {
|
||||
|
||||
override fun handleRequest(context: Context, gameEntity: GameEntity) {
|
||||
VHelper.validateVSpaceBeforeAction(context, gameEntity, true) {
|
||||
if (hasNext()) {
|
||||
getNext()?.handleRequest(context, gameEntity)
|
||||
} else {
|
||||
processEndCallback?.invoke(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.gh.common.chain
|
||||
|
||||
import android.content.Context
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
|
||||
class VersionNumberHandler : ChainHandler() {
|
||||
|
||||
override fun handleRequest(context: Context, gameEntity: GameEntity) {
|
||||
DialogUtils.showVersionNumberDialog(context, gameEntity) {
|
||||
if (hasNext()) {
|
||||
getNext()?.handleRequest(context, gameEntity)
|
||||
} else {
|
||||
processEndCallback?.invoke(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,73 +1,76 @@
|
||||
package com.gh.common.constant;
|
||||
|
||||
import android.content.Context;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.gh.common.util.GsonUtils;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.gh.gamecenter.common.utils.DarkModeUtils;
|
||||
import com.gh.gamecenter.common.utils.EnvHelper;
|
||||
import com.gh.gamecenter.common.constant.Constants;
|
||||
import com.gh.gamecenter.core.utils.GsonUtils;
|
||||
import com.gh.common.util.PackageHelper;
|
||||
import com.gh.common.util.PackageUtils;
|
||||
import com.gh.common.util.SPUtils;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.SuggestionActivity;
|
||||
import com.gh.gamecenter.core.utils.SPUtils;
|
||||
import com.gh.gamecenter.entity.GameGuidePopupEntity;
|
||||
import com.gh.gamecenter.entity.NewSettingsEntity;
|
||||
import com.gh.gamecenter.entity.NewsEntity;
|
||||
import com.gh.gamecenter.entity.SettingsEntity;
|
||||
import com.gh.gamecenter.eventbus.EBReuse;
|
||||
import com.gh.gamecenter.retrofit.BiResponse;
|
||||
import com.gh.gamecenter.retrofit.Response;
|
||||
import com.gh.gamecenter.common.eventbus.EBReuse;
|
||||
import com.gh.gamecenter.entity.SimulatorEntity;
|
||||
import com.gh.gamecenter.entity.VSetting;
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse;
|
||||
import com.gh.gamecenter.common.retrofit.Response;
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager;
|
||||
import com.gh.vspace.VHelper;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
public class Config {
|
||||
|
||||
public static final String API_HOST = BuildConfig.API_HOST;
|
||||
public static final String SENSITIVE_API_HOST = BuildConfig.SENSITIVE_API_HOST;
|
||||
|
||||
/**
|
||||
* 需要配置的请使用{@link PreferenceManager#getDefaultSharedPreferences(Context)}
|
||||
*/
|
||||
// 这个 API_HOST 在测试包里会随着选择的环境切换,正式包里会一直保持正式 host
|
||||
public static final String API_HOST = EnvHelper.getHost();
|
||||
public static final String NEW_API_HOST = EnvHelper.getNewHost();
|
||||
public static final String VAPI_HOST = EnvHelper.getVHost();
|
||||
|
||||
// Third-Party confs
|
||||
public static final String WECHAT_APPID = BuildConfig.WECHAT_APPID;
|
||||
public static final String WECHAT_SECRET = BuildConfig.WECHAT_SECRET;
|
||||
public static final String TENCENT_APPID = BuildConfig.TENCENT_APPID;
|
||||
public static final String WEIBO_APPKEY = BuildConfig.WEIBO_APPKEY;
|
||||
public static final String MIPUSH_APPID = BuildConfig.MIPUSH_APPID;
|
||||
public static final String MIPUSH_APPKEY = BuildConfig.MIPUSH_APPKEY;
|
||||
public static final String MTA_APPKEY = BuildConfig.MTA_APPKEY;
|
||||
public static final String TALKINGDATA_APPID = BuildConfig.TD_APPID;// TalkingData
|
||||
public static final String UMENG_APPKEY = BuildConfig.UMENG_APPKEY;
|
||||
public static final String UMENG_MESSAGE_SECRET = BuildConfig.UMENG_MESSAGE_SECRET;
|
||||
public static final String BUGLY_APPID = BuildConfig.BUGLY_APPID;
|
||||
public static final String LETO_APPID = BuildConfig.LETO_APPID;
|
||||
public static final String TTAD_APPID = BuildConfig.TTAD_APPID;
|
||||
public static final String DOUYIN_CLIENTKEY = BuildConfig.DOUYIN_CLIENTKEY;
|
||||
public static final String DOUYIN_CLIENTSECRET = BuildConfig.DOUYIN_CLIENTSECRET;
|
||||
public static final String QUICK_LOGIN_APPID = BuildConfig.QUICK_LOGIN_APPID;
|
||||
public static final String QUICK_LOGIN_APPKEY = BuildConfig.QUICK_LOGIN_APPKEY;
|
||||
// http://www.ghzs666.com/article/${articleId}.html
|
||||
public static final String URL_ARTICLE = "http://www.ghzs666.com/article/"; // ghzs/ghzs666 统一
|
||||
public static final String PATCHES = "patches";
|
||||
|
||||
public static final String DEFAULT_CHANNEL = "GH_TEST2";
|
||||
|
||||
private static String SETTINGS_KEY = "settingsKey";
|
||||
private static final String SETTINGS_KEY = "settingsKey";
|
||||
|
||||
private static SettingsEntity mSettingsEntity;
|
||||
private static NewSettingsEntity mNewSettingsEntity;
|
||||
|
||||
private static NewSettingsEntity.NightMode mNightModeSetting;
|
||||
private static SimulatorEntity mNewSimulatorEntity;
|
||||
private static VSetting mVSetting;
|
||||
private static GameGuidePopupEntity mGameGuidePopupEntity;
|
||||
private static SharedPreferences mDefaultSharedPreferences;
|
||||
|
||||
public static final String FIX_DOWNLOAD_KEY = "isFixDownload";
|
||||
public static final String FIX_PLUGIN_KEY = "isFixPlugin";
|
||||
public static final String FIX_ARTICLE_KEY = "isFixArticle";
|
||||
@ -76,6 +79,8 @@ public class Config {
|
||||
public static final int VIDEO_PAGE_SIZE = 21; // 视频列表大多都是一行3个
|
||||
|
||||
public static boolean isShow() {
|
||||
if (SPUtils.getBoolean(Constants.SP_TEENAGER_MODE)) return false;
|
||||
|
||||
if (getPreferences().getBoolean(FIX_DOWNLOAD_KEY, false)) return true;
|
||||
|
||||
if (!isExistDownloadFilter()) return false;
|
||||
@ -90,13 +95,6 @@ public class Config {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String getExceptionMsg() {
|
||||
return getPreferences().getString("errMsg", null);
|
||||
}
|
||||
|
||||
public static void setExceptionMsg(String errMsg) {
|
||||
SPUtils.setString(getPreferences(), "errMsg", errMsg); //先用apply(),保存不了再用commit() 9.0机型保存不了信息
|
||||
}
|
||||
|
||||
public static boolean isShowDownload(String gameId) {
|
||||
|
||||
@ -122,6 +120,17 @@ public class Config {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否启用畅玩游戏
|
||||
*/
|
||||
public static boolean isVGameEnabled() {
|
||||
if (getSettings() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !"off".equals(getSettings().getGameSmooth());
|
||||
}
|
||||
|
||||
|
||||
public static boolean isShowPlugin(String gameId) {
|
||||
SharedPreferences preferences = getPreferences();
|
||||
@ -187,11 +196,15 @@ public class Config {
|
||||
getPreferences().edit().putString(SETTINGS_KEY, GsonUtils.toJson(settingsEntity)).apply();
|
||||
mSettingsEntity = settingsEntity;
|
||||
|
||||
// 更新 FIX_ARTICLE_KEY 状态
|
||||
// 更新设置状态
|
||||
mSettingsEntity.showArticleEntrance();
|
||||
mSettingsEntity.showCommunityEntrance();
|
||||
|
||||
// 加载完设置后刷新下
|
||||
PackageHelper.initList();
|
||||
|
||||
// 初始化畅玩相关的东西
|
||||
VHelper.init(HaloApp.getInstance());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@ -209,6 +222,29 @@ public class Config {
|
||||
return mSettingsEntity;
|
||||
}
|
||||
|
||||
//新模拟器
|
||||
@Nullable
|
||||
public static SimulatorEntity getNewSimulatorEntitySetting() {
|
||||
if (mNewSimulatorEntity != null) {
|
||||
return mNewSimulatorEntity;
|
||||
} else if (mNewSettingsEntity != null && mNewSettingsEntity.getSimulator() != null) {
|
||||
return mNewSettingsEntity.getSimulator();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static NewSettingsEntity.NightMode getNightModeSetting() {
|
||||
if (mNightModeSetting != null) {
|
||||
return mNightModeSetting;
|
||||
} else if (mNewSettingsEntity != null && mNewSettingsEntity.getNightMode() != null) {
|
||||
return mNewSettingsEntity.getNightMode();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static NewSettingsEntity getNewSettingsEntity() {
|
||||
if (mNewSettingsEntity == null) {
|
||||
@ -224,6 +260,26 @@ public class Config {
|
||||
return mNewSettingsEntity;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static VSetting getVSettingEntity() {
|
||||
if (mVSetting == null) {
|
||||
try {
|
||||
String json = SPUtils.getString(Constants.SP_V_SETTINGS);
|
||||
if (!TextUtils.isEmpty(json)) {
|
||||
mVSetting = GsonUtils.fromJson(json, VSetting.class);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return mVSetting;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static GameGuidePopupEntity getGameGuidePopupEntity() {
|
||||
return mGameGuidePopupEntity;
|
||||
}
|
||||
|
||||
private static boolean isExistDownloadFilter() {
|
||||
if (getSettings() == null || getSettings().getDownload() == null || getSettings().getDownload().size() == 0) {
|
||||
return false;
|
||||
@ -246,7 +302,11 @@ public class Config {
|
||||
}
|
||||
|
||||
public static SharedPreferences getPreferences() {
|
||||
return PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().getApplication());
|
||||
if (mDefaultSharedPreferences == null) {
|
||||
mDefaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().getApplication());
|
||||
}
|
||||
|
||||
return mDefaultSharedPreferences;
|
||||
}
|
||||
|
||||
public static boolean isExistHideFunction() {
|
||||
@ -258,13 +318,6 @@ public class Config {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isGameDomeSwitchOpen() {
|
||||
return getSettings() != null && getSettings().getGameDomeSwitch().equals("on");
|
||||
}
|
||||
public static boolean isPermissionPopupSwitchOpen() {
|
||||
return getSettings() != null && getSettings().getPermissionPopupSwitch().equals("on");
|
||||
}
|
||||
|
||||
public static void fixHideFunction() {
|
||||
SharedPreferences preferences = PreferenceManager.
|
||||
getDefaultSharedPreferences(HaloApp.getInstance().getApplication());
|
||||
@ -276,10 +329,11 @@ public class Config {
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
public static void getGhzsSettings() {
|
||||
String channel = HaloApp.getInstance().getChannel();
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().getApplication())
|
||||
.getSensitiveApi().getSettings(PackageUtils.getVersionName(), channel)
|
||||
RetrofitManager.getInstance()
|
||||
.getApi().getSettings(PackageUtils.getGhVersionName(), channel)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Response<SettingsEntity>() {
|
||||
@ -296,20 +350,94 @@ public class Config {
|
||||
if (!getPreferences().getBoolean(Config.FIX_DOWNLOAD_KEY, false) && Config.isShow()) {
|
||||
getPreferences().edit().putBoolean(Config.FIX_DOWNLOAD_KEY, true).apply();
|
||||
}
|
||||
EventBus.getDefault().post(new EBReuse("Refresh"));
|
||||
if (!SPUtils.getBoolean(Constants.SP_TEENAGER_MODE)) {
|
||||
EventBus.getDefault().post(new EBReuse("Refresh"));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().getApplication())
|
||||
.getApi().getNewSettings(Build.MANUFACTURER, Build.MODEL, channel)
|
||||
RetrofitManager.getInstance()
|
||||
.getApi().getNewSettings(Build.MANUFACTURER, Build.MODEL, channel, Build.VERSION.SDK_INT, BuildConfig.VERSION_NAME)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new BiResponse<NewSettingsEntity>() {
|
||||
@Override
|
||||
public void onSuccess(NewSettingsEntity data) {
|
||||
mNewSettingsEntity = data;
|
||||
if (mNightModeSetting != null) {
|
||||
mNewSettingsEntity.setNightMode(mNightModeSetting);
|
||||
}
|
||||
SPUtils.setString(Constants.SP_NEW_SETTINGS, GsonUtils.toJson(data));
|
||||
}
|
||||
});
|
||||
|
||||
if (mVSetting == null) {
|
||||
RetrofitManager.getInstance()
|
||||
.getVApi().getSettings(BuildConfig.VERSION_NAME)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(new BiResponse<VSetting>() {
|
||||
@Override
|
||||
public void onSuccess(VSetting data) {
|
||||
mVSetting = data;
|
||||
SPUtils.setString(Constants.SP_V_SETTINGS, GsonUtils.toJson(data));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (mNightModeSetting == null && mNewSimulatorEntity == null) {
|
||||
RetrofitManager.getInstance()
|
||||
.getNewApi().getNewSettings(PackageUtils.getGhVersionName(), channel)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new BiResponse<NewSettingsEntity>() {
|
||||
@Override
|
||||
public void onSuccess(NewSettingsEntity data) {
|
||||
mNightModeSetting = data.getNightMode();
|
||||
mNewSimulatorEntity = data.getSimulator();
|
||||
if (HaloApp.getInstance().isNewForThisVersion && mNightModeSetting != null && mNightModeSetting.getInstall()) {
|
||||
DarkModeUtils.INSTANCE.updateFollowSystemDarkModeToSp(true);
|
||||
DarkModeUtils.INSTANCE.updateAppDarkModeStatusToSp(true);
|
||||
DarkModeUtils.INSTANCE.initDarkMode();
|
||||
}
|
||||
|
||||
if (mNewSettingsEntity != null) {
|
||||
mNewSettingsEntity.setSimulator(mNewSimulatorEntity);
|
||||
mNewSettingsEntity.setNightMode(mNightModeSetting);
|
||||
SPUtils.setString(Constants.SP_NEW_SETTINGS, GsonUtils.toJson(data));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RetrofitManager.getInstance()
|
||||
.getApi().getGameGuidePopup(Build.MANUFACTURER, Build.VERSION.RELEASE, Build.MODEL, channel, BuildConfig.VERSION_NAME)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new BiResponse<GameGuidePopupEntity>() {
|
||||
@Override
|
||||
public void onSuccess(GameGuidePopupEntity data) {
|
||||
mGameGuidePopupEntity = data;
|
||||
}
|
||||
});
|
||||
|
||||
String manufacturer = Build.MANUFACTURER.toUpperCase(Locale.CHINA);
|
||||
if (manufacturer.equals("OPPO") || manufacturer.equals("VIVO")) {
|
||||
RetrofitManager.getInstance().getNewApi().getBrowserHintUrl(manufacturer)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new BiResponse<ResponseBody>() {
|
||||
@Override
|
||||
public void onSuccess(ResponseBody data) {
|
||||
try {
|
||||
JSONObject jsonObject = new JSONObject(data.string());
|
||||
if (!TextUtils.isEmpty(jsonObject.getJSONObject("data").getString("link"))) {
|
||||
SPUtils.setString(Constants.SP_BROWSER_HINT_URL, jsonObject.getJSONObject("data").getString("link"));
|
||||
}
|
||||
} catch (JSONException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,332 +0,0 @@
|
||||
package com.gh.common.constant;
|
||||
|
||||
import com.gh.common.util.PackageUtils;
|
||||
import com.halo.assistant.HaloApp;
|
||||
|
||||
public class Constants {
|
||||
|
||||
public static final int SEND_NEWS_FEEDBACK = 0x126;
|
||||
public static final int SEND_COMMENT_FEEDBACK = 0x127;
|
||||
|
||||
public final static int LIST_FOOTER_ITEM = 1;
|
||||
public final static int LIST_HEAD_ITEM = 1;
|
||||
|
||||
public final static int NOT_NETWORK_CODE = 504; // 没有网络的状态码(应该是这个吧!)
|
||||
|
||||
public static final String USER_TOKEN_KEY = "userTokenKey";
|
||||
public static final String USER_INFO_KEY = "userInfoKey";
|
||||
|
||||
public static final String WELCOME_DIALOG_ID = "welcome_dialog_id";
|
||||
public static final String WELCOME_DIALOG_LINK_TITLE = "welcome_dialog_link_title";
|
||||
|
||||
public static final String DEVICE_KEY = "deviceKey";
|
||||
|
||||
public static final String HAS_REQUESTED_NOTIFICATION_PERMISSIONS = "has_requested_notification_permissions";
|
||||
|
||||
public static final String SHOULD_SHOW_VIDEO_MOBILE_WARNING = "should_show_video_mobile_warning";
|
||||
|
||||
public static final String GAME_DETAIL_COME_IN = "game_detail_come_in"; // 从游戏详情进入
|
||||
|
||||
public static final String SPLASH_AD = "splash_ad"; // 启动广告
|
||||
|
||||
public static final String XPOSED_INSTALLER_PACKAGE_NAME = "de.robv.android.xposed.installer";
|
||||
|
||||
public static final String EB_QUIT_LOGIN = "quit_login";
|
||||
|
||||
public static final String EB_SHOW_AD = "show_ad";
|
||||
|
||||
public static final String EB_GAME_DETAIL = "eb_game_detail";
|
||||
|
||||
// 用于避免历史下载影响到部分依赖名字作为数据更新条件的修饰符
|
||||
public static final String GAME_NAME_DECORATOR = " ";
|
||||
|
||||
// 游戏详情进入时的自定义栏目标签是否已经默认展开过一次的标记
|
||||
public static final String SP_HAS_EXPANDED_GAME_DETAIL_TAGS = "has_expanded_game_detail_tags";
|
||||
// 游戏详情进入时的自定义栏目标签是否已经显示过一次展开更多的浮窗提示
|
||||
public static final String SP_HAS_SHOWN_EXPANDED_GAME_DETAIL_TAGS_HINT = "has_shown_expanded_game_detail_tags_hint";
|
||||
|
||||
// 最近显示的弹窗信息
|
||||
public static final String SP_LAST_OPENING_ID = "last_opening_dialog_id";
|
||||
public static final String SP_LAST_OPENING_TIME = "last_opening_dialog_time";
|
||||
|
||||
// 游戏图标和图标角标
|
||||
public static final String RAW_GAME_ICON = "raw_game_icon";
|
||||
public static final String GAME_ICON_SUBSCRIPT = "game_icon_subscript";
|
||||
|
||||
public static final String IS_PLATFORM_RECOMMEND = "isPlatformRecommend";
|
||||
|
||||
// 下载 id,一般来说跟下载文件名一样
|
||||
public static final String DOWNLOAD_ID = "download_id";
|
||||
|
||||
public static final String GHZS_GAME_ID = "5ae4462c2924bc7936438d07";
|
||||
|
||||
public static final String EXTRA_DOWNLOAD_TYPE = "extra_download_type";
|
||||
public static final String SILENT_UPDATE = "静默更新";
|
||||
public static final String SIMULATOR_DOWNLOAD = "下载模拟器";
|
||||
public static final String SIMULATOR_GAME = "simulator_game";
|
||||
public static final String SIMULATOR = "simulator";
|
||||
public static final String GAME_NAME = "game_name";
|
||||
public static final String SIMULATOR_DOWNLOAD_START_TIME = "simulator_download_start_time";
|
||||
public static final String LAST_GHZS_UPDATE_FILE_SIZE = "last_ghzs_update_file_size";
|
||||
|
||||
// 新用户首次启动光环的时间
|
||||
public static final String SP_INITIAL_USAGE_TIME = "initial_usage_time";
|
||||
|
||||
public static final String SP_IMEI = "imei";
|
||||
public static final String SP_ANDROID_ID = "android_id";
|
||||
|
||||
public static final String LAST_INSTALL_GAME = "last_install_game";
|
||||
|
||||
//引导设置 “通知管理” 引导弹窗
|
||||
public static final String SP_SHOWED_NOTIFICATION_LOGIN = "show_notification_login_hint";
|
||||
public static final String SP_SHOWED_NOTIFICATION_QUESTION = "show_notification_question_hint";
|
||||
public static final String SP_SHOWED_NOTIFICATION_ANSWER = "show_notification_answer_hint";
|
||||
public static final String SP_SHOWED_NOTIFICATION_ARTICLE = "show_notification_article_hint";
|
||||
public static final String SP_SHOWED_NOTIFICATION_VIDEO = "show_notification_video_hint";
|
||||
public static final String SP_SHOWED_NOTIFICATION_RATING = "show_notification_rating_hint";
|
||||
public static final String SP_SHOWED_NOTIFICATION_GIFT = "show_notification_gift_hint";
|
||||
public static final String SP_SHOWED_NOTIFICATION_RESERVE_GAME = "show_notification_reserve_game_hint";
|
||||
public static final String SP_SHOWED_NOTIFICATION_FEEDBACK = "show_notification_feedback_hint";
|
||||
// 新版本 也要触发一次“通知管理” 引导弹窗
|
||||
public static final String SP_SHOWED_NOTIFICATION_NEW_VERSION = "show_notification_new_version";
|
||||
// 今天是否已经触发了 “通知管理” 引导弹窗
|
||||
public static final String SP_IS_SHOWED_NOTIFICATION_TODAY = "show_is_notification_today";
|
||||
// v4.0.0已废弃,标记安装的游戏为已玩过弹窗,最多取消2次 (https://gitlab.ghzs.com/pm/halo-app-issues/issues/722 调整为版本相关) (不是常量了也放这里好像有点奇怪)
|
||||
public static final String SP_MARK_INSTALLED_GAME = "mark_installed_game" + PackageUtils.getVersionName();
|
||||
// 标记安装的游戏为已玩过弹窗(个人主页最多弹一次)
|
||||
public static final String SP_MARK_INSTALLED_GAME_USER_HOME = "mark_installed_game_user_home" + PackageUtils.getVersionName();
|
||||
// 标记安装的游戏为已玩过弹窗(我的游戏最多弹一次)
|
||||
public static final String SP_MARK_INSTALLED_GAME_MY_GAME = "mark_installed_game_my_game" + PackageUtils.getVersionName();
|
||||
//视频详情滑动引导
|
||||
public static final String SP_SHOW_SLIDE_GUIDE = "show_slide_guide";
|
||||
//视频详情点击引导
|
||||
public static final String SP_SHOW_CLICK_GUIDE = "show_click_guide";
|
||||
//视频详情双击点赞引导
|
||||
public static final String SP_SHOW_DOUBLE_CLICK_GUIDE = "show_double_click_guide";
|
||||
//顶部视频声音状态,重启恢复
|
||||
public static final String SP_TOP_VIDEO_VOICE = "top_video_voice";
|
||||
//我的光环提醒设置已读
|
||||
public static final String SP_ADDONS_FUNCS_HAVE_READ = "addons_funcs_have_read";
|
||||
//视频非wifi提醒只提醒一次,重启恢复
|
||||
public static final String SP_NON_WIFI_TIPS = "non_wifi_tips";
|
||||
//首页视频最新tab提示
|
||||
public static final String SP_HOME_NEW_VIDEO_TIPS = "home_new_video";
|
||||
//游戏设备弹窗提示
|
||||
public static final String SP_DEVICE_REMIND = "device_remind";
|
||||
//是否是第一次弹出游戏设备弹窗提示
|
||||
public static final String SP_FIRST_DEVICE_REMIND = "first_device_remind";
|
||||
//游戏设备弹窗不再提示
|
||||
public static final String SP_NO_REMIND_AGAIN = "no_remind_again";
|
||||
//游戏详情过滤标签数据
|
||||
public static final String SP_FILTER_TAGS = "filter_tags";
|
||||
//实名认证弹窗分类数据
|
||||
public static final String SP_AUTH_DIALOG = "auth_dialog";
|
||||
//我的光环小红点提示
|
||||
public static final String SP_GH_RED_POINT_REMIND = "gh_red_point_remind";
|
||||
//论坛首页引导
|
||||
public static final String SP_FORUM_GUIDE = "forum_guide";
|
||||
//礼仪考试开启状态
|
||||
public static final String SP_REGULATION_TEST_LAST_REMIND_TIME = "regulation_test_last_remind_time";
|
||||
public static final String SP_REGULATION_TEST_STATUS = "regulation_test_status";
|
||||
public static final String SP_REGULATION_TEST_PASS_STATUS = "regulation_test_pass_status";
|
||||
//相同设备号,每一种第三方登录方式登录后弹出绑定手机页面的次数
|
||||
public static final String SP_QQ_SHOW_BIND_PHONE_TIME = "qq_show_bind_phone_time" + HaloApp.getInstance().getGid();
|
||||
public static final String SP_WECHAT_SHOW_BIND_PHONE_TIME = "wechat_show_bind_phone_time" + HaloApp.getInstance().getGid();
|
||||
public static final String SP_WEIBO_SHOW_BIND_PHONE_TIME = "weibo_show_bind_phone_time" + HaloApp.getInstance().getGid();
|
||||
public static final String SP_DOUYIN_SHOW_BIND_PHONE_TIME = "douyin_show_bind_phone_time" + HaloApp.getInstance().getGid();
|
||||
//隐私政策是否有更新
|
||||
public static final String SP_PRIVACY_CURRENT_MD5 = "sp_privacy_current_md5";
|
||||
public static final String SP_PRIVACY_MINE_MD5 = "sp_privacy_mine_md5";
|
||||
public static final String SP_PRIVACY_SETTING_MD5 = "sp_privacy_setting_md5";
|
||||
public static final String SP_PRIVACY_MD5 = "sp_privacy_md5";
|
||||
|
||||
public static final String SP_IS_USER_ACCEPTED_PRIVACY_STATEMENT = "has_user_accepted_privacy_statement";
|
||||
public static final String SP_BRAND_NEW_USER = "brand_new_user";
|
||||
//包名检测是否点击不再提示
|
||||
public static final String SP_PACKAGE_CHECK = "package_check";
|
||||
//游戏详情预约引导提示
|
||||
public static final String SP_GAME_DETAIL_RESERVE_GUIDE = "game_detail_reserve_guide";
|
||||
|
||||
public static final String SP_XAPK_UNZIP_ACTIVITY = "xapk_unzip_activity";
|
||||
public static final String SP_XAPK_URL = "xapk_url";
|
||||
|
||||
//游戏详情推荐弹窗
|
||||
public static final String SP_RECOMMEND_POPUP = "recommend_popup";
|
||||
|
||||
|
||||
// 使用浏览器安装开关
|
||||
public static final String SP_USE_BROWSER_TO_INSTALL = "use_browser_to_install";
|
||||
// 游戏详情页底部使用浏览器安装提示
|
||||
public static final String SP_SHOULD_SHOW_GAMEDETAIL_USE_BROWSER_TO_INSTALL_HINT = "should_show_gamedetail_use_browser_to_install_hint";
|
||||
// 第一次普通安装推荐使用浏览器安装提示
|
||||
public static final String SP_SHOULD_SHOW_USE_BROWSER_TO_INSTALL_HINT = "should_show_use_browser_to_install_hint";
|
||||
|
||||
//模拟器管理引导
|
||||
public static final String SP_SIMULATOR_GUIDE = "simulator_guide";
|
||||
//模拟器游戏引导
|
||||
public static final String SP_SIMULATOR_GAME_GUIDE = "simulator_game_guide";
|
||||
|
||||
|
||||
//首页视频播放进度
|
||||
public static final String SP_HOME_VIDEO_PLAY_RECORD = "home_video_play_record";
|
||||
|
||||
// 用户是否曾经永久拒绝过存储权限
|
||||
public static final String SP_USER_HAS_PERMANENTLY_DENIED_STORAGE_PERMISSION = "user_has_permanently_denied_storage_permission";
|
||||
|
||||
// 是否已经填写邀请码
|
||||
public static final String SP_HAS_COMPLETE_INVITE_CODE = "has_complete_invite_code";
|
||||
|
||||
// 补充配置项
|
||||
public static final String SP_NEW_SETTINGS = "new_settings";
|
||||
|
||||
// 头像挂件ID
|
||||
public static final String SP_CHOOSE_AVATAR_ID = "choose_avatar_id";
|
||||
|
||||
// 是否显示返回任务悬浮图标
|
||||
public static final String SP_SHOW_TASK_FLOAT = "show_task_float";
|
||||
// 悬浮图标Y值
|
||||
public static final String SP_TASK_FLOAT_LAST_Y = "task_float_last_y";
|
||||
|
||||
// 是否第一次进入新分类2.0
|
||||
public static final String SP_FIRST_ENTER_CATEGORY_V2 = "first_enter_category_v2";
|
||||
|
||||
// 是否成功取过号
|
||||
public static final String SP_HAS_GET_PHONE_INFO = "has_get_phone_info";
|
||||
|
||||
//手机号码匹配规则
|
||||
public static final String REGEX_MOBILE = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";
|
||||
public static final String REGEX_ACCOUNT = "^[a-zA-Z_]\\w{5,17}$";
|
||||
public static final String REGEX_PASSWORD = "^[a-zA-Z]\\w{5,31}$";
|
||||
|
||||
//输入规则
|
||||
public static final String INPUT_RULE = "0123456789abcdefghijklnmopqrstuvwxyzABCDEFGHIJKLNMOPQRSTUVWXYZ_";
|
||||
|
||||
// 微信绑定地址
|
||||
public static final String WECHAT_BIND_ADDRESS_DEV = "https://resource.ghzs.com/page/wechat_dev/index.html#/";
|
||||
public static final String WECHAT_BIND_ADDRESS = "https://resource.ghzs.com/page/wechat_pro/index.html#/";
|
||||
|
||||
// 礼仪考试地址
|
||||
public static final String REGULATION_TEST_ADDRESS_DEV = "https://static-web.ghzs.com/etiquette-dev/index.html#/";
|
||||
public static final String REGULATION_TEST_ADDRESS = "https://static-web.ghzs.com/etiquette/index.html#/";
|
||||
|
||||
// 徽章中心
|
||||
public static final String BADGE_ADDRESS_DEV = "https://static-web.ghzs.com/badge-dev/index.html#/";
|
||||
public static final String BADGE_ADDRESS = "https://static-web.ghzs.com/badge/index.html#/";
|
||||
|
||||
// 徽章详情
|
||||
public static final String BADGE_DETAIL_ADDRESS_DEV = "https://static-web.ghzs.com/badge-dev/index.html#/badgedetail";
|
||||
public static final String BADGE_DETAIL_ADDRESS = "https://static-web.ghzs.com/badge/index.html#/badgedetail";
|
||||
|
||||
// 分享个人主页地址
|
||||
public static final String SHARE_USER_HOME_ADDRESS_DEV = "https://static-web.ghzs.com/ghzs-userhome-dev/index.html#/";
|
||||
public static final String SHARE_USER_HOME_ADDRESS = "https://static-web.ghzs.com/ghzs-userhome/index.html#/";
|
||||
|
||||
// 腾讯企点地址
|
||||
public static final String TENCENT_QIDIAN_ADDRESS = "https://admin.qidian.qq.com/template/blue/mp/menu/qr-code-jump.html?linkType=0&env=ol&kfuin=2355094296&fid=457&key=c76dcb2e3d582b6ffbfb5bb22cde85ff&cate=1&source=&isLBS=&isCustomEntry=&type=16&ftype=1&_type=wpa&qidian=true";
|
||||
|
||||
//版规声明
|
||||
public static final String FORUM_REGULATIONS_NEWS_ID = "5f4db9cc34d44d01b92fd670";
|
||||
|
||||
// 权限使用场景地址
|
||||
public static final String PERMISSION_SCENARIO_ADDRESS = "https://resource.ghzs.com/page/permissions/android.html";
|
||||
|
||||
//帮助内容详情
|
||||
public static final String HELP_ADDRESS_DEV = "https://static-web.ghzs.com/ghzs_help_dev/help.html?content=";
|
||||
public static final String HELP_ADDRESS = "https://static-web.ghzs.com/ghzs_help/help.html?content=";
|
||||
|
||||
// 注销页面
|
||||
public static final String LOGOUT_ADDRESS_DEV = "https://static-web.ghzs.com/ghzs_help_dev/help.html?content=5f6b1f02786564003944a693&from=ghzs";
|
||||
public static final String LOGOUT_ADDRESS = "https://static-web.ghzs.com/ghzs_help/help.html?content=5f534111b1f72909fc225672&from=ghzs";
|
||||
|
||||
// 商品详情
|
||||
public static final String COMMODITY_DETAIL_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/product?from=ghzs";
|
||||
public static final String COMMODITY_DETAIL_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/product?from=ghzs";
|
||||
|
||||
// 光能记录
|
||||
public static final String ENERGY_RECORD_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/record?from=ghzs";
|
||||
public static final String ENERGY_RECORD_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/record?from=ghzs";
|
||||
|
||||
// 订单中心
|
||||
public static final String ORDER_CENTER_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/orders?from=ghzs";
|
||||
public static final String ORDER_CENTER_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/orders?from=ghzs";
|
||||
|
||||
// 订单详情
|
||||
public static final String ORDER_DETAIL_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/order-detail?from=ghzs";
|
||||
public static final String ORDER_DETAIL_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/order-detail?from=ghzs";
|
||||
|
||||
// 邀请好友
|
||||
public static final String INVITE_FRIENDS_ADDRESS_DEV = "https://static-web.ghzs.com/ghzs_activity_dev/inviteFriends.html#/invite";
|
||||
public static final String INVITE_FRIENDS_ADDRESS = "https://static-web.ghzs.com/ghzs_activity_prod/inviteFriends.html#/invite";
|
||||
|
||||
// 等级页面
|
||||
public static final String LEVEL_ADDRESS_DEV = "https://static-web.ghzs.com/ghzs-userhome-dev/index.html#/level";
|
||||
public static final String LEVEL_ADDRESS = "https://static-web.ghzs.com/ghzs-userhome/index.html#/level";
|
||||
|
||||
// 兑换规则
|
||||
public static final String EXCHANGE_RULE_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/exchange-rule?from=ghzs";
|
||||
public static final String EXCHANGE_RULE_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/exchange-rule?from=ghzs";
|
||||
|
||||
// 光能规则
|
||||
public static final String ENERGY_RULE_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/energy-rule?from=ghzs";
|
||||
public static final String ENERGY_RULE_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/energy-rule?from=ghzs";
|
||||
|
||||
// 兑换商品
|
||||
public static final String EXCHANGE_COMMODITY_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/exchange-log?from=ghzs";
|
||||
public static final String EXCHANGE_COMMODITY_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/exchange-log?from=ghzs";
|
||||
|
||||
// 抽奖乐园
|
||||
public static final String LOTTERY_PARADISE_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/lottery-list?from=ghzs";
|
||||
public static final String LOTTERY_PARADISE_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/lottery-list?from=ghzs";
|
||||
|
||||
// 我的奖品
|
||||
public static final String MY_PRIZE_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/mywin?from=ghzs";
|
||||
public static final String MY_PRIZE_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/mywin?from=ghzs";
|
||||
|
||||
// 中奖订单详情
|
||||
public static final String WIN_ORDER_DETAIL_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/win-order-detail?from=ghzs";
|
||||
public static final String WIN_ORDER_DETAIL_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/win-order-detail?from=ghzs";
|
||||
|
||||
// 地址信息
|
||||
public static final String ADDRESS_INFO_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/address-list?from=ghzs";
|
||||
public static final String ADDRESS_INFO_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/address-list?from=ghzs";
|
||||
|
||||
// 领奖信息
|
||||
public static final String PRIZE_INFO_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/user-info?from=ghzs";
|
||||
public static final String PRIZE_INFO_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/user-info?from=ghzs";
|
||||
|
||||
// 提现信息
|
||||
public static final String WITHDRAW_INFO_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/cash?from=ghzs";
|
||||
public static final String WITHDRAW_INFO_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/cash?from=ghzs";
|
||||
|
||||
//最少需要多少数据才能上传
|
||||
public static final int DATA_AMOUNT = 20;
|
||||
|
||||
//游戏 cd间隔
|
||||
public static final int GAME_CD = 5 * 60 * 1000;
|
||||
//新闻 cd间隔
|
||||
public static final int NEWS_CD = 10 * 60 * 1000;
|
||||
//platform cd间隔
|
||||
public static final int PLATFORM_CD = 10 * 60 * 1000;
|
||||
//update cd间隔
|
||||
public static final int UPDATE_CD = 5 * 60 * 1000;
|
||||
//搜索 cd间隔
|
||||
public static final int SEARCH_CD = 5 * 60 * 1000;
|
||||
//评论 cd间隔
|
||||
public static final int COMMENT_CD = 60 * 1000;
|
||||
//我的光环功能分组 cd间隔
|
||||
public static final int ADDONS_CD = 10 * 60 * 1000;
|
||||
//已收录包名更新 cd间隔
|
||||
public static final int PACKAGES_CD = 60 * 1000;
|
||||
|
||||
public static final String[] REPORT_LIST = new String[]{"垃圾广告营销", "恶意攻击谩骂", "淫秽色情信息", "违法有害信息", "其它"};
|
||||
|
||||
public static final String ENTRANCE_UNKNOWN = "(unknown)";
|
||||
|
||||
public static final String DEFAULT_TEXT_WRAPPER = "###";
|
||||
|
||||
// 触发了安装事件的标记
|
||||
public static final String MARK_ALREADY_TRIGGERED_INSTALLATION = "triggered_installation";
|
||||
|
||||
// 标记下载重试标记(值为任务已下载大小,为空表示需要重试)
|
||||
public static final String MARK_RETRY_DOWNLOAD = "retry_download";
|
||||
}
|
||||
@ -0,0 +1,187 @@
|
||||
package com.gh.common.databind
|
||||
|
||||
import android.os.Build
|
||||
import android.text.Editable
|
||||
import android.text.Html
|
||||
import android.text.TextWatcher
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.EditText
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.PopupWindow
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.databinding.BindingAdapter
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.gh.gamecenter.common.callback.OnViewClickListener
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.toDrawable
|
||||
import com.gh.gamecenter.common.view.BugFixedPopupWindow
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.databinding.KaifuAddItemBinding
|
||||
import com.gh.gamecenter.databinding.LayoutAddKaifuPopupBinding
|
||||
import com.gh.gamecenter.databinding.LayoutPopupContainerBinding
|
||||
import com.gh.gamecenter.entity.ServerCalendarEntity
|
||||
import com.gh.gamecenter.servers.add.AddKaiFuPopupAdapter
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
object AddKaiFuBindingAdapter {
|
||||
private var popupWindow: BugFixedPopupWindow? = null
|
||||
|
||||
@JvmStatic
|
||||
@BindingAdapter("addKaiFuView", "clickListener")
|
||||
fun addKaiFuView(
|
||||
view: LinearLayout,
|
||||
list: List<ServerCalendarEntity?>?,
|
||||
listener: OnViewClickListener<*>?
|
||||
) {
|
||||
if (list == null) return
|
||||
view.removeAllViews()
|
||||
view.addView(LayoutInflater.from(view.context).inflate(R.layout.kaifu_new_add_item_title, null))
|
||||
for (i in list.indices) {
|
||||
val inflate = LayoutInflater.from(view.context).inflate(R.layout.kaifu_add_item, null)
|
||||
val binding = KaifuAddItemBinding.bind(inflate)
|
||||
binding.clickListener = listener
|
||||
binding.entity = list[i]
|
||||
binding.position = i
|
||||
binding.isCloseBottom = list.size - 1 == i
|
||||
view.addView(inflate)
|
||||
binding.kaifuAddFirstName.setOnFocusChangeListener { _, hasFocus ->
|
||||
if (hasFocus) {
|
||||
binding.kaifuAddFirstName.hint = ""
|
||||
if (binding.kaifuAddFirstName.text.isNullOrEmpty()) {
|
||||
showPopupOption(binding.kaifuAddFirstName) {
|
||||
binding.kaifuAddFirstName.setText(it)
|
||||
binding.kaifuAddFirstName.setSelection(it.length)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
binding.kaifuAddFirstName.hint = "点击填写"
|
||||
}
|
||||
}
|
||||
binding.kaifuAddServerName.setOnFocusChangeListener { _, hasFocus ->
|
||||
if (hasFocus) {
|
||||
binding.kaifuAddServerName.hint = ""
|
||||
} else {
|
||||
binding.kaifuAddServerName.hint = "点击填写"
|
||||
}
|
||||
}
|
||||
binding.kaifuAddFirstName.addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(
|
||||
s: CharSequence?,
|
||||
start: Int,
|
||||
count: Int,
|
||||
after: Int
|
||||
) {
|
||||
}
|
||||
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
|
||||
if (!s.isNullOrEmpty()) {
|
||||
popupWindow?.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
}
|
||||
|
||||
})
|
||||
if (i == list.size - 1) {
|
||||
binding.kaifuAddTime.background = R.drawable.bg_add_kaifu_bottom_left.toDrawable(view.context)
|
||||
binding.kaifuAddServerName.background = R.drawable.bg_add_kaifu_bottom_right.toDrawable(view.context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@BindingAdapter("addKaiFuTime", "addKaiFuPosition")
|
||||
fun addKaiFuTime(view: EditText, time: Long, position: Int) {
|
||||
if (time == 0L) {
|
||||
view.hint = "点击选择"
|
||||
view.setText("")
|
||||
} else {
|
||||
val pattern = "yyy-MM-dd HH:mm"
|
||||
val format = SimpleDateFormat(pattern, Locale.CHINA)
|
||||
view.setText(format.format(time * 1000))
|
||||
if (position == 0) {
|
||||
view.append(
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) Html.fromHtml(
|
||||
String.format(
|
||||
"<font color='#2496FF'>%1\$s</font>",
|
||||
" +"
|
||||
), Html.FROM_HTML_MODE_LEGACY
|
||||
) else Html.fromHtml(String.format("<font color='#2496FF'>%1\$s</font>", " +"))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@BindingAdapter("kaiFuTextColor", "kaiFuTextPosition")
|
||||
fun kaiFuTextColor(view: EditText, dataMark: Int, position: Int) {
|
||||
if (dataMark == 1 && view.id == R.id.kaifu_add_time || dataMark == 2 && view.id == R.id.kaifu_add_first_name || dataMark == 3 && view.id == R.id.kaifu_add_server_name || dataMark == 4) {
|
||||
view.setTextColor(ContextCompat.getColor(view.context, R.color.theme_red))
|
||||
view.setHintTextColor(ContextCompat.getColor(view.context, R.color.theme_red))
|
||||
} else if (position == 0) {
|
||||
view.setTextColor(ContextCompat.getColor(view.context, R.color.hint))
|
||||
view.setHintTextColor(ContextCompat.getColor(view.context, R.color.hint))
|
||||
} else {
|
||||
view.setTextColor(ContextCompat.getColor(view.context, R.color.text_title))
|
||||
view.setHintTextColor(ContextCompat.getColor(view.context, R.color.hint))
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
private fun showPopupOption(view: View, callback: (text: String) -> Unit) {
|
||||
val inflater = LayoutInflater.from(view.context)
|
||||
val mainBinding = LayoutPopupContainerBinding.inflate(inflater)
|
||||
popupWindow = BugFixedPopupWindow(
|
||||
mainBinding.root,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
val windowPos = IntArray(2)
|
||||
val anchorLoc = IntArray(2)
|
||||
// 获取锚点View在屏幕上的左上角坐标位置
|
||||
view.getLocationOnScreen(anchorLoc)
|
||||
val anchorHeight = view.height
|
||||
// 获取屏幕的高宽
|
||||
val screenHeight = view.context.resources.displayMetrics.heightPixels
|
||||
popupWindow?.let { popupWindow ->
|
||||
// 测量contentView
|
||||
popupWindow.contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
|
||||
val windowHeight = popupWindow.contentView.measuredHeight
|
||||
|
||||
// 判断需要向上弹出还是向下弹出显示
|
||||
val isNeedShowUp = screenHeight - anchorLoc[1] - anchorHeight < windowHeight
|
||||
windowPos[1] = if (isNeedShowUp) {
|
||||
anchorLoc[1] - windowHeight
|
||||
} else anchorLoc[1] + anchorHeight
|
||||
|
||||
LayoutAddKaifuPopupBinding.inflate(inflater, mainBinding.container, false).apply {
|
||||
root.layoutParams = root.layoutParams.apply {
|
||||
width = view.width + 16F.dip2px()
|
||||
}
|
||||
popupRv.adapter = AddKaiFuPopupAdapter(
|
||||
root.context,
|
||||
arrayListOf("安卓混服", "硬核专服", "官方专服", "官方渠道服", "腾讯QQ服", "腾讯微信服")
|
||||
) {
|
||||
callback.invoke(it)
|
||||
popupWindow.dismiss()
|
||||
}
|
||||
popupRv.layoutManager = LinearLayoutManager(root.context)
|
||||
mainBinding.container.addView(root)
|
||||
}
|
||||
|
||||
popupWindow.isTouchable = true
|
||||
popupWindow.inputMethodMode = PopupWindow.INPUT_METHOD_NEEDED
|
||||
popupWindow.isOutsideTouchable = true
|
||||
popupWindow.animationStyle = R.style.popwindow_option_anim_style
|
||||
|
||||
// 设置偏移
|
||||
windowPos[1] = windowPos[1] - 12F.dip2px()
|
||||
windowPos[0] = anchorLoc[0] - 11F.dip2px()
|
||||
popupWindow.showAtLocation(view, Gravity.TOP or Gravity.START, windowPos[0], windowPos[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -10,67 +10,74 @@ import android.text.style.ForegroundColorSpan;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.databinding.BindingAdapter;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.gh.base.OnViewClickListener;
|
||||
import com.gh.common.chain.BrowserInstallHandler;
|
||||
import com.gh.common.chain.CertificationHandler;
|
||||
import com.gh.common.chain.ChainBuilder;
|
||||
import com.gh.common.chain.ChainHandler;
|
||||
import com.gh.common.chain.CheckDownloadHandler;
|
||||
import com.gh.common.chain.DownloadDialogHelperHandler;
|
||||
import com.gh.common.chain.GamePermissionHandler;
|
||||
import com.gh.common.chain.OverseaDownloadHandler;
|
||||
import com.gh.common.chain.PackageCheckHandler;
|
||||
import com.gh.common.chain.ValidateVSpaceHandler;
|
||||
import com.gh.common.chain.VersionNumberHandler;
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.common.dialog.CertificationDialog;
|
||||
import com.gh.common.dialog.PackageCheckDialogFragment;
|
||||
import com.gh.common.dialog.ReserveDialogFragment;
|
||||
import com.gh.common.exposure.ExposureEvent;
|
||||
import com.gh.common.filter.RegionSetting;
|
||||
import com.gh.common.filter.RegionSettingHelper;
|
||||
import com.gh.common.history.HistoryHelper;
|
||||
import com.gh.common.repository.ReservationRepository;
|
||||
import com.gh.common.simulator.SimulatorDownloadManager;
|
||||
import com.gh.common.simulator.SimulatorGameManager;
|
||||
import com.gh.common.util.CheckLoginUtils;
|
||||
import com.gh.common.util.DataUtils;
|
||||
import com.gh.common.util.DialogUtils;
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.common.util.DownloadDialogHelper;
|
||||
import com.gh.common.util.GameUtils;
|
||||
import com.gh.common.util.GameViewUtils;
|
||||
import com.gh.common.util.ImageUtils;
|
||||
import com.gh.common.util.LogUtils;
|
||||
import com.gh.common.util.MtaHelper;
|
||||
import com.gh.common.util.NewsUtils;
|
||||
import com.gh.common.util.NumberUtils;
|
||||
import com.gh.common.util.PackageInstaller;
|
||||
import com.gh.common.util.PackageUtils;
|
||||
import com.gh.common.util.PlatformUtils;
|
||||
import com.gh.common.util.RealNameHelper;
|
||||
import com.gh.common.util.ReservationHelper;
|
||||
import com.gh.common.view.DownloadProgressBar;
|
||||
import com.gh.common.view.DrawableView;
|
||||
import com.gh.common.view.DownloadButton;
|
||||
import com.gh.common.view.GameIconView;
|
||||
import com.gh.download.DownloadManager;
|
||||
import com.gh.download.dialog.DownloadDialog;
|
||||
import com.gh.download.server.BrowserInstallHelper;
|
||||
import com.gh.gamecenter.DownloadManagerActivity;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.WebActivity;
|
||||
import com.gh.gamecenter.baselist.LoadStatus;
|
||||
import com.gh.gamecenter.databinding.KaifuAddItemBinding;
|
||||
import com.gh.gamecenter.common.baselist.LoadStatus;
|
||||
import com.gh.gamecenter.common.callback.OnViewClickListener;
|
||||
import com.gh.gamecenter.common.utils.ExtensionsKt;
|
||||
import com.gh.gamecenter.common.utils.ImageUtils;
|
||||
import com.gh.gamecenter.common.utils.DarkModeUtils;
|
||||
import com.gh.gamecenter.common.view.DrawableView;
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils;
|
||||
import com.gh.gamecenter.core.utils.MtaHelper;
|
||||
import com.gh.gamecenter.core.utils.NumberUtils;
|
||||
import com.gh.gamecenter.databinding.KaifuDetailItemRowBinding;
|
||||
import com.gh.gamecenter.entity.ApkEntity;
|
||||
import com.gh.gamecenter.entity.GameEntity;
|
||||
import com.gh.gamecenter.entity.LinkEntity;
|
||||
import com.gh.gamecenter.common.entity.LinkEntity;
|
||||
import com.gh.gamecenter.entity.PluginLocation;
|
||||
import com.gh.gamecenter.entity.ServerCalendarEntity;
|
||||
import com.gh.gamecenter.entity.TagStyleEntity;
|
||||
import com.gh.gamecenter.entity.TestEntity;
|
||||
import com.gh.gamecenter.eventbus.EBReuse;
|
||||
import com.gh.gamecenter.common.eventbus.EBReuse;
|
||||
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment;
|
||||
import com.gh.gamecenter.manager.PackagesManager;
|
||||
import com.gh.gamecenter.qa.entity.CommunityVideoEntity;
|
||||
import com.gh.vspace.VDownloadManagerActivity;
|
||||
import com.gh.vspace.VHelper;
|
||||
import com.lightgame.download.DownloadEntity;
|
||||
import com.lightgame.download.FileUtils;
|
||||
import com.lightgame.utils.Utils;
|
||||
@ -78,10 +85,8 @@ import com.lightgame.utils.Utils;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Created by khy on 12/02/18.
|
||||
@ -89,22 +94,18 @@ import java.util.Locale;
|
||||
|
||||
public class BindingAdapters {
|
||||
|
||||
@BindingAdapter("imageIcon")
|
||||
public static void loadIcon(SimpleDraweeView view, String imageUrl) {
|
||||
ImageUtils.displayIcon(view, imageUrl);
|
||||
}
|
||||
|
||||
@BindingAdapter("imageUrl")
|
||||
public static void loadImage(SimpleDraweeView view, String imageUrl) {
|
||||
ImageUtils.display(view, imageUrl);
|
||||
}
|
||||
|
||||
@BindingAdapter("setTextSize")
|
||||
public static void setTextSize(TextView view, int number) {
|
||||
view.setTextSize(number);
|
||||
}
|
||||
|
||||
@BindingAdapter("setTypeface")
|
||||
public static void setTypeface(TextView view, String type) {
|
||||
if (type == null) return;
|
||||
|
||||
@ -124,7 +125,6 @@ public class BindingAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter({"addDetailKaiFuView", "addDetailKaiFuViewListener", "isReadyPatch"})
|
||||
public static void addDetailKaiFuView(LinearLayout view, List<ServerCalendarEntity> list
|
||||
, OnViewClickListener listener, Boolean isReadyPatch) {
|
||||
if (list == null) return;
|
||||
@ -132,13 +132,13 @@ public class BindingAdapters {
|
||||
for (int i = 0; i < list.size() + 1; i++) { // 1 is Title
|
||||
View inflate = LayoutInflater.from(view.getContext()).inflate(R.layout.kaifu_detail_item_row, null);
|
||||
KaifuDetailItemRowBinding binding = KaifuDetailItemRowBinding.bind(inflate);
|
||||
binding.setIsCloseBottom(i == list.size());
|
||||
binding.setIsReadyPatch(isReadyPatch);
|
||||
if (i == 0) {
|
||||
binding.setIsTitle(true);
|
||||
} else {
|
||||
ServerCalendarEntity serverEntity = list.get(i - 1);
|
||||
binding.setEntity(serverEntity);
|
||||
binding.getRoot().setBackgroundColor(isReadyPatch != null && isReadyPatch ? ExtensionsKt.toColor(R.color.theme) : ExtensionsKt.toColor(R.color.white));
|
||||
binding.getRoot().setPadding(DisplayUtils.dip2px(1), DisplayUtils.dip2px(1), DisplayUtils.dip2px(1), i == list.size() ? DisplayUtils.dip2px(1) : 0);
|
||||
ServerCalendarEntity serverEntity = list.get(i - 1);
|
||||
binding.timeTv.setText(i == 0 ? "时间" : serverEntity.getFormatTime("HH:mm"));
|
||||
binding.remarkTv.setText(i == 0 ? "备注" : serverEntity.getRemark());
|
||||
binding.nameTv.setText(i == 0 ? "名字" : (TextUtils.isEmpty(serverEntity.getNote()) ? "-" : serverEntity.getNote()));
|
||||
if (i != 0) {
|
||||
binding.getRoot().setOnClickListener(v -> {
|
||||
listener.onClick(v, isReadyPatch != null && isReadyPatch ? serverEntity : null);
|
||||
});
|
||||
@ -160,77 +160,10 @@ public class BindingAdapters {
|
||||
}
|
||||
|
||||
// 如果超过10000,则转换为1.0W
|
||||
@BindingAdapter("transSimpleCount")
|
||||
public static void transSimpleCount(TextView view, int count) {
|
||||
view.setText(NumberUtils.transSimpleCount(count));
|
||||
}
|
||||
|
||||
@BindingAdapter({"addKaiFuView", "clickListener"})
|
||||
public static void addKaiFuView(LinearLayout view, List<ServerCalendarEntity> list, OnViewClickListener listener) {
|
||||
if (list == null) return;
|
||||
view.removeAllViews();
|
||||
view.addView(LayoutInflater.from(view.getContext()).inflate(R.layout.kaifu_add_item_title, null));
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
View inflate = LayoutInflater.from(view.getContext()).inflate(R.layout.kaifu_add_item, null);
|
||||
KaifuAddItemBinding binding = KaifuAddItemBinding.bind(inflate);
|
||||
binding.setClickListener(listener);
|
||||
binding.setEntity(list.get(i));
|
||||
binding.setPosition(i);
|
||||
binding.setIsCloseBottom(list.size() - 1 == i);
|
||||
view.addView(inflate);
|
||||
|
||||
binding.kaifuAddName.setOnFocusChangeListener((v, hasFocus) -> {
|
||||
if (hasFocus) {
|
||||
binding.kaifuAddName.setHint("");
|
||||
} else {
|
||||
binding.kaifuAddName.setHint("点击填写");
|
||||
}
|
||||
});
|
||||
binding.kaifuAddRemark.setOnFocusChangeListener((v, hasFocus) -> {
|
||||
if (hasFocus) {
|
||||
binding.kaifuAddRemark.setHint("");
|
||||
} else {
|
||||
binding.kaifuAddRemark.setHint("点击填写");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter({"addKaiFuTime", "addKaiFuPosition"})
|
||||
public static void addKaiFuTime(EditText view, Long time, Integer position) {
|
||||
if (time == 0) {
|
||||
view.setHint("点击选择");
|
||||
view.setText("");
|
||||
} else {
|
||||
String pattern;
|
||||
if (position == 0) {
|
||||
pattern = "yyy-MM-dd HH:mm +";
|
||||
} else {
|
||||
pattern = "yyy-MM-dd HH:mm";
|
||||
}
|
||||
SimpleDateFormat format = new SimpleDateFormat(pattern, Locale.CHINA);
|
||||
view.setText(format.format(time * 1000));
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter({"kaiFuTextColor", "kaiFuTextPosition"})
|
||||
public static void kaiFuTextColor(EditText view, Integer dataMark, Integer position) {
|
||||
if (dataMark == 1 && view.getId() == R.id.kaifu_add_time
|
||||
|| dataMark == 2 && view.getId() == R.id.kaifu_add_name
|
||||
|| dataMark == 3 && view.getId() == R.id.kaifu_add_remark
|
||||
|| dataMark == 4 && (view.getId() == R.id.kaifu_add_time || view.getId() == R.id.kaifu_add_name)) {
|
||||
view.setTextColor(ContextCompat.getColor(view.getContext(), R.color.red));
|
||||
view.setHintTextColor(ContextCompat.getColor(view.getContext(), R.color.red));
|
||||
} else if (position == 0) {
|
||||
view.setTextColor(ContextCompat.getColor(view.getContext(), R.color.hint));
|
||||
view.setHintTextColor(ContextCompat.getColor(view.getContext(), R.color.hint));
|
||||
} else {
|
||||
view.setTextColor(ContextCompat.getColor(view.getContext(), R.color.title));
|
||||
view.setHintTextColor(ContextCompat.getColor(view.getContext(), R.color.hint));
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("textColorFromString")
|
||||
public static void textColorFromString(TextView tv, String hexString) {
|
||||
if (TextUtils.isEmpty(hexString)) return;
|
||||
|
||||
@ -241,7 +174,6 @@ public class BindingAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("visibleGone")
|
||||
public static void showHide(View view, Boolean show) {
|
||||
if (show != null && show) {
|
||||
view.setVisibility(View.VISIBLE);
|
||||
@ -250,7 +182,6 @@ public class BindingAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("goneIf")
|
||||
public static void goneIf(View view, Boolean gone) {
|
||||
if (gone != null && gone) {
|
||||
view.setVisibility(View.GONE);
|
||||
@ -262,7 +193,6 @@ public class BindingAdapters {
|
||||
/**
|
||||
* lazy 的 paddingTop
|
||||
*/
|
||||
@BindingAdapter("lazyPaddingLeft")
|
||||
public static void lazyPaddingLeft(View view, int paddingLeftInDp) {
|
||||
view.setPadding(DisplayUtils.dip2px(paddingLeftInDp), view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom());
|
||||
}
|
||||
@ -270,7 +200,6 @@ public class BindingAdapters {
|
||||
/**
|
||||
* lazy 的 paddingTop
|
||||
*/
|
||||
@BindingAdapter("lazyPaddingTop")
|
||||
public static void lazyPaddingTop(View view, int paddingTopInDp) {
|
||||
view.setPadding(view.getPaddingLeft(), DisplayUtils.dip2px(paddingTopInDp), view.getPaddingRight(), view.getPaddingBottom());
|
||||
}
|
||||
@ -278,12 +207,10 @@ public class BindingAdapters {
|
||||
/**
|
||||
* lazy 的 paddingBottom
|
||||
*/
|
||||
@BindingAdapter("lazyPaddingBottom")
|
||||
public static void lazyPaddingBottom(View view, int paddingBottomInDp) {
|
||||
view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(), DisplayUtils.dip2px(paddingBottomInDp));
|
||||
}
|
||||
|
||||
@BindingAdapter("visibleInvisible")
|
||||
public static void visibleInvisible(View view, Boolean show) {
|
||||
if (show != null && show) {
|
||||
view.setVisibility(View.VISIBLE);
|
||||
@ -292,7 +219,6 @@ public class BindingAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("messageUnread")
|
||||
public static void setMessageUnread(TextView view, int unreadCount) {
|
||||
if (unreadCount < 100) {
|
||||
view.setText(String.valueOf(unreadCount));
|
||||
@ -301,7 +227,6 @@ public class BindingAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("serverTypePadding")
|
||||
public static void setServerTypePadding(TextView view, String serverType) {
|
||||
int paddRight = 0;
|
||||
if (TextUtils.isEmpty(serverType)) {
|
||||
@ -319,7 +244,6 @@ public class BindingAdapters {
|
||||
view.setPadding(0, 0, paddRight, 0);
|
||||
}
|
||||
|
||||
@BindingAdapter("serverType")
|
||||
public static void setServerType(TextView view, String serverType) {
|
||||
view.setText(serverType);
|
||||
if ("删档内测".equals(serverType) || "不删档内测".equals(serverType)) {
|
||||
@ -329,19 +253,22 @@ public class BindingAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("game")
|
||||
public static void setGame(View view, GameEntity gameEntity) {
|
||||
if (gameEntity != null && view instanceof GameIconView) {
|
||||
((GameIconView) view).displayGameIcon(gameEntity);
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("articleType")
|
||||
public static void setGameIcon(View view, GameEntity gameEntity) {
|
||||
if (gameEntity != null && view instanceof GameIconView) {
|
||||
((GameIconView) view).displayGameIcon(gameEntity.getIcon(), gameEntity.getIconSubscript());
|
||||
}
|
||||
}
|
||||
|
||||
public static void setArticleType(TextView view, String articleType) {
|
||||
NewsUtils.setNewsType(view, articleType, 0, 0);
|
||||
}
|
||||
|
||||
@BindingAdapter("detailDownloadText")
|
||||
public static void setDetailDownloadText(TextView view, GameEntity gameEntity) {
|
||||
if (gameEntity == null || gameEntity.getApk().isEmpty()) {
|
||||
view.setBackgroundResource(R.drawable.game_item_btn_pause_style);
|
||||
@ -350,7 +277,6 @@ public class BindingAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("liBaoBtn")
|
||||
public static void setLiBaoBtn(TextView view, String status) {
|
||||
if (TextUtils.isEmpty(status)) return;
|
||||
switch (status) {
|
||||
@ -415,14 +341,16 @@ public class BindingAdapters {
|
||||
}
|
||||
|
||||
// 大图下的进度条
|
||||
@BindingAdapter({"downloadButton", "traceEvent", "clickCallBack", "entrance", "location"})
|
||||
public static void setDownloadButton(DownloadProgressBar progressBar,
|
||||
public static void setDownloadButton(DownloadButton progressBar,
|
||||
GameEntity gameEntity,
|
||||
ExposureEvent traceEvent,
|
||||
@Nullable View.OnClickListener clickCallBack,
|
||||
@Nullable String entrance,
|
||||
@Nullable String location) {
|
||||
|
||||
// 恢复DialogFragment
|
||||
restoreDialogFragment(progressBar);
|
||||
|
||||
// 判断是否显示按钮
|
||||
if (gameEntity != null
|
||||
&& Config.isShowDownload(gameEntity.getId())
|
||||
@ -436,62 +364,77 @@ public class BindingAdapters {
|
||||
// 点击事件
|
||||
progressBar.setOnClickListener(v -> {
|
||||
if (clickCallBack != null) clickCallBack.onClick(v);
|
||||
switch (progressBar.getDownloadType()) {
|
||||
switch (progressBar.getButtonStyle()) {
|
||||
case DOWNLOADING_PLUGIN:
|
||||
case DOWNLOADING_NORMAL:
|
||||
Intent intent = DownloadManagerActivity.getDownloadMangerIntent(v.getContext(),
|
||||
gameEntity.getApk().get(0).getUrl(), entrance);
|
||||
v.getContext().startActivity(intent);
|
||||
if (gameEntity.isVGame()) {
|
||||
v.getContext().startActivity(VDownloadManagerActivity.getIntent(v.getContext(), true));
|
||||
} else {
|
||||
Intent intent = DownloadManagerActivity.getDownloadMangerIntent(v.getContext(),
|
||||
gameEntity.getApk().get(0).getUrl(), entrance);
|
||||
v.getContext().startActivity(intent);
|
||||
}
|
||||
break;
|
||||
case NONE:
|
||||
Utils.toast(v.getContext(), "该游戏已关闭下载");
|
||||
break;
|
||||
case NORMAL:
|
||||
case PLUGIN:
|
||||
if (gameEntity.getApk().size() == 1) {
|
||||
ApkEntity apk = gameEntity.getApk().get(0);
|
||||
DownloadEntity downloadEntity = SimulatorGameManager.findDownloadEntityByUrl(apk.getUrl());
|
||||
if (gameEntity.getSimulator() != null) {
|
||||
boolean isInstalled = PackageUtils.isInstalledFromAllPackage(v.getContext(), gameEntity.getSimulator().getApk().getPackageName());
|
||||
if (downloadEntity != null && SimulatorGameManager.isSimulatorGame(gameEntity) && !isInstalled) {
|
||||
SimulatorDownloadManager.getInstance().showDownloadDialog(v.getContext(), gameEntity.getSimulator(),
|
||||
SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.getId(), gameEntity.getName(), null);
|
||||
return;
|
||||
final RegionSetting.GameH5Download gameH5Download = RegionSettingHelper.getGameH5DownloadByGameId(gameEntity.getId());
|
||||
if (gameH5Download != null) {
|
||||
DialogUtils.showGameH5DownloadDialog(v.getContext(), gameEntity, gameH5Download);
|
||||
} else {
|
||||
if (gameEntity.getApk().size() == 1) {
|
||||
ApkEntity apk = gameEntity.getApk().get(0);
|
||||
DownloadEntity downloadEntity = SimulatorGameManager.findDownloadEntityByUrl(apk.getUrl());
|
||||
if (gameEntity.getSimulator() != null) {
|
||||
boolean isInstalled = PackageUtils.isInstalledFromAllPackage(v.getContext(), gameEntity.getSimulator().getApk().getPackageName());
|
||||
if (downloadEntity != null && SimulatorGameManager.isSimulatorGame(gameEntity) && !isInstalled) {
|
||||
SimulatorDownloadManager.getInstance().showDownloadDialog(v.getContext(), gameEntity.getSimulator(),
|
||||
SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.getId(), gameEntity.getName(), null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ChainBuilder builder = new ChainBuilder();
|
||||
builder.addHandler(new ValidateVSpaceHandler());
|
||||
builder.addHandler(new GamePermissionHandler());
|
||||
builder.addHandler(new BrowserInstallHandler());
|
||||
builder.addHandler(new PackageCheckHandler());
|
||||
builder.addHandler(new DownloadDialogHelperHandler());
|
||||
builder.addHandler(new CertificationHandler());
|
||||
builder.addHandler(new VersionNumberHandler());
|
||||
builder.addHandler(new OverseaDownloadHandler());
|
||||
builder.addHandler(new CheckDownloadHandler());
|
||||
|
||||
builder.setProcessEndCallback(o -> {
|
||||
download(progressBar, gameEntity, traceEvent, (boolean) o, entrance, location);
|
||||
return null;
|
||||
});
|
||||
final ChainHandler chainHandler = builder.buildHandlerChain();
|
||||
if (chainHandler != null) {
|
||||
chainHandler.handleRequest(v.getContext(), gameEntity);
|
||||
}
|
||||
} else {
|
||||
ChainBuilder builder = new ChainBuilder();
|
||||
builder.addHandler(new GamePermissionHandler());
|
||||
builder.addHandler(new CertificationHandler());
|
||||
builder.addHandler(new VersionNumberHandler());
|
||||
|
||||
builder.setProcessEndCallback(o -> {
|
||||
DownloadDialog.showDownloadDialog(
|
||||
v.getContext(),
|
||||
gameEntity,
|
||||
traceEvent,
|
||||
entrance,
|
||||
location + ":" + gameEntity.getName());
|
||||
return null;
|
||||
});
|
||||
final ChainHandler chainHandler = builder.buildHandlerChain();
|
||||
if (chainHandler != null) {
|
||||
chainHandler.handleRequest(v.getContext(), gameEntity);
|
||||
}
|
||||
}
|
||||
RealNameHelper.checkIfAuth(v.getContext(), gameEntity, () -> {
|
||||
GamePermissionDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity, gameEntity.getInfo(), () -> {
|
||||
BrowserInstallHelper.showBrowserInstallHintDialog(v.getContext(), () -> {
|
||||
PackageCheckDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity, () -> {
|
||||
DownloadDialogHelper.findAvailableDialogAndShow(v.getContext(), gameEntity, apk, () -> {
|
||||
CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> {
|
||||
DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> {
|
||||
DialogUtils.showOverseaDownloadDialog(v.getContext(), gameEntity, () -> {
|
||||
DialogUtils.checkDownload(v.getContext(), apk.getSize(),
|
||||
isSubscribe -> download(progressBar, gameEntity, traceEvent, isSubscribe, entrance, location));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
RealNameHelper.checkIfAuth(v.getContext(), gameEntity, () -> {
|
||||
GamePermissionDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity, gameEntity.getInfo(), () -> {
|
||||
CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> {
|
||||
DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> {
|
||||
DownloadDialog.showDownloadDialog(
|
||||
v.getContext(),
|
||||
gameEntity,
|
||||
traceEvent,
|
||||
entrance,
|
||||
location + ":" + gameEntity.getName());
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
break;
|
||||
case LAUNCH_OR_OPEN:
|
||||
@ -510,7 +453,12 @@ public class BindingAdapters {
|
||||
}
|
||||
return;
|
||||
}
|
||||
DataUtils.onGameLaunchEvent(v.getContext(), gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), location);
|
||||
|
||||
if (gameEntity.isVGame()) {
|
||||
VHelper.installOrLaunch((AppCompatActivity) v.getContext(), gameEntity.getApk().get(0).getPackageName());
|
||||
return;
|
||||
}
|
||||
|
||||
PackageUtils.launchApplicationByPackageName(v.getContext(), gameEntity.getApk().get(0).getPackageName());
|
||||
} else {
|
||||
DownloadDialog.showDownloadDialog(
|
||||
@ -524,21 +472,25 @@ public class BindingAdapters {
|
||||
case INSTALL_PLUGIN:
|
||||
case INSTALL_NORMAL:
|
||||
if (gameEntity.getApk().size() == 1) {
|
||||
DownloadEntity downloadEntity = DownloadManager.getInstance(progressBar.getContext()).getDownloadEntityByUrl(gameEntity.getApk().get(0).getUrl());
|
||||
DownloadEntity downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity);
|
||||
String packageName = gameEntity.getApk().get(0).getPackageName();
|
||||
|
||||
if (gameEntity.isVGame()) {
|
||||
VHelper.installOrLaunch(v.getContext(), packageName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (downloadEntity != null) {
|
||||
PackageInstaller.install(v.getContext(), downloadEntity);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case RESERVABLE:
|
||||
RealNameHelper.checkIfAuth(v.getContext(), gameEntity, () -> {
|
||||
GamePermissionDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity, gameEntity.getInfo(), () -> {
|
||||
CheckLoginUtils.checkLogin(progressBar.getContext(), "", () -> {
|
||||
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(gameEntity, () -> {
|
||||
LogUtils.logReservation(gameEntity, traceEvent);
|
||||
updateReservation(progressBar, gameEntity);
|
||||
});
|
||||
dialogFragment.show(((AppCompatActivity) progressBar.getContext()).getSupportFragmentManager(), "reserve");
|
||||
GamePermissionDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity, gameEntity.getInfo(), () -> {
|
||||
CheckLoginUtils.checkLogin(progressBar.getContext(), "", () -> {
|
||||
ReservationHelper.reserve(v.getContext(), gameEntity.getId(), () -> {
|
||||
LogUtils.logReservation(gameEntity, traceEvent);
|
||||
updateReservation(progressBar, gameEntity);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -582,10 +534,10 @@ public class BindingAdapters {
|
||||
if (gameEntity.isReservable()) {
|
||||
if (!ReservationRepository.thisGameHasBeenReserved(gameEntity.getId())) {
|
||||
progressBar.setText("预约");
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.RESERVABLE);
|
||||
progressBar.setButtonStyle(DownloadButton.ButtonStyle.RESERVABLE);
|
||||
} else {
|
||||
progressBar.setText("已预约");
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.RESERVED);
|
||||
progressBar.setButtonStyle(DownloadButton.ButtonStyle.RESERVED);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -600,17 +552,17 @@ public class BindingAdapters {
|
||||
} else {
|
||||
progressBar.setText("查看");
|
||||
}
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.H5_GAME);
|
||||
progressBar.setButtonStyle(DownloadButton.ButtonStyle.H5_GAME);
|
||||
} else {
|
||||
if (offStatus != null && "dialog".equals(offStatus)) {
|
||||
progressBar.setText("查看");
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.NONE);
|
||||
progressBar.setButtonStyle(DownloadButton.ButtonStyle.NONE);
|
||||
} else if ("updating".equals(offStatus)) {
|
||||
progressBar.setText("更新中");
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.UPDATING);
|
||||
progressBar.setButtonStyle(DownloadButton.ButtonStyle.UPDATING);
|
||||
} else {
|
||||
progressBar.setText("暂无");
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.NONE);
|
||||
progressBar.setButtonStyle(DownloadButton.ButtonStyle.NONE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -618,14 +570,14 @@ public class BindingAdapters {
|
||||
String status = GameUtils.getDownloadBtnText(progressBar.getContext(), gameEntity, PluginLocation.only_game);
|
||||
switch (status) {
|
||||
case "插件化":
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.PLUGIN);
|
||||
progressBar.setButtonStyle(DownloadButton.ButtonStyle.PLUGIN);
|
||||
break;
|
||||
case "打开":
|
||||
case "启动":
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.LAUNCH_OR_OPEN);
|
||||
progressBar.setButtonStyle(DownloadButton.ButtonStyle.LAUNCH_OR_OPEN);
|
||||
break;
|
||||
default:
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.NORMAL);
|
||||
progressBar.setButtonStyle(DownloadButton.ButtonStyle.NORMAL);
|
||||
break;
|
||||
}
|
||||
progressBar.setText(status);
|
||||
@ -633,7 +585,7 @@ public class BindingAdapters {
|
||||
|
||||
// 显示下载过程状态
|
||||
if (gameEntity.getApk().size() == 1) {
|
||||
DownloadEntity downloadEntity = DownloadManager.getInstance(progressBar.getContext()).getDownloadEntityByUrl(gameEntity.getApk().get(0).getUrl());
|
||||
DownloadEntity downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity);
|
||||
if (downloadEntity != null) {
|
||||
progressBar.setProgress((int) (downloadEntity.getPercent() * 10));
|
||||
switch (downloadEntity.getStatus()) {
|
||||
@ -644,23 +596,27 @@ public class BindingAdapters {
|
||||
case waiting:
|
||||
progressBar.setText(R.string.downloading);
|
||||
if (downloadEntity.isPluggable() && PackagesManager.INSTANCE.isInstalled(downloadEntity.getPackageName())) {
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.DOWNLOADING_PLUGIN);
|
||||
progressBar.setButtonStyle(DownloadButton.ButtonStyle.DOWNLOADING_PLUGIN);
|
||||
} else {
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.DOWNLOADING_NORMAL);
|
||||
progressBar.setButtonStyle(DownloadButton.ButtonStyle.DOWNLOADING_NORMAL);
|
||||
}
|
||||
break;
|
||||
case done:
|
||||
progressBar.setText(R.string.install);
|
||||
if (downloadEntity.isPluggable()
|
||||
&& PackagesManager.INSTANCE.isInstalled(downloadEntity.getPackageName())) {
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.INSTALL_PLUGIN);
|
||||
progressBar.setButtonStyle(DownloadButton.ButtonStyle.INSTALL_PLUGIN);
|
||||
} else {
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.INSTALL_NORMAL);
|
||||
progressBar.setButtonStyle(DownloadButton.ButtonStyle.INSTALL_NORMAL);
|
||||
}
|
||||
break;
|
||||
case cancel:
|
||||
case hijack:
|
||||
case notfound:
|
||||
case uncertificated:
|
||||
case unqualified:
|
||||
case unavailable:
|
||||
case banned:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -669,6 +625,18 @@ public class BindingAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当页面完全重建时,若存在重建的DialogFragment,则需要手动恢复该DialogFragment之前配置的回调(因为DialogFragment重建时只会从arguments中获取之前的配置内容,
|
||||
* 而arguments无法传递回调),或者dismiss该DialogFragment
|
||||
*/
|
||||
private static void restoreDialogFragment(DownloadButton progressBar) {
|
||||
GamePermissionDialogFragment gamePermissionDialogFragment =
|
||||
((GamePermissionDialogFragment) ((AppCompatActivity) progressBar.getContext()).getSupportFragmentManager().findFragmentByTag(GamePermissionDialogFragment.class.getName()));
|
||||
if (gamePermissionDialogFragment != null) {
|
||||
gamePermissionDialogFragment.dismissAllowingStateLoss();
|
||||
}
|
||||
}
|
||||
|
||||
/*private static void download(DownloadProgressBar progressBar, GameEntity gameEntity, ExposureEvent traceEvent, @Nullable String entrance, @Nullable String location, View v) {
|
||||
if (gameEntity.getApk().size() == 1) {
|
||||
ApkEntity apk = gameEntity.getApk().get(0);
|
||||
@ -687,28 +655,28 @@ public class BindingAdapters {
|
||||
}*/
|
||||
|
||||
|
||||
private static void updateReservation(DownloadProgressBar progressBar, GameEntity gameEntity) {
|
||||
private static void updateReservation(DownloadButton progressBar, GameEntity gameEntity) {
|
||||
// 显示预约
|
||||
if (gameEntity.isReservable()) {
|
||||
if (!ReservationRepository.thisGameHasBeenReserved(gameEntity.getId())) {
|
||||
progressBar.setText("预约");
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.RESERVABLE);
|
||||
progressBar.setButtonStyle(DownloadButton.ButtonStyle.RESERVABLE);
|
||||
} else {
|
||||
progressBar.setText("已预约");
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.RESERVED);
|
||||
progressBar.setButtonStyle(DownloadButton.ButtonStyle.RESERVED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 开始下载
|
||||
private static void download(DownloadProgressBar progressBar,
|
||||
private static void download(DownloadButton progressBar,
|
||||
GameEntity gameEntity,
|
||||
ExposureEvent traceEvent,
|
||||
boolean isSubscribe,
|
||||
String entrance,
|
||||
String location) {
|
||||
String str = progressBar.getText();
|
||||
String str = progressBar.getText().toString();
|
||||
String method;
|
||||
if (str.contains("更新")) {
|
||||
method = "更新";
|
||||
@ -720,8 +688,6 @@ public class BindingAdapters {
|
||||
ApkEntity apkEntity = gameEntity.getApk().get(0);
|
||||
String msg = FileUtils.isCanDownload(progressBar.getContext(), apkEntity.getSize());
|
||||
if (TextUtils.isEmpty(msg)) {
|
||||
DataUtils.onGameDownloadEvent(progressBar.getContext(), gameEntity.getName(), apkEntity.getPlatform(), entrance, "下载开始", method);
|
||||
|
||||
DownloadManager.createDownload(progressBar.getContext(),
|
||||
apkEntity,
|
||||
gameEntity,
|
||||
@ -732,21 +698,60 @@ public class BindingAdapters {
|
||||
traceEvent);
|
||||
|
||||
progressBar.setProgress(0);
|
||||
progressBar.setDownloadType("插件化".equals(method) ?
|
||||
DownloadProgressBar.DownloadType.DOWNLOADING_PLUGIN : DownloadProgressBar.DownloadType.DOWNLOADING_NORMAL);
|
||||
progressBar.setButtonStyle("插件化".equals(method) ?
|
||||
DownloadButton.ButtonStyle.DOWNLOADING_PLUGIN : DownloadButton.ButtonStyle.DOWNLOADING_NORMAL);
|
||||
} else {
|
||||
Utils.toast(progressBar.getContext(), msg);
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("gameLabelList")
|
||||
public static void setGameLabelList(LinearLayout layout, List<TagStyleEntity> tagStyle) {
|
||||
GameViewUtils.setLabelList(layout.getContext(), layout, tagStyle);
|
||||
}
|
||||
|
||||
// 包含测试开服标签
|
||||
@BindingAdapter("setGameTags")
|
||||
public static void setGameTags(LinearLayout layout, GameEntity gameEntity) {
|
||||
try {
|
||||
if (layout.getVisibility() == View.GONE) return;
|
||||
ArrayList<TagStyleEntity> tagStyle = new ArrayList<>();
|
||||
TestEntity test = gameEntity.getTest();
|
||||
if (test != null
|
||||
// 这个判断用于开测表列表
|
||||
&& !"type_tag".equals(test.getGameTag())) {
|
||||
if ("custom".equals(test.getGameTag())) {
|
||||
TagStyleEntity typeTag = new TagStyleEntity();
|
||||
if (!TextUtils.isEmpty(test.getText())) {
|
||||
typeTag.setName(test.getText() != null ? test.getText() : "");
|
||||
} else {
|
||||
typeTag.setName(test.getType() != null ? test.getType() : "");
|
||||
}
|
||||
typeTag.setBackground("E8F3FF");
|
||||
typeTag.setColor("1383EB");
|
||||
tagStyle.add(typeTag);
|
||||
} else {
|
||||
TagStyleEntity typeTag = new TagStyleEntity();
|
||||
boolean isDarkModeOn = DarkModeUtils.INSTANCE.isDarkModeOn(layout.getContext());
|
||||
typeTag.setName(test.getType() != null ? test.getType() : "");
|
||||
typeTag.setBackground("1AFFA142");
|
||||
typeTag.setColor(isDarkModeOn ? "EB9238" : "FFA142");
|
||||
tagStyle.add(typeTag);
|
||||
|
||||
TagStyleEntity timeTag = new TagStyleEntity();
|
||||
timeTag.setName(GameViewUtils.getGameTestDate(test.getStart()));
|
||||
timeTag.setBackground("1A06CEA8");
|
||||
timeTag.setColor(isDarkModeOn ? "07A385" : "06CEA8");
|
||||
tagStyle.add(timeTag);
|
||||
}
|
||||
} else {
|
||||
tagStyle = gameEntity.getTagStyle();
|
||||
}
|
||||
GameViewUtils.setLabelList(layout.getContext(), layout, tagStyle);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void setVideoDetailGameTags(LinearLayout layout, GameEntity gameEntity) {
|
||||
try {
|
||||
ArrayList<TagStyleEntity> tagStyle = new ArrayList<>();
|
||||
TestEntity test = gameEntity.getTest();
|
||||
@ -767,20 +772,18 @@ public class BindingAdapters {
|
||||
} else {
|
||||
tagStyle = gameEntity.getTagStyle();
|
||||
}
|
||||
GameViewUtils.setLabelList(layout.getContext(), layout, tagStyle);
|
||||
GameViewUtils.setLabelList(layout.getContext(), layout, tagStyle, 4);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("isRefreshing")
|
||||
public static void isRefreshing(SwipeRefreshLayout layout, LoadStatus status) {
|
||||
if (status != LoadStatus.INIT_LOADING && status != LoadStatus.LIST_LOADING) {
|
||||
layout.setRefreshing(false);
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter({"setGameName", "isShowPlatform", "isShowSuffix"})
|
||||
public static void setGameName(TextView view, GameEntity game, boolean isShowPlatform, @Nullable Boolean isShowSuffix) {
|
||||
if (isShowSuffix == null) isShowSuffix = true; // 默认显示
|
||||
if (isShowPlatform && game.getApk().size() > 0) {
|
||||
@ -793,7 +796,6 @@ public class BindingAdapters {
|
||||
|
||||
}
|
||||
|
||||
@BindingAdapter({"setCommunityImage", "setCommunityVideoImage"})
|
||||
public static void setCommunityImage(SimpleDraweeView imageView, List<String> images, List<CommunityVideoEntity> videos) {
|
||||
if (videos.size() > 0) {
|
||||
CommunityVideoEntity videoEntity = videos.get(0);
|
||||
@ -807,11 +809,10 @@ public class BindingAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter({"setCommunityVideoDuration"})
|
||||
public static void setCommunityVideoDuration(TextView mVideoDuration, List<CommunityVideoEntity> videos) {
|
||||
if (videos != null && videos.size() > 0) {
|
||||
CommunityVideoEntity videoEntity = videos.get(0);
|
||||
mVideoDuration.setBackground(DrawableView.getOvalDrawable(R.color.black_alpha_80, 999F));
|
||||
mVideoDuration.setBackground(DrawableView.getOvalDrawable(R.color.black_alpha_50, 999F));
|
||||
mVideoDuration.setText(videoEntity.getDuration());
|
||||
mVideoDuration.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
@ -819,7 +820,6 @@ public class BindingAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter({"setGameTags", "setMaxGameTags"})
|
||||
public static void setGameTags(TextView view, List<TagStyleEntity> tags, int maxTags) {
|
||||
if (tags == null) {
|
||||
view.setText("");
|
||||
@ -848,7 +848,6 @@ public class BindingAdapters {
|
||||
view.setText(span);
|
||||
}
|
||||
|
||||
@BindingAdapter({"setVideoData"})
|
||||
public static void setVideoData(TextView view, int count) {
|
||||
if (count > 0) {
|
||||
view.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(view.getContext(), R.drawable.ic_video_data_up), null, null, null);
|
||||
@ -856,7 +855,7 @@ public class BindingAdapters {
|
||||
view.setText(count + "");
|
||||
} else {
|
||||
view.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
|
||||
view.setTextColor(ContextCompat.getColor(view.getContext(), R.color.text_999999));
|
||||
view.setTextColor(ContextCompat.getColor(view.getContext(), R.color.text_subtitleDesc));
|
||||
view.setText("-");
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,100 @@
|
||||
package com.gh.common.dialog
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.view.CustomLinkMovementMethod
|
||||
import com.gh.gamecenter.core.utils.SpanBuilder
|
||||
import com.gh.gamecenter.databinding.DialogApplyModeratorBinding
|
||||
|
||||
|
||||
class ApplyModeratorDialogFragment : BaseDialogFragment() {
|
||||
private lateinit var binding: DialogApplyModeratorBinding
|
||||
private var mGroupNumber = ""
|
||||
private var mGroupKey = ""
|
||||
private var mParentTag = ""
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
requireArguments().run {
|
||||
mGroupNumber = getString(KEY_GROUP_NUMBER) ?: ""
|
||||
mGroupKey = getString(KEY_GROUP_KEY) ?: ""
|
||||
mParentTag = getString(EntranceConsts.KEY_PARENT_TAG) ?: ""
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
binding = DialogApplyModeratorBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val startText = "版主考核群:"
|
||||
val text = "$startText$mGroupNumber\n感谢你对论坛建设的支持\n请加入版主考核群并联系群主进行版主资格考核"
|
||||
binding.desTv.text = SpanBuilder(text)
|
||||
.click(
|
||||
requireContext(),
|
||||
startText.length,
|
||||
startText.length + mGroupNumber.length,
|
||||
R.color.theme_font,
|
||||
true
|
||||
) {
|
||||
DirectUtils.directToQqGroup(
|
||||
requireContext(),
|
||||
mGroupKey
|
||||
)
|
||||
}
|
||||
.build()
|
||||
binding.desTv.movementMethod = CustomLinkMovementMethod.getInstance()
|
||||
binding.confirmTv.setOnClickListener {
|
||||
dismissAllowingStateLoss()
|
||||
activity?.supportFragmentManager?.findFragmentByTag(mParentTag)
|
||||
?.onActivityResult(REQUEST_CODE, Activity.RESULT_OK, null)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
val width = requireContext().resources.displayMetrics.widthPixels - 60F.dip2px()
|
||||
val height = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
dialog?.window?.setLayout(width, height)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val KEY_GROUP_NUMBER = "group_number"
|
||||
const val KEY_GROUP_KEY = "group_key"
|
||||
const val REQUEST_CODE = 1103
|
||||
|
||||
@JvmStatic
|
||||
fun show(
|
||||
activity: AppCompatActivity,
|
||||
number: String,
|
||||
key: String,
|
||||
tag: String
|
||||
) {
|
||||
ApplyModeratorDialogFragment().apply {
|
||||
arguments = Bundle().apply {
|
||||
putString(KEY_GROUP_NUMBER, number)
|
||||
putString(KEY_GROUP_KEY, key)
|
||||
putString(EntranceConsts.KEY_PARENT_TAG, tag)
|
||||
}
|
||||
}.show(
|
||||
activity.supportFragmentManager,
|
||||
ApplyModeratorDialogFragment::class.java.name
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -14,27 +14,31 @@ import android.view.View
|
||||
import android.widget.CheckBox
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.gh.common.avoidcallback.AvoidOnResultManager
|
||||
import com.gh.common.avoidcallback.Callback
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.util.CheckLoginUtils
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.common.util.GsonUtils
|
||||
import com.gh.common.util.SPUtils
|
||||
import com.gh.gamecenter.common.avoidcallback.AvoidOnResultManager
|
||||
import com.gh.gamecenter.common.avoidcallback.Callback
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.common.util.*
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.UserInfoEditActivity
|
||||
import com.gh.gamecenter.WebActivity
|
||||
import com.gh.gamecenter.ShellActivity
|
||||
import com.gh.gamecenter.common.callback.ConfirmListener
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.core.utils.GsonUtils
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.entity.AuthDialogEntity
|
||||
import com.gh.gamecenter.entity.AuthDialogLevel
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.user.UserViewModel
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.halo.assistant.fragment.user.UserInfoEditFragment
|
||||
import com.lightgame.utils.AppManager
|
||||
|
||||
class CertificationDialog(context: Context, private val authDialogEntity: AuthDialogEntity, val gameId: String, val listener: DialogUtils.ConfirmListener) :
|
||||
Dialog(context, R.style.GhAlertDialog) {
|
||||
class CertificationDialog(
|
||||
context: Context,
|
||||
private val authDialogEntity: AuthDialogEntity,
|
||||
val gameId: String,
|
||||
val listener: ConfirmListener
|
||||
) :
|
||||
Dialog(context, R.style.GhAlertDialog) {
|
||||
|
||||
private lateinit var view: View
|
||||
private lateinit var detailedDesTv: TextView
|
||||
@ -56,7 +60,7 @@ class CertificationDialog(context: Context, private val authDialogEntity: AuthDi
|
||||
detailedDesTv.paint.isAntiAlias = true
|
||||
|
||||
detailedDesTv.setOnClickListener {
|
||||
context.startActivity(WebActivity.getIntentByUrl(context, authDialogEntity.link))
|
||||
DirectUtils.directToWebView(context, authDialogEntity.link)
|
||||
}
|
||||
|
||||
when (authDialogEntity.level) {
|
||||
@ -120,8 +124,10 @@ class CertificationDialog(context: Context, private val authDialogEntity: AuthDi
|
||||
private fun gotoLoginPage() {
|
||||
val currentActivity = AppManager.getInstance().currentActivity() ?: return
|
||||
|
||||
CheckLoginUtils.checkLogin(currentActivity as AppCompatActivity,
|
||||
null, true, "实名认证弹窗") {
|
||||
CheckLoginUtils.checkLogin(
|
||||
currentActivity as AppCompatActivity,
|
||||
null, true, "实名认证弹窗"
|
||||
) {
|
||||
if (UserManager.getInstance().isAuth) {
|
||||
listener.onConfirm()
|
||||
dismiss()
|
||||
@ -134,10 +140,17 @@ class CertificationDialog(context: Context, private val authDialogEntity: AuthDi
|
||||
val currentActivity = AppManager.getInstance().currentActivity() ?: return
|
||||
|
||||
AvoidOnResultManager.getInstance(currentActivity as AppCompatActivity)
|
||||
.startForResult(UserInfoEditActivity.getIntent(context, UserViewModel.TYPE_ID_CARD), object : Callback {
|
||||
.startForResult(
|
||||
ShellActivity.getIntent(
|
||||
context,
|
||||
ShellActivity.Type.REAL_NAME_INFO,
|
||||
).apply {
|
||||
putExtra(EntranceConsts.KEY_GAME_ID, gameId)
|
||||
}, object : Callback {
|
||||
override fun onActivityResult(resultCode: Int, data: Intent?) {
|
||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||
val isAuthSuccess = data.getBooleanExtra(UserInfoEditFragment.AUTH_SUCCESS, false)
|
||||
val isAuthSuccess =
|
||||
data.getBooleanExtra(UserInfoEditFragment.AUTH_SUCCESS, false)
|
||||
if (isAuthSuccess) {
|
||||
listener.onConfirm()
|
||||
dismiss()
|
||||
@ -150,7 +163,7 @@ class CertificationDialog(context: Context, private val authDialogEntity: AuthDi
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun showCertificationDialog(context: Context, game: GameEntity, listener: DialogUtils.ConfirmListener) {
|
||||
fun showCertificationDialog(context: Context, game: GameEntity, listener: ConfirmListener) {
|
||||
//1.先判断是否登录 是执行2 否执行3
|
||||
//2.判断是否实名认证 是终止 否执行3
|
||||
//3.判断是否需要弹出认证弹窗接口
|
||||
@ -166,7 +179,7 @@ class CertificationDialog(context: Context, private val authDialogEntity: AuthDi
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private fun authDialog(context: Context, game: GameEntity, listener: DialogUtils.ConfirmListener) {
|
||||
private fun authDialog(context: Context, game: GameEntity, listener: ConfirmListener) {
|
||||
var authDialog: AuthDialogEntity? = null
|
||||
if (game.authDialog != null) {
|
||||
authDialog = game.authDialog
|
||||
|
||||
@ -8,7 +8,6 @@ import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Message
|
||||
import android.preference.PreferenceManager
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
@ -19,26 +18,31 @@ import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.util.*
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.core.utils.GsonUtils
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.common.utils.countDownTimer
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.common.utils.ImageUtils
|
||||
import com.gh.gamecenter.databinding.DialogDeviceRemindBinding
|
||||
import com.gh.gamecenter.entity.DeviceDialogEntity
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.halo.assistant.fragment.SettingsFragment.AUTO_INSTALL_SP_KEY
|
||||
import com.gh.gamecenter.setting.GameDownloadSettingFragment.Companion.AUTO_INSTALL_SP_KEY
|
||||
import com.lightgame.download.DataWatcher
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import com.lightgame.download.DownloadStatus
|
||||
import io.reactivex.disposables.Disposable
|
||||
import kotlinx.android.synthetic.main.dialog_device_remind.view.*
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
/**
|
||||
* 设备提醒弹窗
|
||||
*/
|
||||
class DeviceRemindDialog(context: Context, val entity: DeviceDialogEntity, val gameEntity: GameEntity) : Dialog(context, R.style.GhAlertDialog) {
|
||||
private lateinit var view: View
|
||||
class DeviceRemindDialog(context: Context, val entity: DeviceDialogEntity, val gameEntity: GameEntity) :
|
||||
Dialog(context, R.style.GhAlertDialog) {
|
||||
private val mBinding: DialogDeviceRemindBinding by lazy { DialogDeviceRemindBinding.inflate(layoutInflater) }
|
||||
private var currentPage = 0
|
||||
private var mSlideLooperInterval = 3000L
|
||||
private lateinit var mLooperHandle: LooperHandle
|
||||
@ -49,8 +53,7 @@ class DeviceRemindDialog(context: Context, val entity: DeviceDialogEntity, val g
|
||||
private val dataWatcher = object : DataWatcher() {
|
||||
override fun onDataChanged(downloadEntity: DownloadEntity) {
|
||||
if (downloadEntity.status == DownloadStatus.done && downloadEntity.name == gameEntity.name) {
|
||||
val sp = PreferenceManager.getDefaultSharedPreferences(getContext())
|
||||
val autoInstall = sp.getBoolean(AUTO_INSTALL_SP_KEY, true)
|
||||
val autoInstall = SPUtils.getBoolean(AUTO_INSTALL_SP_KEY, true)
|
||||
if (autoInstall) {
|
||||
dismiss()
|
||||
}
|
||||
@ -76,7 +79,8 @@ class DeviceRemindDialog(context: Context, val entity: DeviceDialogEntity, val g
|
||||
val type = object : TypeToken<List<DeviceDialogEntity>>() {}.type
|
||||
val entities = GsonUtils.gson.fromJson<List<DeviceDialogEntity>>(datas, type)
|
||||
//1.判断设备是否匹配
|
||||
val entity = entities.find { it.manufacturer.toLowerCase().startsWith(Build.MANUFACTURER.toLowerCase()) }
|
||||
val entity =
|
||||
entities.find { it.manufacturer.toLowerCase().startsWith(Build.MANUFACTURER.toLowerCase()) }
|
||||
?: return Pair(false, null)
|
||||
//2.判断游戏不含剔除标签
|
||||
gameEntity.tagStyle.forEach {
|
||||
@ -96,13 +100,12 @@ class DeviceRemindDialog(context: Context, val entity: DeviceDialogEntity, val g
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
view = LayoutInflater.from(context).inflate(R.layout.dialog_device_remind, null)
|
||||
setContentView(view)
|
||||
setContentView(mBinding.root)
|
||||
mDatas.addAll(entity.gallery)
|
||||
view.titleTv.text = entity.title
|
||||
view.contentTv.text = entity.content
|
||||
mBinding.titleTv.text = entity.title
|
||||
mBinding.contentTv.text = entity.content
|
||||
|
||||
view.bannerView.apply {
|
||||
mBinding.bannerView.apply {
|
||||
orientation = ViewPager2.ORIENTATION_HORIZONTAL
|
||||
mAdapter = BannerAdapter()
|
||||
val recyclerView = getChildAt(0) as RecyclerView
|
||||
@ -133,36 +136,36 @@ class DeviceRemindDialog(context: Context, val entity: DeviceDialogEntity, val g
|
||||
}
|
||||
val isFirst = SPUtils.getBoolean(Constants.SP_FIRST_DEVICE_REMIND, false)
|
||||
if (!isFirst) {
|
||||
view.cancelTv.isEnabled = false
|
||||
view.cancelTv.background = ContextCompat.getDrawable(context, R.drawable.button_round_f5f5f5)
|
||||
mBinding.cancelTv.isEnabled = false
|
||||
mBinding.cancelTv.background = ContextCompat.getDrawable(context, R.drawable.button_round_f5f5f5)
|
||||
disposable = countDownTimer(3) { finish, time ->
|
||||
if (finish) {
|
||||
view.cancelTv.isEnabled = true
|
||||
view.cancelTv.background = ContextCompat.getDrawable(context, R.drawable.button_blue_oval)
|
||||
view.cancelTv.text = "我知道了"
|
||||
view.cancelTv.setTextColor(ContextCompat.getColor(context, R.color.white))
|
||||
mBinding.cancelTv.isEnabled = true
|
||||
mBinding.cancelTv.background = ContextCompat.getDrawable(context, R.drawable.button_blue_oval)
|
||||
mBinding.cancelTv.text = "我知道了"
|
||||
mBinding.cancelTv.setTextColor(ContextCompat.getColor(context, R.color.white))
|
||||
} else {
|
||||
view.cancelTv.text = "我知道了(${time}S)"
|
||||
mBinding.cancelTv.text = "我知道了(${time}S)"
|
||||
}
|
||||
}
|
||||
|
||||
SPUtils.setBoolean(Constants.SP_FIRST_DEVICE_REMIND, true)
|
||||
} else {
|
||||
view.noRemindAgainCb.visibility = View.VISIBLE
|
||||
view.cancelTv.text = "我知道了"
|
||||
view.cancelTv.isEnabled = true
|
||||
view.cancelTv.setTextColor(ContextCompat.getColor(context, R.color.white))
|
||||
view.cancelTv.background = ContextCompat.getDrawable(context, R.drawable.button_blue_oval)
|
||||
mBinding.noRemindAgainCb.visibility = View.VISIBLE
|
||||
mBinding.cancelTv.text = "我知道了"
|
||||
mBinding.cancelTv.isEnabled = true
|
||||
mBinding.cancelTv.setTextColor(ContextCompat.getColor(context, R.color.white))
|
||||
mBinding.cancelTv.background = ContextCompat.getDrawable(context, R.drawable.button_blue_oval)
|
||||
}
|
||||
view.cancelTv.setOnClickListener {
|
||||
SPUtils.setBoolean(Constants.SP_NO_REMIND_AGAIN, view.noRemindAgainCb.isChecked)
|
||||
mBinding.cancelTv.setOnClickListener {
|
||||
SPUtils.setBoolean(Constants.SP_NO_REMIND_AGAIN, mBinding.noRemindAgainCb.isChecked)
|
||||
dismiss()
|
||||
}
|
||||
DownloadManager.getInstance(context).addObserver(dataWatcher)
|
||||
DownloadManager.getInstance().addObserver(dataWatcher)
|
||||
}
|
||||
|
||||
private fun addIndicator() {
|
||||
view.indicatorLl.removeAllViews()
|
||||
mBinding.indicatorLl.removeAllViews()
|
||||
mDatas.forEach { _ ->
|
||||
val indicatorView = ImageView(context).apply {
|
||||
setImageResource(R.drawable.selector_device_remind_indicator)
|
||||
@ -171,13 +174,13 @@ class DeviceRemindDialog(context: Context, val entity: DeviceDialogEntity, val g
|
||||
params.rightMargin = DisplayUtils.dip2px(1F)
|
||||
layoutParams = params
|
||||
}
|
||||
view.indicatorLl.addView(indicatorView)
|
||||
mBinding.indicatorLl.addView(indicatorView)
|
||||
}
|
||||
}
|
||||
|
||||
private fun slideIndicator(position: Int) {
|
||||
for (i in 0 until view.indicatorLl.childCount) {
|
||||
val childAt = view.indicatorLl.getChildAt(i)
|
||||
for (i in 0 until mBinding.indicatorLl.childCount) {
|
||||
val childAt = mBinding.indicatorLl.getChildAt(i)
|
||||
childAt.isSelected = i == position
|
||||
}
|
||||
}
|
||||
@ -188,7 +191,9 @@ class DeviceRemindDialog(context: Context, val entity: DeviceDialogEntity, val g
|
||||
|
||||
inner class BannerAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return object : RecyclerView.ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_device_remind_banner, parent, false)) {}
|
||||
return object : RecyclerView.ViewHolder(
|
||||
LayoutInflater.from(context).inflate(R.layout.item_device_remind_banner, parent, false)
|
||||
) {}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = if (mDatas.size == 1) mDatas.size else Int.MAX_VALUE
|
||||
@ -210,7 +215,7 @@ class DeviceRemindDialog(context: Context, val entity: DeviceDialogEntity, val g
|
||||
|
||||
fun scrollToNextPage() {
|
||||
currentPage++
|
||||
view.bannerView.setCurrentItem(currentPage, true)
|
||||
mBinding.bannerView.setCurrentItem(currentPage, true)
|
||||
}
|
||||
|
||||
fun startScroll() {
|
||||
@ -238,6 +243,6 @@ class DeviceRemindDialog(context: Context, val entity: DeviceDialogEntity, val g
|
||||
disposable!!.dispose()
|
||||
disposable = null
|
||||
}
|
||||
DownloadManager.getInstance(context).removeObserver(dataWatcher)
|
||||
DownloadManager.getInstance().removeObserver(dataWatcher)
|
||||
}
|
||||
}
|
||||
@ -10,27 +10,30 @@ import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.text.HtmlCompat
|
||||
import com.gh.base.fragment.BaseDialogFragment
|
||||
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.dip2px
|
||||
import com.gh.common.util.toColor
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.databinding.DialogGameOffServiceBinding
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
|
||||
// 游戏关闭下载弹窗
|
||||
class GameOffServiceDialogFragment
|
||||
// : BaseTrackableDialogFragment()
|
||||
: BaseDialogFragment() {
|
||||
class GameOffServiceDialogFragment : BaseDialogFragment() {
|
||||
|
||||
private var mDialog: GameEntity.Dialog? = null
|
||||
private var mBinding: DialogGameOffServiceBinding? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
mDialog = requireArguments().getParcelable(KEY_DIALOG)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return DialogGameOffServiceBinding
|
||||
.inflate(inflater)
|
||||
.apply { mBinding = this }
|
||||
.root
|
||||
.inflate(inflater)
|
||||
.apply { mBinding = this }
|
||||
.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
@ -49,16 +52,19 @@ class GameOffServiceDialogFragment
|
||||
|
||||
notEmptySite.forEachIndexed { index, site ->
|
||||
val siteTv = TextView(context)
|
||||
siteTv.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply {
|
||||
siteTv.layoutParams = LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
).apply {
|
||||
topMargin = 24F.dip2px()
|
||||
if (index == notEmptySite.size - 1) bottomMargin = 8F.dip2px()
|
||||
}
|
||||
siteTv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14F)
|
||||
siteTv.setTextColor(R.color.theme_font.toColor())
|
||||
siteTv.setTextColor(R.color.theme_font.toColor(requireContext()))
|
||||
siteTv.text = site.text
|
||||
siteTv.paintFlags = siteTv.paintFlags or Paint.UNDERLINE_TEXT_FLAG
|
||||
siteTv.setOnClickListener {
|
||||
// MtaHelper.onEvent("游戏下载状态按钮", getKey(), site.text)
|
||||
// MtaHelper.onEvent("游戏下载状态按钮", getKey(), site.text)
|
||||
DirectUtils.directToWebView(requireContext(), site.url, "(关闭下载弹窗)")
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
@ -73,18 +79,14 @@ class GameOffServiceDialogFragment
|
||||
return super.onCreateDialog(savedInstanceState).apply { setCanceledOnTouchOutside(true) }
|
||||
}
|
||||
|
||||
// override fun getEvent(): String {
|
||||
// return "游戏下载状态按钮"
|
||||
// }
|
||||
//
|
||||
// override fun getKey(): String {
|
||||
// return "查看详情弹窗"
|
||||
// }
|
||||
|
||||
companion object {
|
||||
const val KEY_DIALOG = "dialog"
|
||||
|
||||
@JvmStatic
|
||||
fun getInstance(dialog: GameEntity.Dialog) = GameOffServiceDialogFragment().apply {
|
||||
mDialog = dialog
|
||||
arguments = Bundle().apply {
|
||||
putParcelable(KEY_DIALOG, dialog)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -13,20 +13,25 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import com.airbnb.lottie.LottieAnimationView
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.util.PermissionHelper.INSTALL_PERMISSION_CODE
|
||||
import com.gh.common.xapk.XapkInstaller
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.utils.PermissionHelper
|
||||
import com.gh.gamecenter.common.utils.PermissionHelper.INSTALL_PERMISSION_CODE
|
||||
import com.gh.gamecenter.common.utils.getExtension
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import com.lightgame.utils.Utils
|
||||
import kotlin.random.Random
|
||||
|
||||
class InstallPermissionDialogFragment : BaseTrackableDialogFragment() {
|
||||
class InstallPermissionDialogFragment : BaseDialogFragment() {
|
||||
|
||||
lateinit var mView: View
|
||||
var isXapk = false
|
||||
var url: String = ""
|
||||
var mCallBack: (() -> Unit)? = null
|
||||
var mCallBack: ((isFromPermissionGrantedCallback: Boolean) -> Unit)? = null
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
mView = inflater.inflate(R.layout.dialog_install_permission, null, false)
|
||||
@ -54,18 +59,15 @@ class InstallPermissionDialogFragment : BaseTrackableDialogFragment() {
|
||||
}
|
||||
|
||||
closeTv.setOnClickListener {
|
||||
MtaHelper.onEvent(getEvent(), getKey(), "文案样式_点击以后再说")
|
||||
if (isXapk) {
|
||||
mCallBack?.invoke()
|
||||
mCallBack?.invoke(false)
|
||||
}
|
||||
dismiss()
|
||||
}
|
||||
closeIv.setOnClickListener {
|
||||
MtaHelper.onEvent(getEvent(), getKey(), "图标样式_点击关闭")
|
||||
dismiss()
|
||||
}
|
||||
activateTv.setOnClickListener {
|
||||
MtaHelper.onEvent(getEvent(), getKey(), if (randomNumber == 0) "文案样式_点击立即开启" else "图标样式_点击立即开启")
|
||||
PermissionHelper.toInstallPermissionSetting(requireActivity())
|
||||
if (isXapk) {
|
||||
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, requireActivity().javaClass.name)
|
||||
@ -77,44 +79,47 @@ class InstallPermissionDialogFragment : BaseTrackableDialogFragment() {
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (resultCode == RESULT_OK && requestCode == INSTALL_PERMISSION_CODE) {
|
||||
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "")
|
||||
SPUtils.setString(Constants.SP_XAPK_URL, "")
|
||||
mCallBack?.invoke()
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
|
||||
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "")
|
||||
SPUtils.setString(Constants.SP_XAPK_URL, "")
|
||||
}
|
||||
mCallBack?.invoke(true)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getEvent(): String = "安装引导弹窗"
|
||||
|
||||
override fun getKey(): String = "引导弹窗"
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun show(activity: AppCompatActivity, downloadEntity: DownloadEntity, callBack: (() -> Unit)?) {
|
||||
fun show(
|
||||
activity: AppCompatActivity,
|
||||
downloadEntity: DownloadEntity,
|
||||
callBack: ((isFromPermissionGrantedCallback: Boolean) -> Unit)?
|
||||
) {
|
||||
val isXapk = XapkInstaller.XAPK_EXTENSION_NAME == downloadEntity.path.getExtension()
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
callBack?.invoke()
|
||||
callBack?.invoke(false)
|
||||
return
|
||||
}
|
||||
val haveInstallPermission = activity.packageManager.canRequestPackageInstalls()
|
||||
if (haveInstallPermission) {
|
||||
callBack?.invoke()
|
||||
callBack?.invoke(false)
|
||||
return
|
||||
}
|
||||
if (isXapk) {
|
||||
val xapkUnzipVersions = Config.getSettings()?.permissionPopupAppliedVersions?.xapkUnzip
|
||||
if (xapkUnzipVersions?.contains(Build.VERSION.SDK_INT.toString()) == false) {
|
||||
callBack?.invoke()
|
||||
callBack?.invoke(false)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
val installVersions = Config.getSettings()?.permissionPopupAppliedVersions?.install
|
||||
if (installVersions?.contains(Build.VERSION.SDK_INT.toString()) == false) {
|
||||
callBack?.invoke()
|
||||
callBack?.invoke(false)
|
||||
return
|
||||
}
|
||||
}
|
||||
var installPermissionDialogFragment = activity.supportFragmentManager.findFragmentByTag(InstallPermissionDialogFragment::class.java.simpleName) as? InstallPermissionDialogFragment
|
||||
var installPermissionDialogFragment =
|
||||
activity.supportFragmentManager.findFragmentByTag(InstallPermissionDialogFragment::class.java.name) as? InstallPermissionDialogFragment
|
||||
if (installPermissionDialogFragment != null) {
|
||||
installPermissionDialogFragment.mCallBack = callBack
|
||||
installPermissionDialogFragment.isXapk = isXapk
|
||||
@ -128,7 +133,10 @@ class InstallPermissionDialogFragment : BaseTrackableDialogFragment() {
|
||||
this.isXapk = isXapk
|
||||
this.url = downloadEntity.url
|
||||
}
|
||||
installPermissionDialogFragment.show(activity.supportFragmentManager, InstallPermissionDialogFragment::class.java.simpleName)
|
||||
installPermissionDialogFragment.show(
|
||||
activity.supportFragmentManager,
|
||||
InstallPermissionDialogFragment::class.java.name
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,172 @@
|
||||
package com.gh.common.dialog
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned
|
||||
import android.text.TextPaint
|
||||
import android.text.style.ClickableSpan
|
||||
import android.view.*
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.WebActivity
|
||||
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.view.CustomLinkMovementMethod
|
||||
import com.gh.gamecenter.databinding.DialogPrivacyProtocolNewBinding
|
||||
import com.gh.gamecenter.entity.DialogEntity
|
||||
import splitties.bundle.put
|
||||
|
||||
class NewPrivacyPolicyDialogFragment : BaseDialogFragment() {
|
||||
|
||||
private var mCallBack: ((isSuccess: Boolean) -> Unit)? = null
|
||||
private val mBinding by lazy { DialogPrivacyProtocolNewBinding.inflate(layoutInflater) }
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
return mBinding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
updateView()
|
||||
}
|
||||
|
||||
private fun updateView() {
|
||||
val contentText = SpannableStringBuilder(
|
||||
"1.您可以通过《光环助手隐私政策》以及《儿童隐私保护声明》,了解我们如何收集、使用、存储、保护、对外提供您的个人信息以及您享有的权利\n" +
|
||||
"2.您可以通过《接入第三方SDK目录》了解本产品接入的第三方SDK的具体信息\n" +
|
||||
"3.您可以通过《应用权限列表》了解权限申请与使用情况说明\n" +
|
||||
"4.如果您是14周岁以下的未成年人,您需要和您监护人一起仔细阅读《儿童隐私保护声明》,并在征得您监护人同意后,使用我们的产品、服务或向我们提供信息"
|
||||
)
|
||||
|
||||
val privacyPolicyText = "《光环助手隐私政策》"
|
||||
val childrenPrivacyPolicyText = "《儿童隐私保护声明》"
|
||||
val thirdPartySdkText = "《接入第三方SDK目录》"
|
||||
val permissionListText = "《应用权限列表》"
|
||||
|
||||
val hypertextList = arrayListOf(
|
||||
privacyPolicyText,
|
||||
childrenPrivacyPolicyText,
|
||||
thirdPartySdkText,
|
||||
permissionListText
|
||||
)
|
||||
|
||||
val positionListPairList = arrayListOf<Pair<Int, Int>>()
|
||||
|
||||
for (hypertext in hypertextList) {
|
||||
var start = 0
|
||||
var index = 0
|
||||
while (index != -1) {
|
||||
index = contentText.indexOf(hypertext, start)
|
||||
start = index + hypertext.length
|
||||
if (index != -1) {
|
||||
positionListPairList.add(Pair(index, start))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (hypertextPositionPair in positionListPairList) {
|
||||
contentText.setSpan(object : ClickableSpan() {
|
||||
override fun updateDrawState(ds: TextPaint) {
|
||||
super.updateDrawState(ds)
|
||||
ds.color = ContextCompat.getColor(requireContext(), R.color.theme_font)
|
||||
ds.isUnderlineText = false
|
||||
}
|
||||
|
||||
override fun onClick(widget: View) {
|
||||
val privacyPolicyUrl = requireContext().getString(R.string.privacy_policy_url)
|
||||
val childrenPrivacyPolicyUrl = requireContext().getString(R.string.children_policy_url)
|
||||
val thirdPartySdkUrl = requireContext().getString(R.string.sdk_list_url)
|
||||
val permissionListUrl = requireContext().getString(R.string.permission_and_usage_url)
|
||||
|
||||
val selectedUrl =
|
||||
when (contentText.substring(hypertextPositionPair.first, hypertextPositionPair.second)) {
|
||||
privacyPolicyText -> privacyPolicyUrl
|
||||
childrenPrivacyPolicyText -> childrenPrivacyPolicyUrl
|
||||
thirdPartySdkText -> thirdPartySdkUrl
|
||||
permissionListText -> permissionListUrl
|
||||
else -> ""
|
||||
}
|
||||
|
||||
DirectUtils.directToExternalBrowser(requireContext(), selectedUrl)
|
||||
}
|
||||
}, hypertextPositionPair.first, hypertextPositionPair.second, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
|
||||
mBinding.contentTv.movementMethod = CustomLinkMovementMethod.getInstance()
|
||||
mBinding.contentTv.text = contentText
|
||||
|
||||
mBinding.refuseTv.setOnClickListener {
|
||||
mCallBack?.invoke(false)
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
mBinding.agreeTv.setOnClickListener {
|
||||
mCallBack?.invoke(true)
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val createDialog = super.onCreateDialog(savedInstanceState)
|
||||
createDialog.setCanceledOnTouchOutside(false)
|
||||
createDialog.setOnKeyListener(object : DialogInterface.OnKeyListener {
|
||||
override fun onKey(dialog: DialogInterface?, keyCode: Int, event: KeyEvent?): Boolean {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
||||
val window = createDialog.window
|
||||
window?.setGravity(Gravity.CENTER)
|
||||
return createDialog
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
val width = 300F.dip2px()
|
||||
val height = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
dialog?.window?.setLayout(width, height)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val KEY_DATA = "data"
|
||||
|
||||
@JvmStatic
|
||||
fun show(
|
||||
activity: FragmentActivity,
|
||||
privacyPolicyEntity: DialogEntity.PrivacyPolicyEntity? = null,
|
||||
callBack: ((isSuccess: Boolean) -> Unit)?
|
||||
) {
|
||||
var privacyDialogFragment =
|
||||
activity.supportFragmentManager.findFragmentByTag(NewPrivacyPolicyDialogFragment::class.java.name) as? NewPrivacyPolicyDialogFragment
|
||||
if (privacyDialogFragment != null) {
|
||||
privacyDialogFragment.mCallBack = callBack
|
||||
val transaction: FragmentTransaction = activity.supportFragmentManager.beginTransaction()
|
||||
transaction.show(privacyDialogFragment)
|
||||
transaction.commit()
|
||||
} else {
|
||||
privacyDialogFragment = NewPrivacyPolicyDialogFragment().apply {
|
||||
mCallBack = callBack
|
||||
}
|
||||
}
|
||||
privacyDialogFragment.arguments = Bundle().apply {
|
||||
put(KEY_DATA, privacyPolicyEntity)
|
||||
}
|
||||
privacyDialogFragment.show(
|
||||
activity.supportFragmentManager,
|
||||
NewPrivacyPolicyDialogFragment::class.java.name
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,127 +0,0 @@
|
||||
package com.gh.common.dialog
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.gh.common.util.GsonUtils
|
||||
import com.gh.common.util.MtaHelper
|
||||
import com.gh.common.util.PermissionHelper
|
||||
import com.gh.common.util.fromHtml
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.NotificationStyleEntity
|
||||
import com.gh.gamecenter.entity.NotificationUgc
|
||||
import com.lightgame.utils.Utils
|
||||
import kotlinx.android.synthetic.main.dialog_notification_hint.*
|
||||
import org.json.JSONArray
|
||||
import java.io.BufferedReader
|
||||
import java.io.IOException
|
||||
import java.io.InputStreamReader
|
||||
import kotlin.random.Random
|
||||
|
||||
// 通知权限弹窗
|
||||
class NotificationHintDialogFragment : BaseTrackableDialogFragment() {
|
||||
|
||||
private var mNotificationUgc: NotificationUgc? = null
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.dialog_notification_hint, null)
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val jsonString = getJsonFromAssets()
|
||||
if (jsonString.isNullOrEmpty()) {
|
||||
Utils.log("Failed to obtain configuration file")
|
||||
return
|
||||
}
|
||||
val index = Random.nextInt(2)
|
||||
val jsonArray = JSONArray(jsonString)
|
||||
val jsonObj = jsonArray.getJSONObject(index)
|
||||
if (!jsonObj.has(mNotificationUgc?.value)) {
|
||||
Utils.log("ugc type error")
|
||||
return
|
||||
}
|
||||
val styleEntityJson = jsonObj.getJSONObject(mNotificationUgc!!.value)
|
||||
val styleEntity = GsonUtils.fromJson(styleEntityJson.toString(), NotificationStyleEntity::class.java)
|
||||
val drawableId = resources.getIdentifier(styleEntity.image, "drawable", requireContext().packageName)
|
||||
notificationIv.setImageDrawable(ContextCompat.getDrawable(requireContext(), drawableId))
|
||||
notificationTitle.text = styleEntity.title
|
||||
notificationContent.text = styleEntity.content.fromHtml()
|
||||
if (index == 0) {
|
||||
closeIv.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_notification_close_1))
|
||||
} else {
|
||||
activateTv.background = ContextCompat.getDrawable(requireContext(), R.drawable.bg_notification_open_btn_style_1)
|
||||
activateTv.text = "优雅的开启"
|
||||
}
|
||||
|
||||
activateTv.setOnClickListener {
|
||||
MtaHelper.onEventWithBasicDeviceInfo(getEvent(), getKey(), "点击立即开启")
|
||||
MtaHelper.onEventWithBasicDeviceInfo(getEvent(), getKey(), "${styleEntity.scenes}_${styleEntity.styleNo}_点击立即开启")
|
||||
dismissAllowingStateLoss()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
//这种方案适用于 API 26, 即8.0(含8.0)以上可以用
|
||||
val intent = Intent()
|
||||
intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
|
||||
intent.putExtra(Settings.EXTRA_APP_PACKAGE, BuildConfig.APPLICATION_ID)
|
||||
startActivity(intent)
|
||||
} else {
|
||||
PermissionHelper.toPermissionSetting(requireActivity())
|
||||
}
|
||||
}
|
||||
|
||||
closeIv.setOnClickListener {
|
||||
dismissAllowingStateLoss()
|
||||
MtaHelper.onEventWithBasicDeviceInfo(getEvent(), getKey(), "点击关闭")
|
||||
MtaHelper.onEventWithBasicDeviceInfo(getEvent(), getKey(), "${styleEntity.scenes}_${styleEntity.styleNo}_点击关闭")
|
||||
}
|
||||
|
||||
dialog?.setCanceledOnTouchOutside(true)
|
||||
}
|
||||
|
||||
override fun getEvent(): String {
|
||||
return "推送引导弹窗"
|
||||
}
|
||||
|
||||
override fun getKey(): String {
|
||||
return "引导弹窗"
|
||||
}
|
||||
|
||||
override fun trackWithBasicDeviceInfo() = true
|
||||
|
||||
private fun getJsonFromAssets(): String? {
|
||||
val stringBuilder = StringBuilder()
|
||||
var bufferedReader: BufferedReader? = null
|
||||
var inputStreamReader: InputStreamReader? = null
|
||||
try {
|
||||
inputStreamReader = InputStreamReader(requireContext().assets.open("notification_style.json"))
|
||||
bufferedReader = BufferedReader(inputStreamReader)
|
||||
var line: String?
|
||||
while (bufferedReader.readLine().also { line = it } != null) {
|
||||
stringBuilder.append(line)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
} finally {
|
||||
inputStreamReader?.close()
|
||||
bufferedReader?.close()
|
||||
}
|
||||
return stringBuilder.toString()
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(ugc: NotificationUgc) = NotificationHintDialogFragment().apply {
|
||||
mNotificationUgc = ugc
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -15,17 +15,24 @@ import androidx.fragment.app.FragmentTransaction
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.base.BaseRecyclerViewHolder
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.view.CustomLinkMovementMethod
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.LogUtils
|
||||
import com.gh.common.util.PackageUtils
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
|
||||
import com.gh.gamecenter.common.callback.ConfirmListener
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.common.view.CustomLinkMovementMethod
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.core.utils.SpanBuilder
|
||||
import com.gh.gamecenter.databinding.FragmentPackageCheckBinding
|
||||
import com.gh.gamecenter.databinding.PackageCheckItemBinding
|
||||
import com.gh.gamecenter.entity.DetectionObjectEntity
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.entity.LinkEntity
|
||||
import com.gh.gamecenter.entity.PackageDialogEntity
|
||||
import com.gh.gamecenter.eventbus.EBPackage
|
||||
import com.halo.assistant.HaloApp
|
||||
@ -42,6 +49,7 @@ import org.greenrobot.eventbus.ThreadMode
|
||||
/**
|
||||
* 包名检测弹窗
|
||||
*/
|
||||
// TODO 将 gameEntity 放到 argument 里再取出,避免重建时为空
|
||||
class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
|
||||
private lateinit var binding: FragmentPackageCheckBinding
|
||||
@ -51,7 +59,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
private var mAdapter: PackageCheckAdapter? = null
|
||||
private var mAllInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
|
||||
var gameEntity: GameEntity? = null
|
||||
var callBack: DialogUtils.ConfirmListener? = null
|
||||
var callBack: ConfirmListener? = null
|
||||
|
||||
private val dataWatcher = object : DataWatcher() {
|
||||
override fun onDataChanged(downloadEntity: DownloadEntity) {
|
||||
@ -61,9 +69,16 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
detectionObjects?.forEach { detectionObject ->
|
||||
if (detectionObject.packages.contains(packageName)) {
|
||||
val packageLink = gameEntity?.packageDialog?.links?.find { it.buttonLink }
|
||||
LogUtils.uploadPackageCheck("pkg_check_pop_download", if (DownloadStatus.add == downloadEntity.status) "下载开始" else "下载完成",
|
||||
gameEntity, packageLink?.text ?: "", packageLink?.title
|
||||
?: "", downloadEntity.gameId, downloadEntity.getMetaExtra(Constants.GAME_NAME))
|
||||
LogUtils.uploadPackageCheck(
|
||||
"pkg_check_pop_download",
|
||||
if (DownloadStatus.add == downloadEntity.status) "下载开始" else "下载完成",
|
||||
gameEntity,
|
||||
packageLink?.text ?: "",
|
||||
packageLink?.title
|
||||
?: "",
|
||||
downloadEntity.gameId,
|
||||
downloadEntity.getMetaExtra(Constants.GAME_NAME)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -73,7 +88,9 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
EventBus.getDefault().register(this)
|
||||
LogUtils.uploadPackageCheck("pkg_check_pop_click", "出现弹窗", gameEntity, "", "", "", "")
|
||||
gameEntity?.let {
|
||||
LogUtils.uploadPackageCheck("pkg_check_pop_click", "出现弹窗", it, "", "", "", "")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
@ -95,9 +112,22 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
|
||||
val spanBuilder = SpanBuilder(it.linkHintText).build()
|
||||
it.links.forEachIndexed { index, link ->
|
||||
val linkSpan = SpanBuilder(link.title ?: "").click(0, (link.title
|
||||
?: "").length, R.color.theme_font, true) {
|
||||
LogUtils.uploadPackageCheck("pkg_check_pop_click", "点击链接", gameEntity, link.text, link.title, "", "")
|
||||
val linkSpan = SpanBuilder(link.title ?: "").click(
|
||||
requireContext(),
|
||||
0,
|
||||
(link.title ?: "").length,
|
||||
R.color.theme_font,
|
||||
true
|
||||
) {
|
||||
LogUtils.uploadPackageCheck(
|
||||
"pkg_check_pop_click",
|
||||
"点击链接",
|
||||
gameEntity,
|
||||
link.text,
|
||||
link.title,
|
||||
"",
|
||||
""
|
||||
)
|
||||
DirectUtils.directToLinkPage(requireContext(), link, "包名检测弹窗", "")
|
||||
}.build()
|
||||
spanBuilder.append(linkSpan)
|
||||
@ -154,7 +184,15 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
packageLink = entity.links.find { it.buttonLink }
|
||||
}
|
||||
if (packageLink != null) {
|
||||
LogUtils.uploadPackageCheck("pkg_check_pop_click", "点击前往下载", gameEntity, packageLink.text, packageLink.title, "", "")
|
||||
LogUtils.uploadPackageCheck(
|
||||
"pkg_check_pop_click",
|
||||
"点击前往下载",
|
||||
gameEntity,
|
||||
packageLink.text,
|
||||
packageLink.title,
|
||||
"",
|
||||
""
|
||||
)
|
||||
DirectUtils.directToLinkPage(requireContext(), packageLink, "包名检测弹窗", "")
|
||||
}
|
||||
}
|
||||
@ -202,6 +240,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
if (it >= mDuration) {
|
||||
mDisposable?.dispose()
|
||||
binding.downloadBtn.isEnabled = true
|
||||
binding.downloadBtn.background = R.drawable.bg_notification_open_btn_style_2.toDrawable()
|
||||
}
|
||||
}
|
||||
val animator = ValueAnimator.ofInt(0, 100)
|
||||
@ -237,7 +276,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
val height = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
requireDialog().window?.setLayout(width, height)
|
||||
requireDialog().setCanceledOnTouchOutside(true)
|
||||
DownloadManager.getInstance(context).addObserver(dataWatcher)
|
||||
DownloadManager.getInstance().addObserver(dataWatcher)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
@ -258,7 +297,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
mDisposable?.dispose()
|
||||
}
|
||||
LogUtils.uploadPackageCheck("pkg_check_pop_click", "关闭弹窗", gameEntity, "", "", "", "")
|
||||
DownloadManager.getInstance(context).removeObserver(dataWatcher)
|
||||
DownloadManager.getInstance().removeObserver(dataWatcher)
|
||||
}
|
||||
|
||||
//安装、卸载事件
|
||||
@ -270,7 +309,8 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
inner class PackageCheckAdapter(val context: Context, val entities: ArrayList<DetectionObjectEntity>) : BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
|
||||
inner class PackageCheckAdapter(val context: Context, val entities: ArrayList<DetectionObjectEntity>) :
|
||||
BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
|
||||
private var index = -1
|
||||
|
||||
fun notifyPackages() {
|
||||
@ -279,7 +319,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return PackageCheckViewHolder(PackageCheckItemBinding.bind(LayoutInflater.from(context).inflate(R.layout.package_check_item, parent, false)))
|
||||
return PackageCheckViewHolder(parent.toBinding())
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = entities.size
|
||||
@ -287,7 +327,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
if (holder is PackageCheckViewHolder) {
|
||||
val entity = entities[position]
|
||||
holder.binding.entity = entity
|
||||
holder.binding.gameNameTv.text = entity.text
|
||||
if (position <= index) {
|
||||
val isAllInstalled = checkDetectionsInstalled(mAllInstalledPackages, entity.packages)
|
||||
if (isAllInstalled) {
|
||||
@ -295,7 +335,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
holder.binding.statusTv.setTextColor(ContextCompat.getColor(context, R.color.theme_font))
|
||||
} else {
|
||||
holder.binding.statusTv.text = "未安装"
|
||||
holder.binding.statusTv.setTextColor(ContextCompat.getColor(context, R.color.text_FF4147))
|
||||
holder.binding.statusTv.setTextColor(ContextCompat.getColor(context, R.color.theme_red))
|
||||
}
|
||||
holder.binding.statusTv.visibility = View.VISIBLE
|
||||
} else {
|
||||
@ -305,11 +345,12 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
class PackageCheckViewHolder(val binding: PackageCheckItemBinding) : BaseRecyclerViewHolder<DetectionObjectEntity>(binding.root)
|
||||
class PackageCheckViewHolder(val binding: PackageCheckItemBinding) :
|
||||
BaseRecyclerViewHolder<DetectionObjectEntity>(binding.root)
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun show(activity: AppCompatActivity, gameEntity: GameEntity, callBack: DialogUtils.ConfirmListener) {
|
||||
fun show(activity: AppCompatActivity, gameEntity: GameEntity, callBack: ConfirmListener) {
|
||||
val packageDialogEntity = gameEntity.packageDialog
|
||||
if (packageDialogEntity == null) {
|
||||
callBack.onConfirm()
|
||||
@ -336,12 +377,13 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
|
||||
if (!activity.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) return
|
||||
|
||||
var dialogFragment = activity.supportFragmentManager.findFragmentByTag(PackageCheckDialogFragment::class.java.simpleName) as? PackageCheckDialogFragment
|
||||
var dialogFragment =
|
||||
activity.supportFragmentManager.findFragmentByTag(PackageCheckDialogFragment::class.java.name) as? PackageCheckDialogFragment
|
||||
if (dialogFragment == null) {
|
||||
dialogFragment = PackageCheckDialogFragment()
|
||||
dialogFragment.gameEntity = gameEntity
|
||||
dialogFragment.callBack = callBack
|
||||
dialogFragment.show(activity.supportFragmentManager, PackageCheckDialogFragment::class.java.simpleName)
|
||||
dialogFragment.show(activity.supportFragmentManager, PackageCheckDialogFragment::class.java.name)
|
||||
} else {
|
||||
dialogFragment.gameEntity = gameEntity
|
||||
dialogFragment.callBack = callBack
|
||||
@ -351,7 +393,10 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkDetectionsInstalled(allInstalledPackages: List<PackageInfo>, packages: ArrayList<String>): Boolean {
|
||||
private fun checkDetectionsInstalled(
|
||||
allInstalledPackages: List<PackageInfo>,
|
||||
packages: ArrayList<String>
|
||||
): Boolean {
|
||||
var isPackagesInstalled = false
|
||||
packages.forEach { packageName ->
|
||||
val isInstalled = allInstalledPackages.find { it.packageName == packageName } != null
|
||||
@ -364,7 +409,10 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
}
|
||||
|
||||
|
||||
fun isAllPackageInstalled(allInstalledPackages: List<PackageInfo>, packageDialogEntity: PackageDialogEntity): Boolean {
|
||||
fun isAllPackageInstalled(
|
||||
allInstalledPackages: List<PackageInfo>,
|
||||
packageDialogEntity: PackageDialogEntity
|
||||
): Boolean {
|
||||
var isAllInstalled = true
|
||||
packageDialogEntity.detectionObjects.forEach loop@{ obj ->
|
||||
if (!checkDetectionsInstalled(allInstalledPackages, obj.packages)) {
|
||||
|
||||
@ -1,157 +0,0 @@
|
||||
package com.gh.common.dialog
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned
|
||||
import android.text.TextPaint
|
||||
import android.text.method.ScrollingMovementMethod
|
||||
import android.text.style.ClickableSpan
|
||||
import android.view.*
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import com.gh.base.fragment.BaseDialogFragment
|
||||
import com.gh.common.util.dip2px
|
||||
import com.gh.common.view.CustomLinkMovementMethod
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.WebActivity
|
||||
|
||||
class PrivacyDialogFragment : BaseDialogFragment() {
|
||||
|
||||
// private val mLocalPrivacyHtml = "file:///android_asset/privacy_policies.html"
|
||||
// private val mLocalRegulationHtml = "file:///android_asset/user_regulation.html"
|
||||
|
||||
var containerView: View? = null
|
||||
var mCallBack: ((isSuccess: Boolean) -> Unit)? = null
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
containerView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_privacy_protocol, null, false)
|
||||
return containerView
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
// val mWebViewPrivacy = containerView?.findViewById<WebView>(R.id.webView)
|
||||
// val mWebViewRegulation = containerView?.findViewById<WebView>(R.id.webView2)
|
||||
//
|
||||
// mWebViewPrivacy?.isHorizontalScrollBarEnabled = false
|
||||
// mWebViewRegulation?.isHorizontalScrollBarEnabled = false
|
||||
|
||||
val contentTv = containerView?.findViewById<TextView>(R.id.contentTv)
|
||||
val descTv = containerView?.findViewById<TextView>(R.id.descTv)
|
||||
contentTv?.movementMethod = ScrollingMovementMethod()
|
||||
|
||||
val skipText = SpannableStringBuilder("查看完整版的隐私政策和用户协议")
|
||||
skipText.setSpan(object : ClickableSpan() {
|
||||
override fun updateDrawState(ds: TextPaint) {
|
||||
super.updateDrawState(ds)
|
||||
ds.color = ContextCompat.getColor(requireContext(), R.color.theme_font)
|
||||
ds.isUnderlineText = false
|
||||
}
|
||||
|
||||
override fun onClick(widget: View) {
|
||||
val intent = WebActivity.getIntent(requireContext(), context!!.getString(R.string.privacy_policy_url), true)
|
||||
context?.startActivity(intent)
|
||||
}
|
||||
}, skipText.length - 9, skipText.length - 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
|
||||
skipText.setSpan(object : ClickableSpan() {
|
||||
override fun updateDrawState(ds: TextPaint) {
|
||||
super.updateDrawState(ds)
|
||||
ds.color = ContextCompat.getColor(requireContext(), R.color.theme_font)
|
||||
ds.isUnderlineText = false
|
||||
}
|
||||
|
||||
override fun onClick(widget: View) {
|
||||
val intent = WebActivity.getIntent(requireContext(), context!!.getString(R.string.disclaimer_url), true)
|
||||
context?.startActivity(intent)
|
||||
}
|
||||
}, skipText.length - 4, skipText.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
descTv?.movementMethod = CustomLinkMovementMethod()
|
||||
descTv?.text = skipText
|
||||
|
||||
// val mWebViewPrivacy = containerView?.findViewById<WebView>(R.id.webView)
|
||||
//
|
||||
// mWebViewPrivacy?.isHorizontalScrollBarEnabled = false
|
||||
//
|
||||
// val settingsArrayList = arrayListOf(mWebViewPrivacy?.settings, mWebViewRegulation?.settings)
|
||||
//
|
||||
// for (settings in settingsArrayList) {
|
||||
// settings?.javaScriptEnabled = true
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
// settings?.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
|
||||
// }
|
||||
// // 避免提示网页有害信息不能访问
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// settings?.safeBrowsingEnabled = false
|
||||
// }
|
||||
//
|
||||
// // 适配大于屏幕宽度的页面
|
||||
// settings?.useWideViewPort = true
|
||||
// settings?.loadWithOverviewMode = true
|
||||
// settings?.domStorageEnabled = true
|
||||
//
|
||||
// // 自适应屏幕
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
// settings?.layoutAlgorithm = WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING
|
||||
// }
|
||||
// }
|
||||
|
||||
// mWebViewPrivacy?.webViewClient = client
|
||||
// mWebViewRegulation?.webViewClient = client
|
||||
|
||||
containerView?.findViewById<View>(R.id.refuseTv)?.setOnClickListener {
|
||||
mCallBack?.invoke(false)
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
containerView?.findViewById<View>(R.id.agreeTv)?.setOnClickListener {
|
||||
mCallBack?.invoke(true)
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val createDialog = super.onCreateDialog(savedInstanceState)
|
||||
createDialog.setCanceledOnTouchOutside(false)
|
||||
createDialog.setOnKeyListener(object : DialogInterface.OnKeyListener {
|
||||
override fun onKey(dialog: DialogInterface?, keyCode: Int, event: KeyEvent?): Boolean {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
||||
val window = createDialog.window
|
||||
window?.setGravity(Gravity.CENTER)
|
||||
return createDialog
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
val width = requireContext().resources.displayMetrics.widthPixels - 60F.dip2px()
|
||||
val height = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
dialog?.window?.setLayout(width, height)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun show(activity: AppCompatActivity, callBack: ((isSuccess: Boolean) -> Unit)?) {
|
||||
var privacyDialogFragment = activity.supportFragmentManager.findFragmentByTag(PrivacyDialogFragment::class.java.simpleName) as? PrivacyDialogFragment
|
||||
if (privacyDialogFragment != null) {
|
||||
privacyDialogFragment.mCallBack = callBack
|
||||
val transaction: FragmentTransaction = activity.supportFragmentManager.beginTransaction()
|
||||
transaction.show(privacyDialogFragment)
|
||||
transaction.commit()
|
||||
} else {
|
||||
privacyDialogFragment = PrivacyDialogFragment().apply {
|
||||
mCallBack = callBack
|
||||
}
|
||||
privacyDialogFragment.show(activity.supportFragmentManager, PrivacyDialogFragment::class.java.simpleName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,195 @@
|
||||
package com.gh.common.dialog
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned
|
||||
import android.text.TextPaint
|
||||
import android.text.method.ScrollingMovementMethod
|
||||
import android.text.style.ClickableSpan
|
||||
import android.view.*
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.WebActivity
|
||||
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.fromHtml
|
||||
import com.gh.gamecenter.common.view.CustomLinkMovementMethod
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.databinding.DialogPrivacyProtocolBinding
|
||||
import com.gh.gamecenter.entity.DialogEntity
|
||||
import com.lightgame.utils.AppManager
|
||||
import splitties.bundle.put
|
||||
|
||||
class PrivacyPolicyDialogFragment : BaseDialogFragment() {
|
||||
|
||||
private var mCallBack: ((isSuccess: Boolean) -> Unit)? = null
|
||||
private val mBinding by lazy { DialogPrivacyProtocolBinding.inflate(layoutInflater) }
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
return mBinding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
mBinding.contentTv.movementMethod = ScrollingMovementMethod()
|
||||
|
||||
val privacyPolicyEntity = arguments?.get(KEY_DATA) as? DialogEntity.PrivacyPolicyEntity
|
||||
if (privacyPolicyEntity == null) {
|
||||
showPreLaunchStyle()
|
||||
} else {
|
||||
showUpdatedStyle(privacyPolicyEntity)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showUpdatedStyle(privacyPolicyEntity: DialogEntity.PrivacyPolicyEntity) {
|
||||
mBinding.titleIv.visibility = View.VISIBLE
|
||||
mBinding.privacyTitleTv.text = "光环助手《隐私协议》更新"
|
||||
mBinding.contentTv.text = privacyPolicyEntity.content.fromHtml()
|
||||
|
||||
val skipText = SpannableStringBuilder("查看隐私政策详情")
|
||||
skipText.setSpan(object : ClickableSpan() {
|
||||
override fun updateDrawState(ds: TextPaint) {
|
||||
super.updateDrawState(ds)
|
||||
ds.color = ContextCompat.getColor(requireContext(), R.color.theme_font)
|
||||
ds.isUnderlineText = false
|
||||
}
|
||||
|
||||
override fun onClick(widget: View) {
|
||||
val intent =
|
||||
WebActivity.getIntent(requireContext(), context!!.getString(R.string.privacy_policy_url), true)
|
||||
context?.startActivity(intent)
|
||||
}
|
||||
}, skipText.length - 6, skipText.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
mBinding.descTv.movementMethod = CustomLinkMovementMethod()
|
||||
mBinding.descTv.text = skipText
|
||||
|
||||
if (privacyPolicyEntity.alertType == "INFORM") {
|
||||
mBinding.refuseTv.visibility = View.GONE
|
||||
mBinding.agreeTv.text = "我知道了"
|
||||
mBinding.agreeTv.setOnClickListener {
|
||||
SPUtils.setString(Constants.SP_LAST_ACCEPTED_PRIVACY_DIALOG_ID, privacyPolicyEntity.id)
|
||||
mCallBack?.invoke(true)
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
} else {
|
||||
mBinding.refuseTv.text = "不同意退出"
|
||||
mBinding.agreeTv.text = "同意"
|
||||
mBinding.refuseTv.setOnClickListener {
|
||||
dismissAllowingStateLoss()
|
||||
AppManager.getInstance().finishAllActivity()
|
||||
}
|
||||
mBinding.agreeTv.setOnClickListener {
|
||||
SPUtils.setString(Constants.SP_LAST_ACCEPTED_PRIVACY_DIALOG_ID, privacyPolicyEntity.id)
|
||||
mCallBack?.invoke(true)
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showPreLaunchStyle() {
|
||||
val skipText = SpannableStringBuilder("查看完整版的隐私政策和用户协议")
|
||||
|
||||
skipText.setSpan(object : ClickableSpan() {
|
||||
override fun updateDrawState(ds: TextPaint) {
|
||||
super.updateDrawState(ds)
|
||||
ds.color = ContextCompat.getColor(requireContext(), R.color.theme_font)
|
||||
ds.isUnderlineText = false
|
||||
}
|
||||
|
||||
override fun onClick(widget: View) {
|
||||
val intent =
|
||||
WebActivity.getIntent(requireContext(), context!!.getString(R.string.privacy_policy_url), true)
|
||||
context?.startActivity(intent)
|
||||
}
|
||||
}, skipText.length - 9, skipText.length - 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
|
||||
skipText.setSpan(object : ClickableSpan() {
|
||||
override fun updateDrawState(ds: TextPaint) {
|
||||
super.updateDrawState(ds)
|
||||
ds.color = ContextCompat.getColor(requireContext(), R.color.theme_font)
|
||||
ds.isUnderlineText = false
|
||||
}
|
||||
|
||||
override fun onClick(widget: View) {
|
||||
val intent = WebActivity.getIntent(requireContext(), context!!.getString(R.string.disclaimer_url), true)
|
||||
context?.startActivity(intent)
|
||||
}
|
||||
}, skipText.length - 4, skipText.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
mBinding.descTv.movementMethod = CustomLinkMovementMethod()
|
||||
mBinding.descTv.text = skipText
|
||||
|
||||
mBinding.refuseTv.setOnClickListener {
|
||||
mCallBack?.invoke(false)
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
mBinding.agreeTv.setOnClickListener {
|
||||
mCallBack?.invoke(true)
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val createDialog = super.onCreateDialog(savedInstanceState)
|
||||
createDialog.setCanceledOnTouchOutside(false)
|
||||
createDialog.setOnKeyListener(object : DialogInterface.OnKeyListener {
|
||||
override fun onKey(dialog: DialogInterface?, keyCode: Int, event: KeyEvent?): Boolean {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
||||
val window = createDialog.window
|
||||
window?.setGravity(Gravity.CENTER)
|
||||
return createDialog
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
val width = requireContext().resources.displayMetrics.widthPixels - 60F.dip2px()
|
||||
val height = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
dialog?.window?.setLayout(width, height)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val KEY_DATA = "data"
|
||||
|
||||
@JvmStatic
|
||||
fun show(
|
||||
activity: FragmentActivity,
|
||||
privacyPolicyEntity: DialogEntity.PrivacyPolicyEntity? = null,
|
||||
callBack: ((isSuccess: Boolean) -> Unit)?
|
||||
) {
|
||||
var privacyDialogFragment =
|
||||
activity.supportFragmentManager.findFragmentByTag(PrivacyPolicyDialogFragment::class.java.name) as? PrivacyPolicyDialogFragment
|
||||
if (privacyDialogFragment != null) {
|
||||
privacyDialogFragment.mCallBack = callBack
|
||||
val transaction: FragmentTransaction = activity.supportFragmentManager.beginTransaction()
|
||||
transaction.show(privacyDialogFragment)
|
||||
transaction.commit()
|
||||
} else {
|
||||
privacyDialogFragment = PrivacyPolicyDialogFragment().apply {
|
||||
mCallBack = callBack
|
||||
}
|
||||
}
|
||||
privacyDialogFragment.arguments = Bundle().apply {
|
||||
put(KEY_DATA, privacyPolicyEntity)
|
||||
}
|
||||
privacyDialogFragment.show(
|
||||
activity.supportFragmentManager,
|
||||
PrivacyPolicyDialogFragment::class.java.name
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,17 +1,18 @@
|
||||
package com.gh.common.view
|
||||
package com.gh.common.dialog
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.base.BaseRecyclerViewHolder
|
||||
import com.gh.base.fragment.BaseDialogFragment
|
||||
import com.gh.common.util.fromHtml
|
||||
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
|
||||
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
|
||||
import com.gh.gamecenter.common.utils.ImageUtils
|
||||
import com.gh.gamecenter.common.utils.fromHtml
|
||||
import com.gh.gamecenter.GameDetailActivity
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.view.FixLinearLayoutManager
|
||||
import com.gh.gamecenter.databinding.DialogReserveBinding
|
||||
import com.gh.gamecenter.databinding.DialogReserveItemBinding
|
||||
import com.gh.gamecenter.entity.SimpleGameEntity
|
||||
@ -23,8 +24,8 @@ class ReserveDialog : BaseDialogFragment() {
|
||||
private lateinit var mReserveList: List<SimpleGameEntity>
|
||||
private var mDismissListener: (() -> Unit)? = null
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
val binding: DialogReserveBinding = DataBindingUtil.inflate(inflater, R.layout.dialog_reserve, container, false)
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
val binding: DialogReserveBinding = DialogReserveBinding.inflate(layoutInflater, null, false)
|
||||
|
||||
mReserveList = arguments?.getParcelableArrayList(RESERVE_LIST) ?: arrayListOf()
|
||||
|
||||
@ -54,7 +55,8 @@ class ReserveDialog : BaseDialogFragment() {
|
||||
|
||||
override fun onBindViewHolder(holder: ReserveDialogItemViewHolder, position: Int) {
|
||||
val entity = mReserveList[position]
|
||||
holder.binding.game = entity
|
||||
ImageUtils.display(holder.binding.icon, entity.icon)
|
||||
holder.binding.gameNameTv.text = entity.name
|
||||
holder.itemView.setOnClickListener {
|
||||
GameDetailActivity.startGameDetailActivity(mContext, entity.id, "(预约弹窗)")
|
||||
dismissAllowingStateLoss()
|
||||
@ -1,379 +0,0 @@
|
||||
package com.gh.common.dialog
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import android.os.Bundle
|
||||
import android.text.Html
|
||||
import android.view.*
|
||||
import android.view.animation.AnimationUtils
|
||||
import android.widget.EditText
|
||||
import android.widget.TextView
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import butterknife.OnClick
|
||||
import com.gh.base.fragment.BaseDialogFragment
|
||||
import com.gh.common.AppExecutor
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.history.HistoryHelper
|
||||
import com.gh.common.repository.ReservationRepository
|
||||
import com.gh.common.util.*
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.entity.NotificationUgc
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.ResponseBody
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
|
||||
// 预约弹窗
|
||||
class ReserveDialogFragment
|
||||
: BaseDialogFragment(), KeyboardHeightObserver {
|
||||
// : BaseTrackableDialogFragment() {
|
||||
|
||||
@BindView(R.id.reserve_hint_tv)
|
||||
lateinit var reserveHintTv: TextView
|
||||
|
||||
@BindView(R.id.reserve_content_tv)
|
||||
lateinit var reserveContentTv: TextView
|
||||
|
||||
@BindView(R.id.reserve_completed_content_tv)
|
||||
lateinit var reserveCompletedContentTv: TextView
|
||||
|
||||
@BindView(R.id.mobile_et)
|
||||
lateinit var mobileEt: EditText
|
||||
|
||||
@BindView(R.id.reserve_container)
|
||||
lateinit var reserveContainer: View
|
||||
|
||||
@BindView(R.id.reserve_completed_container)
|
||||
lateinit var reserveCompletedContainer: View
|
||||
|
||||
@BindView(R.id.customizable_btn)
|
||||
lateinit var customizableBtn: TextView
|
||||
|
||||
@BindView(R.id.content_container)
|
||||
lateinit var contentContainer: View
|
||||
|
||||
@BindView(R.id.mobile_index_container)
|
||||
lateinit var mobileIndexContainer: View
|
||||
|
||||
@BindView(R.id.mobile_index_reserve)
|
||||
lateinit var mobileIndexReserve: TextView
|
||||
|
||||
@BindView(R.id.mobile_index_user)
|
||||
lateinit var mobileIndexUser: TextView
|
||||
|
||||
@BindView(R.id.mobile_et_delete)
|
||||
lateinit var mobileEtDelete: View
|
||||
|
||||
@BindView(R.id.layout_container)
|
||||
lateinit var layoutContainer: View
|
||||
|
||||
private lateinit var mViewModel: ReserveViewModel
|
||||
|
||||
private var mSuccessCallback: SuccessCallback? = null
|
||||
|
||||
private var mGame: GameEntity? = null
|
||||
private var mGameId: String = ""
|
||||
private var mGameName: String = ""
|
||||
|
||||
private var mKeyboardHeightProvider: KeyboardHeightProvider? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
mViewModel = viewModelProvider()
|
||||
mKeyboardHeightProvider = KeyboardHeightProvider(activity)
|
||||
mKeyboardHeightProvider?.start()
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.dialog_reserve_game, null)
|
||||
}
|
||||
|
||||
// override fun getEvent(): String {
|
||||
// return "预约游戏"
|
||||
// }
|
||||
//
|
||||
// override fun getKey(): String {
|
||||
// return "预约功能操作"
|
||||
// }
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
ButterKnife.bind(this, view)
|
||||
|
||||
val reserveContent = "游戏上线,您将收到<font color='#1383EB'>免费短信</font>提醒"
|
||||
reserveContentTv.text = Html.fromHtml(reserveContent)
|
||||
|
||||
|
||||
mobileEt.setTextChangedListener { s, _, _, _ ->
|
||||
mobileIndexContainer.visibility = View.GONE
|
||||
mobileEtDelete.goneIf(s.trim().isEmpty())
|
||||
}
|
||||
|
||||
mViewModel.reservation.observeNonNull(this) {
|
||||
if (it.success) {
|
||||
showSuccessDialog(it.withMobile, it.boundWechat)
|
||||
mSuccessCallback?.onSuccess()
|
||||
HistoryHelper.insertGameEntity(mGame!!)
|
||||
}
|
||||
}
|
||||
|
||||
mViewModel.reserveMobile.observe(viewLifecycleOwner, Observer {
|
||||
setMobileIndexHint(it)
|
||||
})
|
||||
|
||||
dialog?.setCanceledOnTouchOutside(true)
|
||||
}
|
||||
|
||||
private fun showSuccessDialog(withMobile: Boolean, boundWechat: Boolean) {
|
||||
reserveHintTv.text = "游戏预约成功"
|
||||
reserveContainer.visibility = View.GONE
|
||||
reserveCompletedContainer.visibility = View.VISIBLE
|
||||
|
||||
val reservation = Config.getSettings()?.appointment
|
||||
val dialogConfig = if (withMobile) reservation?.withMobile else reservation?.withoutMobile
|
||||
|
||||
reserveCompletedContentTv.text = dialogConfig?.htmlContent?.fromHtml()
|
||||
if (dialogConfig?.text.isNullOrEmpty()
|
||||
|| (dialogConfig?.type == "wechat_bind" && boundWechat)) {
|
||||
customizableBtn.visibility = View.GONE
|
||||
} else {
|
||||
customizableBtn.text = dialogConfig?.text
|
||||
customizableBtn.setOnClickListener {
|
||||
// MtaHelper.onEvent("预约游戏", "预约功能操作", "点击跳转按钮")
|
||||
DirectUtils.directToLinkPage(
|
||||
requireContext(),
|
||||
dialogConfig!!.toLinkEntity(),
|
||||
"(游戏预约)",
|
||||
"")
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setMobileIndexHint(reserveMobile: String?) {
|
||||
var userMobile = UserManager.getInstance().userInfoEntity?.mobile
|
||||
if (reserveMobile == userMobile) userMobile = null
|
||||
|
||||
if (!reserveMobile.isNullOrEmpty()) {
|
||||
mobileIndexReserve.visibility = View.VISIBLE
|
||||
mobileIndexReserve.text = reserveMobile
|
||||
} else {
|
||||
mobileIndexReserve.visibility = View.GONE
|
||||
}
|
||||
|
||||
if (!userMobile.isNullOrEmpty()) {
|
||||
mobileIndexUser.visibility = View.VISIBLE
|
||||
mobileIndexUser.text = userMobile
|
||||
} else {
|
||||
mobileIndexUser.visibility = View.GONE
|
||||
}
|
||||
mobileIndexContainer.goneIf(mobileIndexUser.visibility == View.GONE && mobileIndexReserve.visibility == View.GONE)
|
||||
if (mobileIndexContainer.visibility ==View.VISIBLE) {
|
||||
mobileIndexContainer.animation = AnimationUtils.loadAnimation(requireContext(), R.anim.reserve_dialog_index_anim)
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.reserve_with_mobile_btn,
|
||||
R.id.reserve_without_mobile_btn,
|
||||
R.id.content_container,
|
||||
R.id.close_btn,
|
||||
R.id.customizable_btn,
|
||||
R.id.mobile_index_reserve,
|
||||
R.id.mobile_index_user,
|
||||
R.id.mobile_et_delete,
|
||||
R.id.mobile_et,
|
||||
R.id.layout_container)
|
||||
fun onClick(view: View) {
|
||||
when (view.id) {
|
||||
R.id.reserve_without_mobile_btn -> {
|
||||
// MtaHelper.onEvent("预约游戏", "预约功能操作", "点击无手机号预约")
|
||||
if (mobileIndexContainer.visibility == View.VISIBLE) {
|
||||
mobileIndexContainer.visibility = View.GONE
|
||||
return
|
||||
}
|
||||
|
||||
mViewModel.reserve(gameId = mGameId, gameName = mGameName)
|
||||
}
|
||||
|
||||
R.id.reserve_with_mobile_btn -> {
|
||||
if (mobileIndexContainer.visibility == View.VISIBLE) {
|
||||
mobileIndexContainer.visibility = View.GONE
|
||||
return
|
||||
}
|
||||
|
||||
val mobile = mobileEt.text.toString()
|
||||
if (mobile.length < 11 || !mobile.startsWith("1")) {
|
||||
Utils.toast(context, "手机号格式错误,请检查并重新输入")
|
||||
return
|
||||
}
|
||||
|
||||
// MtaHelper.onEvent("预约游戏", "预约功能操作", "点击立即预约")
|
||||
mViewModel.reserve(gameId = mGameId, gameName = mGameName, mobile = mobile)
|
||||
}
|
||||
|
||||
R.id.close_btn -> {
|
||||
// MtaHelper.onEvent("预约游戏", "预约功能操作", "点击关闭")
|
||||
dismissAllowingStateLoss()
|
||||
AppExecutor.uiExecutor.executeWithDelay(Runnable {
|
||||
NotificationHelper.showNotificationHintDialog(NotificationUgc.RESERVE_GAME)
|
||||
}, 1000)
|
||||
}
|
||||
R.id.content_container -> {
|
||||
mobileIndexContainer.visibility = View.GONE
|
||||
}
|
||||
R.id.mobile_index_reserve -> {
|
||||
mobileEt.setText(mobileIndexReserve.text.toString())
|
||||
mobileEt.setSelection(mobileEt.text.length)
|
||||
mobileIndexContainer.visibility = View.GONE
|
||||
}
|
||||
R.id.mobile_index_user -> {
|
||||
mobileEt.setText(mobileIndexUser.text.toString())
|
||||
mobileEt.setSelection(mobileEt.text.length)
|
||||
mobileIndexContainer.visibility = View.GONE
|
||||
}
|
||||
R.id.mobile_et_delete -> {
|
||||
mobileEt.setText("")
|
||||
}
|
||||
R.id.mobile_et -> {
|
||||
mobileIndexContainer.visibility = View.GONE
|
||||
}
|
||||
R.id.layout_container -> {
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if (HaloApp.getInstance().mCacheKeyboardHeight > 0) {
|
||||
val attributes = dialog?.window?.attributes
|
||||
val heightPixels = requireContext().resources.displayMetrics.heightPixels
|
||||
val mCacheKeyboardHeight = HaloApp.getInstance().mCacheKeyboardHeight
|
||||
val statusBarHeight = DisplayUtils.getStatusBarHeight(requireContext().resources)
|
||||
dialog?.window?.attributes?.height = heightPixels - mCacheKeyboardHeight - statusBarHeight
|
||||
attributes?.gravity = Gravity.TOP
|
||||
dialog?.window?.attributes = attributes
|
||||
}
|
||||
mKeyboardHeightProvider?.setKeyboardHeightObserver(this)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
mKeyboardHeightProvider?.setKeyboardHeightObserver(null)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
mKeyboardHeightProvider?.close()
|
||||
}
|
||||
|
||||
override fun onKeyboardHeightChanged(height: Int, orientation: Int) {
|
||||
if (height > 0) {
|
||||
val attributes = dialog?.window?.attributes
|
||||
attributes?.gravity = Gravity.CENTER
|
||||
dialog?.window?.attributes = attributes
|
||||
HaloApp.getInstance().mCacheKeyboardHeight = height
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(gameEntity: GameEntity, successCallback: SuccessCallback) = ReserveDialogFragment().apply {
|
||||
this.mGame = gameEntity
|
||||
this.mGameId = gameEntity.id
|
||||
this.mGameName = gameEntity.name ?: ""
|
||||
this.mSuccessCallback = successCallback
|
||||
}
|
||||
}
|
||||
|
||||
interface SuccessCallback {
|
||||
fun onSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
class ReserveViewModel(application: Application) : AndroidViewModel(application) {
|
||||
val reservation = MutableLiveData<Reservation>()
|
||||
|
||||
val reserveMobile = MutableLiveData<String>()
|
||||
|
||||
init {
|
||||
getAppointmentMobile()
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
fun reserve(gameId: String, gameName: String, mobile: String = "") {
|
||||
|
||||
val requestMap = hashMapOf<String, String>()
|
||||
requestMap["game_id"] = gameId
|
||||
if (mobile.isNotEmpty()) {
|
||||
requestMap["mobile"] = mobile
|
||||
}
|
||||
|
||||
RetrofitManager.getInstance(getApplication()).api
|
||||
.createNewGameReservation(requestMap.createRequestBody())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
var boundWechat = false
|
||||
tryWithDefaultCatch {
|
||||
boundWechat = JSONObject(data.string() ?: "").getBoolean("wechat_bind")
|
||||
}
|
||||
|
||||
reservation.postValue(Reservation(success = true, withMobile = mobile.isNotEmpty(), boundWechat = boundWechat))
|
||||
ReservationRepository.addReservationToMemoryAndRefresh(gameId)
|
||||
|
||||
// MtaHelper.onEvent("预约游戏", "预约", gameName)
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
Utils.toast(getApplication(), exception.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private fun getAppointmentMobile() {
|
||||
RetrofitManager.getInstance(getApplication()).api
|
||||
.getAppointmentMobile(UserManager.getInstance().userId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
var mobile: String? = null
|
||||
tryCatchInRelease {
|
||||
val jsonArray = JSONArray(data.string())
|
||||
if (jsonArray.length() > 0) {
|
||||
mobile = jsonArray.get(0).toString()
|
||||
}
|
||||
}
|
||||
|
||||
reserveMobile.postValue(mobile)
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
reserveMobile.postValue(null)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
class Reservation(var success: Boolean = false, var withMobile: Boolean = false, var boundWechat: Boolean = false)
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
package com.gh.common.dialog
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.KeyEvent
|
||||
import com.gh.common.util.MtaHelper
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
open class TrackableDialog(context: Context,
|
||||
themeResId: Int,
|
||||
private var mEvent: String,
|
||||
private var mKey: String,
|
||||
private var mValue: String? = null,
|
||||
private var mCancelValue: String? = null,
|
||||
private var mKeyBackValue: String? = null,
|
||||
private var mLogShowEvent: Boolean = true)
|
||||
: Dialog(context, themeResId) {
|
||||
|
||||
// 区分此 dialog 是点击 dialog 外部取消的还是点击返回取消的
|
||||
private val mIsCanceledByClickOutsideOfDialog = AtomicBoolean(true)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
setOnCancelListener {
|
||||
if (mIsCanceledByClickOutsideOfDialog.get()) {
|
||||
MtaHelper.onEvent(mEvent, mKey, mCancelValue ?: "点击空白")
|
||||
if (!mValue.isNullOrEmpty()) {
|
||||
MtaHelper.onEvent(mEvent, "点击空白", mValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setOnKeyListener { _, keyCode, event ->
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP) {
|
||||
mIsCanceledByClickOutsideOfDialog.set(false)
|
||||
MtaHelper.onEvent(mEvent, mKey, mKeyBackValue ?: "点击返回")
|
||||
if (mValue != null) {
|
||||
MtaHelper.onEvent(mEvent, "点击返回", mValue)
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun show() {
|
||||
super.show()
|
||||
if (mLogShowEvent) {
|
||||
MtaHelper.onEvent(mEvent, mKey, "出现弹窗")
|
||||
if (!mValue.isNullOrEmpty()) {
|
||||
MtaHelper.onEvent(mEvent, "出现弹窗", mValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,61 +0,0 @@
|
||||
package com.gh.common.exposure
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import com.gh.common.exposure.meta.Meta
|
||||
import com.gh.common.util.GsonUtils
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class ExposureConverters {
|
||||
|
||||
@TypeConverter
|
||||
fun convertPayload2String(any: ExposureEntity): String {
|
||||
return GsonUtils.toJson(any)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun convertString2Payload(string: String): ExposureEntity {
|
||||
return GsonUtils.fromJson(string, ExposureEntity::class.java)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun convertSource2String(sourceList: List<ExposureSource>): String {
|
||||
return GsonUtils.toJson(sourceList)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun convertString2Source(sourceList: String): List<ExposureSource> {
|
||||
return ArrayList(Arrays.asList(GsonUtils.fromJson(sourceList, Array<ExposureSource>::class.java))) as List<ExposureSource>
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun convertETrace2String(sourceList: List<ExposureEvent>?): String {
|
||||
return GsonUtils.toJson(sourceList)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun convertStringToETrace(sourceList: String): List<ExposureEvent> {
|
||||
return ArrayList(Arrays.asList(GsonUtils.fromJson(sourceList, Array<ExposureEvent>::class.java))) as List<ExposureEvent>
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun convertExposeType2String(exposureType: ExposureType): String {
|
||||
return exposureType.toString()
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun convertStringToExposeType(exposureType: String): ExposureType {
|
||||
return ExposureType.valueOf(exposureType)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun convertMeta2String(any: Meta): String {
|
||||
return GsonUtils.toJson(any)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun convertString2Meta(string: String): Meta {
|
||||
return GsonUtils.fromJson(string, Meta::class.java)
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
package com.gh.common.exposure
|
||||
|
||||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.TypeConverters
|
||||
import android.content.Context
|
||||
|
||||
@TypeConverters(ExposureConverters::class)
|
||||
@Database(entities = [ExposureEvent::class], version = 1, exportSchema = false)
|
||||
abstract class ExposureDatabase : RoomDatabase() {
|
||||
companion object {
|
||||
private const val DATABASE = "exposure_database"
|
||||
|
||||
fun buildDatabase(context: Context): ExposureDatabase {
|
||||
return Room.databaseBuilder(context, ExposureDatabase::class.java, DATABASE)
|
||||
.fallbackToDestructiveMigration()
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun logHubEventDao(): ExposureEventDao
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
package com.gh.common.exposure
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.annotation.Keep
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
|
||||
@Keep
|
||||
@Parcelize
|
||||
data class ExposureEntity(
|
||||
@SerializedName("game_id")
|
||||
val gameId: String? = "",
|
||||
val gameName: String? = "",
|
||||
val gameVersion: String? = "",
|
||||
val sequence: Int? = 0,
|
||||
val outerSequence: Int? = 0,
|
||||
val platform: String? = "",
|
||||
var isMirrorData: Boolean = false,
|
||||
@SerializedName("is_web_download")
|
||||
var isWebDownload: Boolean = false,
|
||||
val downloadType: String? = "",
|
||||
val downloadCompleteType: String? = "",
|
||||
@SerializedName("display_type")
|
||||
val displayType: String? = "",
|
||||
@SerializedName("is_platform_recommend")
|
||||
val isPlatformRecommend: Boolean? = false,
|
||||
|
||||
// 下载地址的 host 和 path
|
||||
var host: String? = "",
|
||||
var path: String? = "",
|
||||
|
||||
// 统计启动弹窗相关数据用的 (ugly)
|
||||
@SerializedName("dialog_id")
|
||||
var welcomeDialogId: String? = "",
|
||||
@SerializedName("link_title")
|
||||
var welcomeDialogLinkTitle: String? = ""
|
||||
) : Parcelable
|
||||
@ -2,71 +2,183 @@ package com.gh.common.exposure
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.annotation.Keep
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.exposure.meta.Meta
|
||||
import com.gh.common.exposure.meta.MetaUtil
|
||||
import com.gh.common.exposure.time.TimeUtil
|
||||
import com.gh.common.util.getFirstElementDividedByDivider
|
||||
import com.gh.download.server.BrowserInstallHelper
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.entity.ExposureEntity
|
||||
import com.gh.gamecenter.common.exposure.meta.Meta
|
||||
import com.gh.gamecenter.common.exposure.meta.MetaUtil
|
||||
import com.gh.gamecenter.common.utils.getFirstElementDividedByDivider
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import com.lightgame.utils.Utils
|
||||
import kotlinx.parcelize.IgnoredOnParcel
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
@Keep
|
||||
@Parcelize
|
||||
@Entity(tableName = "exposureEvent")
|
||||
data class ExposureEvent(
|
||||
var payload: ExposureEntity,
|
||||
val source: List<ExposureSource>,
|
||||
var eTrace: List<ExposureEvent>? = arrayListOf(),
|
||||
val event: ExposureType,
|
||||
val meta: Meta = MetaUtil.getMeta(),
|
||||
val time: Int = TimeUtil.currentTime(),
|
||||
@PrimaryKey
|
||||
val id: String = UUID.randomUUID().toString()) : Parcelable {
|
||||
companion object {
|
||||
var payload: ExposureEntity,
|
||||
var source: List<ExposureSource>,
|
||||
var eTrace: List<ExposureEvent>? = arrayListOf(),
|
||||
var event: ExposureType,
|
||||
val meta: Meta = MetaUtil.getMeta(),
|
||||
var time: Int = TimeUtil.currentTime(),
|
||||
var timeInMillisecond: Long = System.currentTimeMillis(),
|
||||
@PrimaryKey
|
||||
var id: String = UUID.randomUUID().toString(),
|
||||
) : Parcelable {
|
||||
|
||||
@Transient
|
||||
@IgnoredOnParcel
|
||||
var next: ExposureEvent? = null
|
||||
|
||||
@Transient
|
||||
@IgnoredOnParcel
|
||||
var flags = 0
|
||||
|
||||
private fun initExposureEventData(
|
||||
gameEntity: GameEntity?,
|
||||
source: List<ExposureSource>,
|
||||
eTrace: List<ExposureEvent>? = null,
|
||||
event: ExposureType = ExposureType.EXPOSURE
|
||||
) {
|
||||
this.payload = ExposureEntity(
|
||||
gameId = gameEntity?.id?.getFirstElementDividedByDivider(DownloadEntity.GAME_ID_DIVIDER),
|
||||
gameName = eTrace?.firstOrNull()?.payload?.gameName
|
||||
?: gameEntity?.name?.removeSuffix(Constants.GAME_NAME_DECORATOR),
|
||||
gameVersion = eTrace?.firstOrNull()?.payload?.gameVersion
|
||||
?: gameEntity?.gameVersion,
|
||||
subjectId = eTrace?.firstOrNull()?.payload?.subjectId
|
||||
?: gameEntity?.subjectId
|
||||
?: gameEntity?.subjectData?.id,
|
||||
isMirrorData = eTrace?.firstOrNull()?.payload?.isMirrorData
|
||||
?: gameEntity?.shouldUseMirrorInfo() ?: false,
|
||||
isWebDownload = BrowserInstallHelper.isUseBrowserToInstallEnabled() && BrowserInstallHelper.shouldUseBrowserToInstall(), // 实时的值,不用从 eTrace 里取
|
||||
sequence = eTrace?.firstOrNull()?.payload?.sequence ?: gameEntity?.sequence,
|
||||
outerSequence = eTrace?.firstOrNull()?.payload?.outerSequence
|
||||
?: gameEntity?.outerSequence,
|
||||
platform = eTrace?.firstOrNull()?.payload?.platform ?: gameEntity?.platform,
|
||||
downloadType = gameEntity?.downloadType,
|
||||
downloadCompleteType = gameEntity?.downloadCompleteType,
|
||||
displayType = eTrace?.firstOrNull()?.payload?.displayType
|
||||
?: gameEntity?.displayContent,
|
||||
isPlatformRecommend = gameEntity?.isPlatformRecommend,
|
||||
// ugly
|
||||
welcomeDialogId = gameEntity?.welcomeDialogId
|
||||
?: eTrace?.firstOrNull()?.payload?.welcomeDialogId,
|
||||
welcomeDialogLinkTitle = gameEntity?.welcomeDialogTitle
|
||||
?: eTrace?.firstOrNull()?.payload?.welcomeDialogLinkTitle
|
||||
)
|
||||
this.id = UUID.randomUUID().toString()
|
||||
this.timeInMillisecond = System.currentTimeMillis()
|
||||
this.time = TimeUtil.currentTime()
|
||||
this.source = source
|
||||
this.eTrace = eTrace
|
||||
this.event = event
|
||||
this.also {
|
||||
it.payload.categoryId = eTrace?.firstOrNull()?.payload?.categoryId
|
||||
it.payload.categoryV2Id = eTrace?.firstOrNull()?.payload?.categoryV2Id
|
||||
it.payload.testServerId = eTrace?.firstOrNull()?.payload?.testServerId
|
||||
it.payload.blockId = eTrace?.firstOrNull()?.payload?.blockId
|
||||
|
||||
it.payload.setContainerInfo(
|
||||
eTrace?.firstOrNull()?.payload?.containerId ?: gameEntity?.containerId,
|
||||
eTrace?.firstOrNull()?.payload?.containerType ?: gameEntity?.containerType
|
||||
)
|
||||
|
||||
it.payload.sourcePage = eTrace?.firstOrNull()?.payload?.sourcePage
|
||||
it.payload.sourcePageId = eTrace?.firstOrNull()?.payload?.sourcePageId
|
||||
it.payload.sourcePageName = eTrace?.firstOrNull()?.payload?.sourcePageName
|
||||
gameEntity?.exposureEvent = it
|
||||
}
|
||||
}
|
||||
|
||||
fun recycle() {
|
||||
if (inUse()) {
|
||||
Utils.log(
|
||||
EXPOSURE_EVENT_LOG_TAG,
|
||||
"This ExposureEvent $this cannot be recycled because it is still in use."
|
||||
)
|
||||
return
|
||||
}
|
||||
recycleUnchecked()
|
||||
}
|
||||
|
||||
private fun recycleUnchecked() {
|
||||
this.flags = FLAG_IN_USE
|
||||
synchronized(sPoolSync) {
|
||||
if (sPoolSize < EXPOSURE_EVENT_MAX_POOL_SIZE) {
|
||||
next = sPool
|
||||
sPool = this
|
||||
sPoolSize++
|
||||
Utils.log(EXPOSURE_EVENT_LOG_TAG, "This ExposureEvent $this Recycled")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun inUse(): Boolean {
|
||||
return flags == FLAG_IN_USE
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val sPoolSync = Any()
|
||||
private var sPool: ExposureEvent? = null
|
||||
private var sPoolSize: Int = 0
|
||||
|
||||
private const val EXPOSURE_EVENT_MAX_POOL_SIZE: Int = 300
|
||||
private const val FLAG_IN_USE = 1
|
||||
private const val EXPOSURE_EVENT_LOG_TAG = "ExposureEvent"
|
||||
|
||||
// TODO 建一个 exposureEvent 池规避反复生成对象
|
||||
@JvmStatic
|
||||
fun createEvent(gameEntity: GameEntity?,
|
||||
source: List<ExposureSource>,
|
||||
eTrace: List<ExposureEvent>? = null,
|
||||
event: ExposureType = ExposureType.EXPOSURE): ExposureEvent {
|
||||
fun createEvent(
|
||||
gameEntity: GameEntity?,
|
||||
source: List<ExposureSource>,
|
||||
eTrace: List<ExposureEvent>? = null,
|
||||
event: ExposureType = ExposureType.EXPOSURE
|
||||
): ExposureEvent {
|
||||
if (gameEntity?.getApk()?.size == 1) {
|
||||
gameEntity.gameVersion = gameEntity.getApk().elementAtOrNull(0)?.version ?: ""
|
||||
}
|
||||
return ExposureEvent(
|
||||
payload = ExposureEntity(
|
||||
gameId = gameEntity?.id?.getFirstElementDividedByDivider(DownloadEntity.GAME_ID_DIVIDER),
|
||||
gameName = eTrace?.firstOrNull()?.payload?.gameName ?: gameEntity?.name?.removeSuffix(Constants.GAME_NAME_DECORATOR),
|
||||
gameVersion = eTrace?.firstOrNull()?.payload?.gameVersion ?:gameEntity?.gameVersion,
|
||||
isMirrorData = eTrace?.firstOrNull()?.payload?.isMirrorData ?: gameEntity?.shouldUseMirrorInfo() ?: false,
|
||||
isWebDownload = BrowserInstallHelper.isUseBrowserToInstallEnabled() && BrowserInstallHelper.shouldUseBrowserToInstall(), // 实时的值,不用从 eTrace 里取
|
||||
sequence = eTrace?.firstOrNull()?.payload?.sequence ?: gameEntity?.sequence,
|
||||
outerSequence = eTrace?.firstOrNull()?.payload?.outerSequence ?: gameEntity?.outerSequence,
|
||||
platform = eTrace?.firstOrNull()?.payload?.platform ?:gameEntity?.platform,
|
||||
downloadType = gameEntity?.downloadType,
|
||||
downloadCompleteType = gameEntity?.downloadCompleteType,
|
||||
displayType = eTrace?.firstOrNull()?.payload?.displayType ?:gameEntity?.displayContent,
|
||||
isPlatformRecommend = gameEntity?.isPlatformRecommend ?: false,
|
||||
// ugly
|
||||
welcomeDialogId = gameEntity?.welcomeDialogId ?: eTrace?.firstOrNull()?.payload?.welcomeDialogId,
|
||||
welcomeDialogLinkTitle = gameEntity?.welcomeDialogTitle ?: eTrace?.firstOrNull()?.payload?.welcomeDialogLinkTitle),
|
||||
source = source,
|
||||
eTrace = eTrace,
|
||||
event = event).apply { gameEntity?.exposureEvent = this }
|
||||
synchronized(sPoolSync) {
|
||||
if (sPool != null) {
|
||||
val exposureEvent = sPool
|
||||
sPool = exposureEvent?.next
|
||||
exposureEvent?.next = null
|
||||
exposureEvent?.flags = 0
|
||||
sPoolSize--
|
||||
exposureEvent?.initExposureEventData(gameEntity, source, eTrace, event)
|
||||
Utils.log(
|
||||
EXPOSURE_EVENT_LOG_TAG,
|
||||
"ExposureEvent 对象 $this 正在被循环使用, 当前对象池数量还有 $sPoolSize"
|
||||
)
|
||||
return exposureEvent!!
|
||||
}
|
||||
}
|
||||
Utils.log(
|
||||
EXPOSURE_EVENT_LOG_TAG,
|
||||
"new ExposureEvent 对象"
|
||||
)
|
||||
val exposureEvent = ExposureEvent(
|
||||
payload = ExposureEntity(),
|
||||
source = source,
|
||||
eTrace = eTrace,
|
||||
event = event
|
||||
)
|
||||
exposureEvent.initExposureEventData(gameEntity, source, eTrace, event)
|
||||
return exposureEvent
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun createEventWithSourceConcat(gameEntity: GameEntity?,
|
||||
basicSource: List<ExposureSource>,
|
||||
source: List<ExposureSource>,
|
||||
eTrace: List<ExposureEvent>? = null,
|
||||
event: ExposureType = ExposureType.EXPOSURE): ExposureEvent {
|
||||
fun createEventWithSourceConcat(
|
||||
gameEntity: GameEntity?,
|
||||
basicSource: List<ExposureSource>,
|
||||
source: List<ExposureSource>,
|
||||
eTrace: List<ExposureEvent>? = null,
|
||||
event: ExposureType = ExposureType.EXPOSURE
|
||||
): ExposureEvent {
|
||||
val concatSourceList = ArrayList<ExposureSource>().apply {
|
||||
addAll(basicSource)
|
||||
addAll(source)
|
||||
|
||||
@ -1,18 +0,0 @@
|
||||
package com.gh.common.exposure
|
||||
|
||||
import androidx.room.*
|
||||
|
||||
@Dao
|
||||
interface ExposureEventDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insertMany(eventList: List<ExposureEvent>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insert(event: ExposureEvent)
|
||||
|
||||
@Query("SELECT * FROM exposureEvent")
|
||||
fun getAll(): List<ExposureEvent>
|
||||
|
||||
@Delete
|
||||
fun deleteMany(eventList: List<ExposureEvent>)
|
||||
}
|
||||
@ -11,22 +11,32 @@ import io.reactivex.functions.Consumer
|
||||
*/
|
||||
class ExposureListener(var fragment: Fragment, var exposable: IExposable) : RecyclerView.OnScrollListener() {
|
||||
|
||||
val throttleBus: ExposureThrottleBus by lazy { ExposureThrottleBus(Consumer { commitExposure(it) }, Consumer(Throwable::printStackTrace)) }
|
||||
val throttleBus: ExposureThrottleBus by lazy {
|
||||
ExposureThrottleBus(
|
||||
Consumer { commitExposure(it) },
|
||||
Consumer(Throwable::printStackTrace)
|
||||
)
|
||||
}
|
||||
var layoutManager: LinearLayoutManager? = null
|
||||
var visibleState: ExposureThrottleBus.VisibleState? = null
|
||||
|
||||
init {
|
||||
fragment.fragmentManager?.registerFragmentLifecycleCallbacks(
|
||||
object : FragmentManager.FragmentLifecycleCallbacks() {
|
||||
override fun onFragmentPaused(fm: FragmentManager, f: Fragment) {
|
||||
object : FragmentManager.FragmentLifecycleCallbacks() {
|
||||
override fun onFragmentPaused(fm: FragmentManager, f: Fragment) {
|
||||
if (fragment == f) {
|
||||
visibleState?.let { commitExposure(it) }
|
||||
throttleBus.clear()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFragmentViewDestroyed(fm: FragmentManager, f: Fragment) {
|
||||
override fun onFragmentViewDestroyed(fm: FragmentManager, f: Fragment) {
|
||||
if (fragment == f) {
|
||||
fragment.fragmentManager?.unregisterFragmentLifecycleCallbacks(this)
|
||||
}
|
||||
}, false)
|
||||
}
|
||||
}, false
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -39,7 +49,8 @@ class ExposureListener(var fragment: Fragment, var exposable: IExposable) : Recy
|
||||
if (layoutManager == null) layoutManager = recyclerView.layoutManager as LinearLayoutManager
|
||||
|
||||
layoutManager?.run {
|
||||
visibleState = ExposureThrottleBus.VisibleState(findFirstVisibleItemPosition(), findLastVisibleItemPosition())
|
||||
visibleState =
|
||||
ExposureThrottleBus.VisibleState(findFirstVisibleItemPosition(), findLastVisibleItemPosition())
|
||||
throttleBus.postVisibleState(visibleState!!)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
package com.gh.common.exposure
|
||||
|
||||
import com.aliyun.sls.android.producer.Log
|
||||
import com.gh.common.loghub.LoghubHelper
|
||||
import com.gh.common.util.toJson
|
||||
import com.gh.common.util.tryWithDefaultCatch
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.gh.gamecenter.common.loghub.LoghubHelper
|
||||
import com.gh.gamecenter.common.utils.FixedSizeLinkedHashSet
|
||||
import com.gh.gamecenter.common.utils.toJson
|
||||
import com.lightgame.utils.Utils
|
||||
import java.util.concurrent.ExecutorService
|
||||
|
||||
/**
|
||||
* A handful tool for committing logs to aliyun loghub.
|
||||
@ -25,40 +23,17 @@ object ExposureManager {
|
||||
|
||||
// exposureCache 用来过滤掉具有相同 id 的曝光事件,避免重复发送事件
|
||||
private val exposureSet by lazy { hashSetOf<ExposureEvent>() }
|
||||
private var exposureExecutor: ExecutorService? = null
|
||||
private val exposureCache by lazy { FixedSizeLinkedHashSet<String>(300) }
|
||||
private val exposureDao by lazy { ExposureDatabase.buildDatabase(HaloApp.getInstance().application).logHubEventDao() }
|
||||
|
||||
@JvmStatic
|
||||
fun init(excutor: ExecutorService) {
|
||||
exposureExecutor = excutor
|
||||
exposureExecutor?.execute {
|
||||
tryWithDefaultCatch {
|
||||
val eventList = exposureDao.getAll()
|
||||
exposureSet.addAll(eventList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a single exposure event.
|
||||
*/
|
||||
fun log(event: ExposureEvent) {
|
||||
exposureExecutor?.execute {
|
||||
try {
|
||||
if (!exposureCache.contains(event.id)) {
|
||||
// Catch `android.database.sqlite.SQLiteFullException: database or disk is full` exception.
|
||||
|
||||
exposureSet.add(event)
|
||||
exposureDao.insert(event)
|
||||
exposureCache.add(event.id)
|
||||
|
||||
} else {
|
||||
Utils.log("Exposure", "遇到重复曝光事件,自动过滤 (${event.id} - ${event.payload.gameName})")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
if (!exposureCache.contains(event.id)) {
|
||||
exposureSet.add(event)
|
||||
exposureCache.add(event.id)
|
||||
} else {
|
||||
Utils.log("Exposure", "遇到重复曝光事件,自动过滤 (${event.id} - ${event.payload.gameName})")
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,51 +41,37 @@ object ExposureManager {
|
||||
* Log a collection of exposure event.
|
||||
*/
|
||||
fun log(eventList: List<ExposureEvent>) {
|
||||
exposureExecutor?.execute {
|
||||
for (event in eventList) {
|
||||
try {
|
||||
if (!exposureCache.contains(event.id)) {
|
||||
// Catch `android.database.sqlite.SQLiteFullException: database or disk is full` exception.
|
||||
exposureSet.add(event)
|
||||
exposureDao.insert(event)
|
||||
exposureCache.add(event.id)
|
||||
} else {
|
||||
Utils.log("Exposure", "遇到重复曝光事件,自动过滤 (${event.id} - ${event.payload.gameName})")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
for (event in eventList) {
|
||||
if (!exposureCache.contains(event.id)) {
|
||||
exposureSet.add(event)
|
||||
exposureCache.add(event.id)
|
||||
} else {
|
||||
Utils.log("Exposure", "遇到重复曝光事件,自动过滤 (${event.id} - ${event.payload.gameName})")
|
||||
}
|
||||
commitSavedExposureEvents()
|
||||
}
|
||||
commitSavedExposureEvents()
|
||||
}
|
||||
|
||||
/**
|
||||
* @param forced Ignore all restrictions.
|
||||
* @param forcedUpload Ignore all restrictions.
|
||||
*/
|
||||
fun commitSavedExposureEvents(forced: Boolean = false) {
|
||||
exposureExecutor?.execute {
|
||||
tryWithDefaultCatch {
|
||||
// TODO 初始化 loghubHelper 去掉这个 tryCatch 块
|
||||
if (exposureSet.size < STORE_SIZE && !forced || exposureSet.size == 0) return@execute
|
||||
fun commitSavedExposureEvents(forcedUpload: Boolean = false) {
|
||||
if (exposureSet.size < STORE_SIZE && !forcedUpload || exposureSet.size == 0) return
|
||||
|
||||
val exposureList = exposureSet.toList()
|
||||
uploadExposures(exposureList)
|
||||
uploadExposures(exposureSet.toList(), forcedUpload)
|
||||
|
||||
Utils.log("Exposure", "提交了${exposureList.size}条曝光记录")
|
||||
exposureSet.removeAll(exposureList)
|
||||
exposureDao.deleteMany(exposureList)
|
||||
}
|
||||
}
|
||||
Utils.log("Exposure", "提交了${exposureSet.size}条曝光记录")
|
||||
exposureSet.clear()
|
||||
}
|
||||
|
||||
private fun eliminateMultipleBrackets(jsonWithMultipleBracket: String): String {
|
||||
return jsonWithMultipleBracket.replace("[[", "[").replace("]]", "]")
|
||||
}
|
||||
|
||||
private fun uploadExposures(eventList: List<ExposureEvent>) {
|
||||
private fun uploadExposures(eventList: List<ExposureEvent>, forced: Boolean) {
|
||||
eventList.forEach {
|
||||
LoghubHelper.uploadLog(buildLog(it), LOG_STORE)
|
||||
LoghubHelper.uploadLog(buildLog(it), LOG_STORE, forced)
|
||||
it.recycle()
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,25 +81,13 @@ object ExposureManager {
|
||||
putContent("event", event.event.toString())
|
||||
putContent("source", eliminateMultipleBrackets(event.source.toJson()))
|
||||
putContent("meta", event.meta.toJson())
|
||||
putContent("e-traces", if (event.eTrace != null) {
|
||||
eliminateMultipleBrackets(event.eTrace?.toJson() ?: "")
|
||||
} else "")
|
||||
putContent("real_millisecond", event.timeInMillisecond.toString())
|
||||
putContent(
|
||||
"e-traces", if (event.eTrace != null) {
|
||||
eliminateMultipleBrackets(event.eTrace?.toJson() ?: "")
|
||||
} else ""
|
||||
)
|
||||
logTime = event.time.toLong()
|
||||
}
|
||||
|
||||
class FixedSizeLinkedHashSet<T>(var maxSize: Int) : LinkedHashSet<T>() {
|
||||
override fun add(element: T): Boolean {
|
||||
if (size == maxSize) {
|
||||
pop()
|
||||
}
|
||||
return super.add(element);
|
||||
}
|
||||
|
||||
private fun pop() {
|
||||
if (size > 0) {
|
||||
remove(iterator().next())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -2,8 +2,8 @@ package com.gh.common.exposure
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.annotation.Keep
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Keep
|
||||
@Parcelize
|
||||
data class ExposureSource(var k: String, var v: String = ""): Parcelable
|
||||
data class ExposureSource(var k: String, var v: String = "") : Parcelable
|
||||
@ -23,10 +23,10 @@ class ExposureThrottleBus(var onSuccess: Consumer<VisibleState>, var onError: Co
|
||||
* throttleWithTimeout() to pass a visibleState event with a delay and drop current event if another event arrives before the timeout.
|
||||
*/
|
||||
val disposable = mPublishSubject
|
||||
.distinctUntilChanged()
|
||||
.throttleWithTimeout(THRESHOLD_TIME, TimeUnit.MILLISECONDS)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(onSuccess, onError)
|
||||
.distinctUntilChanged()
|
||||
.throttleWithTimeout(THRESHOLD_TIME, TimeUnit.MILLISECONDS)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(onSuccess, onError)
|
||||
mCompositeDisposable.add(disposable)
|
||||
}
|
||||
|
||||
|
||||
@ -3,21 +3,25 @@ package com.gh.common.exposure
|
||||
import android.text.TextUtils
|
||||
import com.g00fy2.versioncompare.Version
|
||||
import com.gh.common.util.PackageUtils
|
||||
import com.gh.common.util.toObject
|
||||
import com.gh.gamecenter.common.utils.FixedSizeLinkedHashSet
|
||||
import com.gh.gamecenter.common.utils.toObject
|
||||
import com.gh.gamecenter.entity.ApkEntity
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.manager.PackagesManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.download.DownloadEntity
|
||||
|
||||
object ExposureUtils {
|
||||
|
||||
private val mDownloadCompleteTraceEventIdSet = ExposureManager.FixedSizeLinkedHashSet<String>(3)
|
||||
private val mDownloadCompleteTraceEventIdSet = FixedSizeLinkedHashSet<String>(3)
|
||||
|
||||
@JvmStatic
|
||||
fun logADownloadExposureEvent(entity: GameEntity,
|
||||
platform: String?,
|
||||
traceEvent: ExposureEvent?,
|
||||
downloadType: DownloadType): ExposureEvent {
|
||||
fun logADownloadExposureEvent(
|
||||
entity: GameEntity,
|
||||
platform: String?,
|
||||
traceEvent: ExposureEvent?,
|
||||
downloadType: DownloadType
|
||||
): ExposureEvent {
|
||||
val gameEntity = entity.clone()
|
||||
gameEntity.id = if (entity.id.contains(DownloadEntity.GAME_ID_DIVIDER)) {
|
||||
entity.id.split(DownloadEntity.GAME_ID_DIVIDER).toTypedArray()[0]
|
||||
@ -25,13 +29,15 @@ object ExposureUtils {
|
||||
entity.id
|
||||
}
|
||||
gameEntity.gameVersion = entity.getApk().elementAtOrNull(0)?.version
|
||||
?: gameEntity.gameVersion
|
||||
?: gameEntity.gameVersion
|
||||
gameEntity.platform = platform
|
||||
gameEntity.downloadType = downloadType.toString()
|
||||
val exposureEvent = ExposureEvent.createEvent(gameEntity = gameEntity,
|
||||
source = traceEvent?.source ?: ArrayList(),
|
||||
eTrace = ExposureTraceUtils.appendTrace(traceEvent),
|
||||
event = ExposureType.DOWNLOAD)
|
||||
val exposureEvent = ExposureEvent.createEvent(
|
||||
gameEntity = gameEntity,
|
||||
source = traceEvent?.source ?: ArrayList(),
|
||||
eTrace = ExposureTraceUtils.appendTrace(traceEvent),
|
||||
event = ExposureType.DOWNLOAD
|
||||
)
|
||||
if (!TextUtils.isEmpty(entity.id)) {
|
||||
ExposureManager.log(exposureEvent)
|
||||
}
|
||||
@ -39,12 +45,14 @@ object ExposureUtils {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun logADownloadCompleteExposureEvent(entity: GameEntity,
|
||||
platform: String?,
|
||||
trace: String?,
|
||||
host: String? = "unknown",
|
||||
path: String? = "unknown",
|
||||
downloadType: DownloadType) {
|
||||
fun logADownloadCompleteExposureEvent(
|
||||
entity: GameEntity,
|
||||
platform: String?,
|
||||
trace: String?,
|
||||
host: String? = "unknown",
|
||||
path: String? = "unknown",
|
||||
downloadType: DownloadType
|
||||
) {
|
||||
val gameEntity = entity.clone()
|
||||
gameEntity.platform = platform
|
||||
gameEntity.downloadCompleteType = downloadType.toString()
|
||||
@ -59,46 +67,72 @@ object ExposureUtils {
|
||||
|
||||
traceEvent?.payload?.gameId?.let { mDownloadCompleteTraceEventIdSet.add(it) }
|
||||
|
||||
val exposureEvent = ExposureEvent.createEvent(gameEntity = gameEntity,
|
||||
source = traceEvent?.source ?: ArrayList(),
|
||||
eTrace = ExposureTraceUtils.appendTrace(traceEvent),
|
||||
event = ExposureType.DOWNLOAD_COMPLETE)
|
||||
val exposureEvent = ExposureEvent.createEvent(
|
||||
gameEntity = gameEntity,
|
||||
source = traceEvent?.source ?: ArrayList(),
|
||||
eTrace = ExposureTraceUtils.appendTrace(traceEvent),
|
||||
event = ExposureType.DOWNLOAD_COMPLETE
|
||||
)
|
||||
exposureEvent.payload.host = host
|
||||
exposureEvent.payload.path = path
|
||||
ExposureManager.log(exposureEvent)
|
||||
ExposureManager.commitSavedExposureEvents(forced = true)
|
||||
ExposureManager.commitSavedExposureEvents(forcedUpload = true)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getDownloadType(apkEntity: ApkEntity, gameId: String): DownloadType {
|
||||
return if (PackageUtils.isInstalled(HaloApp.getInstance().application, apkEntity.packageName)) {
|
||||
if (PackageUtils.isSignedByGh(HaloApp.getInstance().application, apkEntity.packageName)) {
|
||||
if (PackageUtils.isCanUpdate(apkEntity, gameId)) {
|
||||
DownloadType.PLUGIN_UPDATE
|
||||
} else {
|
||||
if (Version(apkEntity.version).isHigherThan(PackageUtils.getVersionByPackage(apkEntity.packageName))) {
|
||||
DownloadType.UPDATE
|
||||
} else {
|
||||
DownloadType.DOWNLOAD
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!TextUtils.isEmpty(apkEntity.ghVersion)) {
|
||||
DownloadType.PLUGIN_DOWNLOAD
|
||||
} else {
|
||||
DownloadType.UPDATE
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DownloadType.DOWNLOAD
|
||||
fun getDownloadType(apkEntity: ApkEntity, gameId: String, isVGame: Boolean): DownloadType {
|
||||
return when {
|
||||
isVGame -> getVGameDownloadType(apkEntity, gameId)
|
||||
PackageUtils.isInstalled(
|
||||
HaloApp.getInstance().application,
|
||||
apkEntity.packageName
|
||||
) -> getInstallDownloadType(apkEntity, gameId)
|
||||
else -> DownloadType.DOWNLOAD
|
||||
}
|
||||
}
|
||||
|
||||
private fun getVGameDownloadType(apkEntity: ApkEntity, gameId: String): DownloadType {
|
||||
return when {
|
||||
PackagesManager.isCanUpdate(gameId, apkEntity.packageName) -> DownloadType.FUN_UPDATE
|
||||
else -> DownloadType.FUN_DOWNLOAD
|
||||
}
|
||||
}
|
||||
|
||||
private fun getInstallDownloadType(apkEntity: ApkEntity, gameId: String): DownloadType {
|
||||
return when {
|
||||
PackageUtils.isSignedByGh(
|
||||
HaloApp.getInstance().application,
|
||||
apkEntity.packageName
|
||||
) -> getUpdateDownloadType(apkEntity, gameId)
|
||||
!TextUtils.isEmpty(apkEntity.ghVersion) -> DownloadType.PLUGIN_DOWNLOAD
|
||||
else -> DownloadType.UPDATE
|
||||
}
|
||||
}
|
||||
|
||||
private fun getUpdateDownloadType(apkEntity: ApkEntity, gameId: String): DownloadType {
|
||||
return when {
|
||||
PackageUtils.isCanUpdate(apkEntity, gameId) -> DownloadType.PLUGIN_UPDATE
|
||||
Version(apkEntity.version).isHigherThan(PackageUtils.getVersionNameByPackageName(apkEntity.packageName)) -> DownloadType.UPDATE
|
||||
else -> DownloadType.DOWNLOAD
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 为游戏实体添加位置序号和上层专题 id (若存在)
|
||||
*/
|
||||
@JvmStatic
|
||||
fun updateExposureSequence(gameList: List<GameEntity>?) {
|
||||
fun updateExposureInfo(
|
||||
gameList: List<GameEntity>?,
|
||||
subjectId: String? = null,
|
||||
containerId: String? = null,
|
||||
containerType: String? = null
|
||||
) {
|
||||
gameList?.let {
|
||||
for ((index, game) in it.withIndex()) {
|
||||
game.sequence = index
|
||||
game.subjectId = subjectId
|
||||
game.containerId = containerId
|
||||
game.containerType = containerType
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -110,6 +144,10 @@ object ExposureUtils {
|
||||
|
||||
PLUGIN_UPDATE,
|
||||
|
||||
PLUGIN_DOWNLOAD
|
||||
PLUGIN_DOWNLOAD,
|
||||
|
||||
FUN_DOWNLOAD,
|
||||
|
||||
FUN_UPDATE
|
||||
}
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
package com.gh.common.exposure.meta
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.annotation.Keep
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
|
||||
@Keep
|
||||
@Parcelize
|
||||
data class Meta(
|
||||
val mac: String? = "",
|
||||
val jnfj: String? = "",
|
||||
val model: String? = "",
|
||||
val manufacturer: String? = "",
|
||||
val dia: String? = "",
|
||||
val android_sdk: Int? = -1,
|
||||
val android_version: String? = "",
|
||||
val network: String? = "",
|
||||
val os: String? = "",
|
||||
val gid: String? = "",
|
||||
val oaid: String? = "",
|
||||
val channel: String? = "",
|
||||
val appVersion: String? = "",
|
||||
val userId: String? = "",
|
||||
val exposureVersion: String? = "",
|
||||
val rom: String? = ""
|
||||
) : Parcelable
|
||||
@ -1,242 +0,0 @@
|
||||
package com.gh.common.exposure.meta
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.ConnectivityManager
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import android.telephony.TelephonyManager
|
||||
import android.text.TextUtils
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.util.SPUtils
|
||||
import com.gh.common.util.tryWithDefaultCatch
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.leon.channel.helper.ChannelReaderUtil
|
||||
import com.walkud.rom.checker.RomIdentifier
|
||||
|
||||
object MetaUtil {
|
||||
|
||||
private val application: Application = HaloApp.getInstance().application
|
||||
private var channel = ""
|
||||
|
||||
private var m: Meta? = null
|
||||
private var imei: String? = null
|
||||
private var base64EncodedImei: String? = null
|
||||
private var androidId: String? = null
|
||||
private var base64EncodedAndroidId: String? = null
|
||||
|
||||
private var romName: String? = null
|
||||
private var romVersion: String? = null
|
||||
|
||||
fun refreshMeta() {
|
||||
|
||||
if (romName == null) {
|
||||
tryWithDefaultCatch {
|
||||
romName = RomIdentifier.getRom().name
|
||||
romVersion = RomIdentifier.getRom().versionName
|
||||
}
|
||||
}
|
||||
|
||||
m = Meta(mac = "",
|
||||
jnfj = getBase64EncodedIMEI(),
|
||||
model = getModel(),
|
||||
manufacturer = getManufacturer(),
|
||||
dia = getBase64EncodedAndroidId(),
|
||||
android_sdk = getAndroidSDK(),
|
||||
android_version = getAndroidVersion(),
|
||||
network = getNetwork(),
|
||||
os = getOS(),
|
||||
gid = HaloApp.getInstance().gid,
|
||||
oaid = HaloApp.getInstance().oaid,
|
||||
channel = getChannel(),
|
||||
appVersion = BuildConfig.VERSION_NAME,
|
||||
userId = UserManager.getInstance().userId,
|
||||
exposureVersion = BuildConfig.EXPOSURE_VERSION,
|
||||
rom = romName + "" + romVersion)
|
||||
}
|
||||
|
||||
fun getMeta(): Meta {
|
||||
if (m == null) {
|
||||
refreshMeta()
|
||||
}
|
||||
return m!!
|
||||
}
|
||||
|
||||
private fun getChannel(): String? {
|
||||
if (TextUtils.isEmpty(channel)) {
|
||||
channel = if (ChannelReaderUtil.getChannel(application) != null) ChannelReaderUtil.getChannel(application) else ""
|
||||
}
|
||||
return channel
|
||||
}
|
||||
|
||||
/**
|
||||
* Get IMEI
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getIMEI(): String {
|
||||
|
||||
if (!HaloApp.isUserAcceptPrivacyPolicy(HaloApp.getInstance().application)) {
|
||||
return ""
|
||||
}
|
||||
|
||||
if (imei != null) {
|
||||
return imei ?: ""
|
||||
}
|
||||
|
||||
imei = SPUtils.getString(Constants.SP_IMEI)
|
||||
|
||||
if (!TextUtils.isEmpty(imei)) {
|
||||
return imei ?: ""
|
||||
}
|
||||
|
||||
if (application.checkCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
|
||||
return ""
|
||||
}
|
||||
|
||||
val telephonyManager = application.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 29) {
|
||||
return "".apply {
|
||||
imei = this
|
||||
SPUtils.setString(Constants.SP_IMEI, this)
|
||||
}
|
||||
} else if (Build.VERSION.SDK_INT >= 26) {
|
||||
return (telephonyManager.imei ?: "").apply {
|
||||
imei = this
|
||||
SPUtils.setString(Constants.SP_IMEI, this)
|
||||
}
|
||||
}
|
||||
|
||||
return (telephonyManager.getDeviceId() ?: "").apply {
|
||||
imei = this
|
||||
SPUtils.setString(Constants.SP_IMEI, this)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getBase64EncodedIMEI(): String {
|
||||
if (imei == null) {
|
||||
getIMEI()
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(base64EncodedImei) && imei != null) {
|
||||
try {
|
||||
base64EncodedImei = android.util.Base64.encodeToString(getIMEI().trim().toByteArray(), android.util.Base64.NO_WRAP)
|
||||
} catch (e: java.lang.Exception) {
|
||||
e.printStackTrace()
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
return base64EncodedImei ?: ""
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getBase64EncodedAndroidId(): String {
|
||||
if (androidId == null) {
|
||||
getAndroidId()
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(base64EncodedAndroidId) && androidId != null) {
|
||||
try {
|
||||
base64EncodedAndroidId = android.util.Base64.encodeToString(getAndroidId().trim().toByteArray(), android.util.Base64.NO_WRAP)
|
||||
} catch (e: java.lang.Exception) {
|
||||
e.printStackTrace()
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
return base64EncodedAndroidId ?: ""
|
||||
}
|
||||
|
||||
fun getModel(): String? {
|
||||
return Build.MODEL
|
||||
}
|
||||
|
||||
fun getManufacturer(): String? {
|
||||
return Build.MANUFACTURER
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getAndroidId(): String {
|
||||
|
||||
if (!HaloApp.isUserAcceptPrivacyPolicy(HaloApp.getInstance().application)) {
|
||||
return ""
|
||||
}
|
||||
|
||||
if (androidId != null) {
|
||||
return androidId ?: ""
|
||||
}
|
||||
|
||||
androidId = SPUtils.getString(Constants.SP_ANDROID_ID)
|
||||
|
||||
if (!TextUtils.isEmpty(androidId)) {
|
||||
return androidId ?: ""
|
||||
}
|
||||
|
||||
return try {
|
||||
Settings.Secure.getString(application.contentResolver, Settings.Secure.ANDROID_ID).apply {
|
||||
androidId = this
|
||||
SPUtils.setString(Constants.SP_ANDROID_ID, this)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
androidId = ""
|
||||
SPUtils.setString(Constants.SP_ANDROID_ID, "")
|
||||
""
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun getAndroidSDK(): Int? {
|
||||
return Build.VERSION.SDK_INT
|
||||
}
|
||||
|
||||
fun getAndroidVersion(): String? {
|
||||
return Build.VERSION.RELEASE
|
||||
}
|
||||
|
||||
fun getNetwork(): String? {
|
||||
|
||||
if (application.checkCallingOrSelfPermission(Manifest.permission.ACCESS_NETWORK_STATE) != PackageManager.PERMISSION_GRANTED)
|
||||
return "unknown"
|
||||
|
||||
val activeNetwork = (application.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).activeNetworkInfo
|
||||
?: return "unknown"
|
||||
|
||||
return when (activeNetwork.type) {
|
||||
ConnectivityManager.TYPE_WIFI -> "Wifi"
|
||||
ConnectivityManager.TYPE_WIMAX -> "WifiMax"
|
||||
ConnectivityManager.TYPE_MOBILE -> {
|
||||
val telephonyManager = application.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
|
||||
if (telephonyManager.simState != TelephonyManager.SIM_STATE_READY) return "unknown"
|
||||
when (telephonyManager.networkType) {
|
||||
// Unknown
|
||||
TelephonyManager.NETWORK_TYPE_UNKNOWN -> "Cellular - Unknown"
|
||||
// Cellular Data–2G
|
||||
TelephonyManager.NETWORK_TYPE_EDGE, TelephonyManager.NETWORK_TYPE_GPRS, TelephonyManager.NETWORK_TYPE_CDMA,
|
||||
TelephonyManager.NETWORK_TYPE_IDEN, TelephonyManager.NETWORK_TYPE_1xRTT -> "Cellular - 2G"
|
||||
// Cellular Data–3G
|
||||
TelephonyManager.NETWORK_TYPE_UMTS, TelephonyManager.NETWORK_TYPE_HSDPA, TelephonyManager.NETWORK_TYPE_HSPA,
|
||||
TelephonyManager.NETWORK_TYPE_HSPAP, TelephonyManager.NETWORK_TYPE_HSUPA, TelephonyManager.NETWORK_TYPE_EVDO_0,
|
||||
TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyManager.NETWORK_TYPE_EVDO_B -> "Cellular - 3G"
|
||||
// Cellular Data–4G
|
||||
TelephonyManager.NETWORK_TYPE_LTE -> "Cellular - 4G"
|
||||
else -> "Cellular - Unknown Generation"
|
||||
}
|
||||
|
||||
}
|
||||
else -> "unknown"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun getOS(): String {
|
||||
return "android"
|
||||
}
|
||||
}
|
||||
@ -5,17 +5,46 @@ import com.google.gson.annotations.SerializedName
|
||||
|
||||
@Keep
|
||||
data class RegionSetting(
|
||||
@SerializedName("game_mirror")
|
||||
var mirrorGameIdSet: HashSet<String>,
|
||||
@SerializedName("game_block")
|
||||
var filterGameIdSet: HashSet<String>,
|
||||
@SerializedName("channel_control")
|
||||
var channelControl: ChannelControl) {
|
||||
@SerializedName("game_mirror")
|
||||
var mirrorGameIdSet: HashSet<String>,
|
||||
@SerializedName("game_block")
|
||||
var filterGameIdSet: HashSet<String>,
|
||||
@SerializedName("channel_control")
|
||||
var channelControl: ChannelControl,
|
||||
@SerializedName("game_h5_download")
|
||||
var gameH5DownloadList: List<GameH5Download>,
|
||||
@SerializedName("game_special_download")
|
||||
var gameSpecialDownloadInfoList: List<GameSpecialDownloadInfo>
|
||||
) {
|
||||
|
||||
@Keep
|
||||
data class ChannelControl(
|
||||
@SerializedName("game_category")
|
||||
var gameCategory: String,
|
||||
@SerializedName("effect")
|
||||
var effect: Boolean)
|
||||
@SerializedName("game_category")
|
||||
var gameCategory: String,
|
||||
@SerializedName("effect")
|
||||
var effect: Boolean
|
||||
)
|
||||
|
||||
@Keep
|
||||
data class GameH5Download(
|
||||
@SerializedName("game_id")
|
||||
var gameId: String,// 游戏id
|
||||
@SerializedName("h5_link")
|
||||
var h5Link: String,// 网页链接
|
||||
@SerializedName("download_link")
|
||||
var downloadLink: String,// 下载链接
|
||||
@SerializedName("button_text")
|
||||
var buttonText: String,// 按钮文案
|
||||
)
|
||||
|
||||
data class GameSpecialDownloadInfo(
|
||||
@SerializedName("game_id")
|
||||
var gameId: String = "",
|
||||
@SerializedName("bbs_id")
|
||||
var bbsId: String = "",
|
||||
@SerializedName("top_id")
|
||||
var topId: String = "",
|
||||
@SerializedName("hint_text")
|
||||
var hintText: String = ""
|
||||
)
|
||||
}
|
||||
@ -1,17 +1,16 @@
|
||||
package com.gh.common.filter
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.util.SPUtils
|
||||
import com.gh.common.util.debounceActionWithInterval
|
||||
import com.gh.common.util.toJson
|
||||
import com.gh.common.util.toObject
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.common.utils.debounceActionWithInterval
|
||||
import com.gh.gamecenter.common.utils.toJson
|
||||
import com.gh.gamecenter.common.utils.toObject
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.functions.Function
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
||||
@ -20,6 +19,8 @@ object RegionSettingHelper {
|
||||
private var mChannelControl: RegionSetting.ChannelControl? = null
|
||||
private var mFilterGameIdSet: HashSet<String>? = hashSetOf()
|
||||
private var mDisplayMirrorIfoGameIdSet: HashSet<String>? = hashSetOf()
|
||||
private var mGameH5DownloadList: List<RegionSetting.GameH5Download>? = listOf()
|
||||
private var mGameSpecialDownloadInfoList: List<RegionSetting.GameSpecialDownloadInfo>? = listOf()
|
||||
|
||||
private const val SP_SETTING = "region_setting"
|
||||
|
||||
@ -32,6 +33,12 @@ object RegionSettingHelper {
|
||||
return mFilterGameIdSet?.contains(gameId) ?: false
|
||||
}
|
||||
|
||||
fun shouldThisGameShowSpecialDownload(gameId: String) =
|
||||
mGameSpecialDownloadInfoList?.any { it.gameId == gameId } ?: false
|
||||
|
||||
@JvmStatic
|
||||
fun getGameSpecialDownloadInfo(gameId: String) = mGameSpecialDownloadInfoList?.find { it.gameId == gameId }
|
||||
|
||||
@JvmStatic
|
||||
fun filterGame(list: List<GameEntity>?): ArrayList<GameEntity> {
|
||||
if (list == null) return arrayListOf()
|
||||
@ -59,28 +66,33 @@ object RegionSettingHelper {
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getGameH5DownloadByGameId(gameId: String): RegionSetting.GameH5Download? {
|
||||
if (mGameH5DownloadList.isNullOrEmpty()) return null
|
||||
return mGameH5DownloadList!!.find { it.gameId == gameId }
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
@JvmStatic
|
||||
fun getRegionSetting() {
|
||||
debounceActionWithInterval(R.string.app_name, 3000) {
|
||||
debounceActionWithInterval(R.string.app_name, 5000) {
|
||||
// 使用默认的 Schdulers.io() 可能会触发 OOM
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application)
|
||||
.sensitiveApi
|
||||
.getRegionSetting(HaloApp.getInstance().channel)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BiResponse<RegionSetting>() {
|
||||
override fun onSuccess(data: RegionSetting) {
|
||||
updateSettingsInMemory(data)
|
||||
SPUtils.setString(SP_SETTING, data.toJson())
|
||||
}
|
||||
RetrofitManager.getInstance()
|
||||
.api
|
||||
.getRegionSetting(HaloApp.getInstance().channel)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(object : BiResponse<RegionSetting>() {
|
||||
override fun onSuccess(data: RegionSetting) {
|
||||
updateSettingsInMemory(data)
|
||||
SPUtils.setString(SP_SETTING, data.toJson())
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
SPUtils.getString(SP_SETTING)?.toObject<RegionSetting>()?.let {
|
||||
updateSettingsInMemory(it)
|
||||
}
|
||||
override fun onFailure(exception: Exception) {
|
||||
SPUtils.getString(SP_SETTING)?.toObject<RegionSetting>()?.let {
|
||||
updateSettingsInMemory(it)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,6 +100,8 @@ object RegionSettingHelper {
|
||||
mFilterGameIdSet = data.filterGameIdSet
|
||||
mDisplayMirrorIfoGameIdSet = data.mirrorGameIdSet
|
||||
mChannelControl = data.channelControl
|
||||
mGameH5DownloadList = data.gameH5DownloadList
|
||||
mGameSpecialDownloadInfoList = data.gameSpecialDownloadInfoList
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -6,6 +6,7 @@ import androidx.room.RoomDatabase
|
||||
import androidx.room.TypeConverters
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import com.gh.gamecenter.entity.GamesCollectionEntity
|
||||
import com.gh.gamecenter.entity.HistoryGameEntity
|
||||
import com.gh.gamecenter.entity.MyVideoEntity
|
||||
import com.gh.gamecenter.entity.NewsEntity
|
||||
@ -15,18 +16,30 @@ import com.gh.gamecenter.room.converter.*
|
||||
import com.gh.gamecenter.room.dao.*
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
@Database(entities = [AnswerEntity::class, ArticleEntity::class, NewsEntity::class, HistoryGameEntity::class, MyVideoEntity::class], version = 8, exportSchema = false)
|
||||
@TypeConverters(CountConverter::class,
|
||||
CommunityConverter::class,
|
||||
TimeConverter::class,
|
||||
AnswerUserConverter::class,
|
||||
ThumbnailConverter::class,
|
||||
TagStyleListConverter::class,
|
||||
StringArrayListConverter::class,
|
||||
ListStringConverter::class,
|
||||
CommunityVideoConverter::class,
|
||||
UserConverter::class,
|
||||
ImageInfoConverter::class)
|
||||
@Database(
|
||||
entities = [AnswerEntity::class, ArticleEntity::class, NewsEntity::class, HistoryGameEntity::class, MyVideoEntity::class, GamesCollectionEntity::class],
|
||||
version = 11,
|
||||
exportSchema = false
|
||||
)
|
||||
@TypeConverters(
|
||||
CountConverter::class,
|
||||
CommunityConverter::class,
|
||||
TimeConverter::class,
|
||||
AnswerUserConverter::class,
|
||||
ThumbnailConverter::class,
|
||||
TagStyleListConverter::class,
|
||||
StringArrayListConverter::class,
|
||||
ListStringConverter::class,
|
||||
CommunityVideoConverter::class,
|
||||
UserConverter::class,
|
||||
ImageInfoConverter::class,
|
||||
VideoInfoConverter::class,
|
||||
QuestionsConverter::class,
|
||||
MeConverter::class,
|
||||
SimpleGameListConverter::class,
|
||||
TagInfoListConverter::class,
|
||||
ActivityLabelListConverter::class
|
||||
)
|
||||
|
||||
abstract class HistoryDatabase : RoomDatabase() {
|
||||
|
||||
@ -35,6 +48,7 @@ abstract class HistoryDatabase : RoomDatabase() {
|
||||
abstract fun newsDao(): NewsHistoryDao
|
||||
abstract fun gameDao(): GameDao
|
||||
abstract fun videoHistoryDao(): VideoHistoryDao
|
||||
abstract fun gamesCollectionDao(): GamesCollectionDao
|
||||
|
||||
companion object {
|
||||
|
||||
@ -79,15 +93,56 @@ abstract class HistoryDatabase : RoomDatabase() {
|
||||
}
|
||||
}
|
||||
|
||||
val MIGRATION_8_9: Migration = object : Migration(8, 9) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("Alter TABLE ArticleEntity add des TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE ArticleEntity add url TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE ArticleEntity add videoInfo TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE ArticleEntity add poster TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE ArticleEntity add length INTEGER NOT NULL DEFAULT 0")
|
||||
database.execSQL("Alter TABLE ArticleEntity add status TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE ArticleEntity add content TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE ArticleEntity add questions TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE AnswerEntity add des TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE AnswerEntity add url TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE AnswerEntity add videoInfo TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE AnswerEntity add poster TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE AnswerEntity add length INTEGER NOT NULL DEFAULT 0")
|
||||
database.execSQL("Alter TABLE AnswerEntity add status TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE AnswerEntity add content TEXT NOT NULL DEFAULT ''")
|
||||
}
|
||||
}
|
||||
|
||||
val MIGRATION_9_10: Migration = object : Migration(9, 10) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL(
|
||||
"CREATE TABLE GamesCollectionEntity (id TEXT NOT NULL PRIMARY KEY, tags TEXT, games TEXT, title TEXT NOT NULL, intro TEXT NOT NULL, cover TEXT NOT NULL, display TEXT NOT NULL, stamp TEXT NOT NULL, count TEXT, user TEXT, me TEXT, orderTag INTEGER NOT NULL)"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val MIGRATION_10_11: Migration = object : Migration(10, 11) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("Alter TABLE GamesCollectionEntity add activityTags TEXT DEFAULT ''")
|
||||
}
|
||||
}
|
||||
|
||||
val instance by lazy {
|
||||
Room.databaseBuilder(HaloApp.getInstance().application, HistoryDatabase::class.java, "USER_TRACK_HISTORY_DATABASE")
|
||||
.addMigrations(MIGRATION_2_3)
|
||||
.addMigrations(MIGRATION_3_4)
|
||||
.addMigrations(MIGRATION_4_5)
|
||||
.addMigrations(MIGRATION_5_6)
|
||||
.addMigrations(MIGRATION_6_7)
|
||||
.addMigrations(MIGRATION_7_8)
|
||||
.build()
|
||||
Room.databaseBuilder(
|
||||
HaloApp.getInstance().application,
|
||||
HistoryDatabase::class.java,
|
||||
"USER_TRACK_HISTORY_DATABASE"
|
||||
)
|
||||
.addMigrations(MIGRATION_2_3)
|
||||
.addMigrations(MIGRATION_3_4)
|
||||
.addMigrations(MIGRATION_4_5)
|
||||
.addMigrations(MIGRATION_5_6)
|
||||
.addMigrations(MIGRATION_6_7)
|
||||
.addMigrations(MIGRATION_7_8)
|
||||
.addMigrations(MIGRATION_8_9)
|
||||
.addMigrations(MIGRATION_9_10)
|
||||
.addMigrations(MIGRATION_10_11)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user