Compare commits
2998 Commits
v3.0
...
v3.7.2-fix
| Author | SHA1 | Date | |
|---|---|---|---|
| 6281b4f510 | |||
| 2cbc0b0e17 | |||
| f18a0ef72c | |||
| 98fb4fc412 | |||
| 73c995c31f | |||
| 60dcafe0c1 | |||
| c118d7e4ad | |||
| babc55739b | |||
| df8790c6ff | |||
| 30ccdcd750 | |||
| 79d23bb203 | |||
| b2c5e6551b | |||
| ec49d7f20a | |||
| 5a35d13d70 | |||
| dcfa4fdaaf | |||
| 43324ca44e | |||
| 8e778e8172 | |||
| 928a98831e | |||
| 3dc678bc27 | |||
| d2b19a128d | |||
| cc75cb497d | |||
| 4840c5c604 | |||
| 347cfdb72d | |||
| 06ec87ba6d | |||
| 1206800a3d | |||
| d4763468c1 | |||
| 9c1a186a28 | |||
| bd9b914c18 | |||
| d40a57bcaa | |||
| 1892758288 | |||
| ca2e26756a | |||
| ed5696f4bd | |||
| cee34e7d76 | |||
| 54decbade3 | |||
| 11167670f8 | |||
| 37c7629cf0 | |||
| 947236f85d | |||
| eafa13ec76 | |||
| 7258812537 | |||
| e0a82f5050 | |||
| e0e7cbd2a3 | |||
| 554ec20493 | |||
| 31c3ed3bc5 | |||
| 466b690ac0 | |||
| 0420557f47 | |||
| c0edbf1a57 | |||
| 374610dbc0 | |||
| 080ac5f1d5 | |||
| 9dc967087d | |||
| 80a238253d | |||
| d7b7f11ebf | |||
| 9abb14e37f | |||
| 5fbb93cbee | |||
| 20b75ff046 | |||
| 73374017a5 | |||
| 73c3d5cd4d | |||
| 01a02a000f | |||
| 8998f1323f | |||
| bb77cf4624 | |||
| 772705ed0f | |||
| 6e2f568ad3 | |||
| df20c8235e | |||
| 4882cc5203 | |||
| 4fa6a41681 | |||
| f77e9d4949 | |||
| 1bc167fe7b | |||
| 98213ad3ee | |||
| 0b101d693d | |||
| 8655822d88 | |||
| 386923d16e | |||
| 013536b147 | |||
| 880eef90fb | |||
| 61e3784991 | |||
| 0664d92e62 | |||
| aab99b0c29 | |||
| 2e6ca9c524 | |||
| 0a402e4e92 | |||
| 7e75cd7859 | |||
| e3522d4160 | |||
| c9d0b813b6 | |||
| 3a7e28fac2 | |||
| 9aca24c02b | |||
| 9c818e1470 | |||
| 614ed0e7e2 | |||
| 55b1d43e73 | |||
| 25526f3666 | |||
| 773f2e798d | |||
| 58b5ec4eb9 | |||
| 007cef39a7 | |||
| ba1a702ea1 | |||
| 56d8b58f72 | |||
| f53c8377e6 | |||
| cfb1d86e8e | |||
| 8f0caa0949 | |||
| 8ef13cb4ff | |||
| e6d4f60d4f | |||
| e67f85c084 | |||
| 5318693650 | |||
| 3bf242b145 | |||
| 0ba82a334e | |||
| 0a385bb720 | |||
| 7658fd2a4f | |||
| e40e655bfa | |||
| cfa000bf88 | |||
| 12c35cebc4 | |||
| 92089e60ce | |||
| 141a6df8ab | |||
| 7719e9763d | |||
| 8d3307986d | |||
| d0b7ec39a7 | |||
| cfd198b4ab | |||
| a557c12c6d | |||
| 6b777d4ec8 | |||
| 882dd95190 | |||
| 7764bd29c8 | |||
| 08730f1ce9 | |||
| f9c15d3427 | |||
| 8e8668036e | |||
| cc65eed48d | |||
| 29f4e547a1 | |||
| 419003ae23 | |||
| 0519872d81 | |||
| e9b52bb70b | |||
| 681ea201c3 | |||
| a5466bb6ad | |||
| 3a3998ae84 | |||
| 7e27502430 | |||
| 8956885f1c | |||
| caeb0a1362 | |||
| cc094889b8 | |||
| 839386c5f4 | |||
| 6c5de65278 | |||
| 3aadac942c | |||
| dca9b49d75 | |||
| 8e764dc22a | |||
| 383cf4941e | |||
| 05510a8588 | |||
| eb611a9ff1 | |||
| 15aa3713e6 | |||
| 7d11713c49 | |||
| 66ff610078 | |||
| f351761d9e | |||
| 6bb5e18253 | |||
| c44e8cffcc | |||
| 39d4c35504 | |||
| d42b57f385 | |||
| 2142a1676e | |||
| b0fa41bded | |||
| 28f552ca19 | |||
| da0b256054 | |||
| 8b477c357a | |||
| 650075488d | |||
| 8cff41defa | |||
| 6519eca511 | |||
| 85d8463972 | |||
| c762a7c755 | |||
| 142859fd39 | |||
| d7f84ff3c8 | |||
| 6c4545e364 | |||
| a3d9f12414 | |||
| 412d2ff9dc | |||
| 65f8440637 | |||
| f06359f5c3 | |||
| 433088116e | |||
| c93e55f306 | |||
| e613066ed3 | |||
| 9aabfde5b0 | |||
| 9f4c9431b9 | |||
| 74f64d9782 | |||
| d79b3f10e8 | |||
| b29d32c8f2 | |||
| b8ec93c6a1 | |||
| dad3c9aee7 | |||
| 833e0406f0 | |||
| 3d6b556dfd | |||
| ad0a5525f0 | |||
| a012c3e3de | |||
| 6c2d489940 | |||
| 0ea56b01eb | |||
| f65c226657 | |||
| 006b82381b | |||
| 059414b9f8 | |||
| 93c1105346 | |||
| 7ca92e8b7f | |||
| eeb7415086 | |||
| 9a288e8870 | |||
| 351fefd57b | |||
| 4915cdc3ba | |||
| 9d044a4001 | |||
| 8e465c17dd | |||
| fa73ac790c | |||
| 899f442f14 | |||
| 698af5d584 | |||
| 66dea77546 | |||
| eed2eed992 | |||
| 913c0027a6 | |||
| a7884325c8 | |||
| a7caa063ef | |||
| ee99895cba | |||
| cf7a14e80a | |||
| 07a64d118a | |||
| 72329d0222 | |||
| 16e85e9222 | |||
| dd11883eab | |||
| be70ce8551 | |||
| d428c46957 | |||
| 516b956269 | |||
| 8bb90f4d4c | |||
| 2f9e9fe976 | |||
| bf2271ac06 | |||
| f279564e02 | |||
| 386eafa0bc | |||
| 619b5a3cc3 | |||
| d0391c779d | |||
| fc9d3f2e91 | |||
| 42c7123d2d | |||
| 8e66f80360 | |||
| b80fab06ad | |||
| 943c359c22 | |||
| 8631045874 | |||
| 5991a90353 | |||
| 8534455344 | |||
| 1a21fceeb7 | |||
| 274739c885 | |||
| 5134fa19be | |||
| 7342e94bdc | |||
| 28bf579518 | |||
| 9e490ef349 | |||
| 548206792e | |||
| c87d7f9c28 | |||
| cfe1584fc3 | |||
| 137a95f5ab | |||
| 6ab8b24353 | |||
| 1515cc1ddd | |||
| abfd4834ef | |||
| 03032a0dbd | |||
| 75545a5929 | |||
| 1425a95bc8 | |||
| 23674a1c55 | |||
| caf0a8d5f5 | |||
| b11928528c | |||
| cf9bd70c6c | |||
| c6ab68e9b4 | |||
| 899da43682 | |||
| 1825f713b3 | |||
| 760bc9b63c | |||
| 4974c105bf | |||
| 9c910ce6de | |||
| fcd1c2d418 | |||
| 5c0c227c3b | |||
| a69669a7ca | |||
| 166e2e341a | |||
| 8cb689cc99 | |||
| 1dd5c5fd40 | |||
| 92719c538e | |||
| 3448dfddef | |||
| b190b31afa | |||
| 083a62ed9d | |||
| 5f0bfd1184 | |||
| 15bb7d654c | |||
| f42278b91f | |||
| aa23d515c6 | |||
| b3417749ed | |||
| 4c33977568 | |||
| 1ecd83b6af | |||
| b202302a7e | |||
| 7450edd177 | |||
| 4c7ab844e8 | |||
| fd6581671d | |||
| 71cc0962d3 | |||
| 9c70d802b5 | |||
| ed6bec0cfc | |||
| 36834cfec7 | |||
| 7dfaf45dc2 | |||
| 5efddb05b3 | |||
| f46122787c | |||
| 1b8cde1c91 | |||
| 1694603cd0 | |||
| 4243f37126 | |||
| 63e0b9887c | |||
| 201efd9628 | |||
| c7c29b7ca8 | |||
| 0b3fd3a123 | |||
| 99e988a0d9 | |||
| eaa3b81e31 | |||
| dbbf9a846e | |||
| af8b336434 | |||
| ce84c0f9c9 | |||
| 0f8d9cd5d3 | |||
| cb70e12632 | |||
| a5ad403614 | |||
| e674a8313a | |||
| 1cef4bb53d | |||
| 3851aeb790 | |||
| 7680e2e125 | |||
| f674aa4a79 | |||
| be1533a5df | |||
| eca3bdd4e5 | |||
| c885579516 | |||
| 341d849e29 | |||
| 2bb5c79c38 | |||
| fa26e1a17b | |||
| 8ed76089eb | |||
| 678418da0b | |||
| 1c11fc4469 | |||
| 78f277fd6d | |||
| 5520fd7122 | |||
| cb6ce2e14f | |||
| 80933e82eb | |||
| e32dce2ef9 | |||
| e252a9ebf8 | |||
| 08936a22c8 | |||
| 3fea57d05f | |||
| 52ae5fc451 | |||
| 045dea265d | |||
| 501282f243 | |||
| 998cf70723 | |||
| 1a10fcac71 | |||
| ee5862eddd | |||
| c1527ec37e | |||
| eb112b358e | |||
| b860ab912a | |||
| b14ee68882 | |||
| 44065fcb06 | |||
| ec5305b76f | |||
| ddfb651d6a | |||
| 8a828a3250 | |||
| 31f5795e27 | |||
| dbde817b59 | |||
| 83e251492d | |||
| 5fa22c7f5d | |||
| b4ad18c806 | |||
| 61eb35cf31 | |||
| 07e54d5b5e | |||
| e0c27f721c | |||
| d2bf6bb211 | |||
| e2681494db | |||
| ac1d078681 | |||
| 624d9c1e2d | |||
| 892cc3cdde | |||
| fd7b9263bf | |||
| a9428ddb3b | |||
| 319f526e0f | |||
| 4755542933 | |||
| f221e20169 | |||
| a149666d3a | |||
| 0ff428b61a | |||
| cfedc72955 | |||
| 16de588c30 | |||
| 779d907397 | |||
| f91e2e41b6 | |||
| a04e4874f3 | |||
| d303b67e35 | |||
| 31c0c43d14 | |||
| fafb73d03c | |||
| e4ee4d9efe | |||
| 3a043b2704 | |||
| 8c9c7309a5 | |||
| 09330e9cbf | |||
| 08ad62dc70 | |||
| 464482a507 | |||
| d449b1266f | |||
| 6d0c4b18d6 | |||
| a83d1b5761 | |||
| 99d564278e | |||
| 482f45d43f | |||
| 21335a843a | |||
| 1facde123e | |||
| d02a527b36 | |||
| 8f9d6ed2ce | |||
| e43902be79 | |||
| 0f5f8861a7 | |||
| cb08886d27 | |||
| 322ec56787 | |||
| 75883e11d8 | |||
| 60b12a3bdf | |||
| 26a66e3a2b | |||
| e86e78a665 | |||
| 3ba68abbee | |||
| a46ba32f06 | |||
| 82348b519a | |||
| 8315a50d49 | |||
| dca07831db | |||
| d568dd0791 | |||
| 9dbfc68488 | |||
| 0b46e0ef8e | |||
| 472604bc15 | |||
| 58a2d38518 | |||
| c91186be8a | |||
| 03235438bc | |||
| d015285f1a | |||
| 45323a6817 | |||
| bcc8d35654 | |||
| 9137b65f4a | |||
| fbc9dac99e | |||
| c27a6e06ad | |||
| 07970fcbae | |||
| 0b3e250386 | |||
| 13b1ba613d | |||
| 5a1feb4500 | |||
| cc7accbc95 | |||
| 42a83ea0c5 | |||
| 39f84442cd | |||
| 047c25b0b7 | |||
| 045f21beac | |||
| 8a64460097 | |||
| 195d039904 | |||
| bcf77433b9 | |||
| 3a122a7137 | |||
| 354d286a98 | |||
| bfccc1c9b8 | |||
| 80767c17b2 | |||
| 0a9185462e | |||
| c058d3f8c1 | |||
| 70655da2e7 | |||
| 51f8c15af6 | |||
| 20d6984057 | |||
| f26813c137 | |||
| e2a265c3c7 | |||
| e840daa340 | |||
| c54df5336d | |||
| 4ec97409a8 | |||
| 31b5568dfa | |||
| 10cfc6521d | |||
| bfdbc7fc92 | |||
| ead332d863 | |||
| b8fd666e84 | |||
| fb6e3637de | |||
| 2db519f9e0 | |||
| f55aeaf3d4 | |||
| 2340d4957b | |||
| 7bed914a92 | |||
| 4b9f86a4bb | |||
| a1844e15e1 | |||
| 148589a6c5 | |||
| 2902a8b441 | |||
| b410016fae | |||
| 0d56448bfd | |||
| 326c292572 | |||
| afdaef1a64 | |||
| 9bcd4b8e95 | |||
| 4d455f13b6 | |||
| 94eea3aa90 | |||
| b00f47dd99 | |||
| 20a4427e08 | |||
| 3287f31e2c | |||
| fbb6b01585 | |||
| f07d1b7257 | |||
| 45d2d958a2 | |||
| 2ba2498f6b | |||
| d76dada9f8 | |||
| 28b63ee21b | |||
| 90ea78eb39 | |||
| 0cda0e93f0 | |||
| 2e0469f915 | |||
| fdfbd23963 | |||
| 5f8b11f8e0 | |||
| a1df2f6ca6 | |||
| 1d0d0e40de | |||
| b3e5144cea | |||
| aed74449b0 | |||
| 45dc231024 | |||
| c1a223f120 | |||
| 4a926997aa | |||
| ae764b95fb | |||
| 7bba3f8b4d | |||
| b2ad804d3c | |||
| c49fa5cd3d | |||
| 92b5e28675 | |||
| 4afa5f6bc6 | |||
| fbdc31aa97 | |||
| 4eedfadc22 | |||
| 3432a6c39f | |||
| 7e7c2180ce | |||
| 0386446a00 | |||
| 09853e4187 | |||
| 40020fa617 | |||
| cc68c15824 | |||
| 7aa874a0e3 | |||
| 8203e5b568 | |||
| 4f54bca286 | |||
| 087479325d | |||
| 357b2c2a60 | |||
| e1918b56e2 | |||
| 1f31d1e614 | |||
| f5468c5f11 | |||
| 672cf331ea | |||
| 348ad0faed | |||
| ae742547d8 | |||
| ff1c01c836 | |||
| a645a3c929 | |||
| 37c590400e | |||
| 785e2d8cf5 | |||
| 03d25cb102 | |||
| 869dd9ac11 | |||
| f647e172bd | |||
| 7069200c6e | |||
| c61cfcbed9 | |||
| 67eddc99ef | |||
| 03fd5aaf09 | |||
| 31a8f5e5c7 | |||
| b7c6460c0e | |||
| 538c096b8f | |||
| d05c738696 | |||
| 976035da22 | |||
| d47fd51c7c | |||
| a047c65efd | |||
| 5bbb6b1c89 | |||
| 95432cb591 | |||
| 04862e7f22 | |||
| abafd0bb24 | |||
| aa83617796 | |||
| a5b8806997 | |||
| 7a70c0158e | |||
| 74f5972874 | |||
| b01a29d2e9 | |||
| 88bd0dc9f5 | |||
| c7b6d44874 | |||
| 8b6e01929b | |||
| 2ecba00d2a | |||
| 851fcaab13 | |||
| e1b9504421 | |||
| 247e8ed6cc | |||
| 996d1be136 | |||
| a249d4d572 | |||
| c91d52d753 | |||
| 0c37db444a | |||
| eb93f1d915 | |||
| 74e6c9b145 | |||
| f15e630fd1 | |||
| 01ee84caa8 | |||
| 311a1916d1 | |||
| ae43ae1b97 | |||
| d9814bbb1f | |||
| dba8abacf2 | |||
| 3ee1474535 | |||
| 8481e923ee | |||
| 53cfb0f078 | |||
| 233277f6e8 | |||
| dbd75cb513 | |||
| bae14a54a1 | |||
| 9c48afca77 | |||
| 54ebc460fa | |||
| 901e9a39f9 | |||
| 2ebd12c6db | |||
| c762529b8b | |||
| 3c371038cf | |||
| 0350c19c81 | |||
| ebace67201 | |||
| cbe6e2e3bd | |||
| 4adefc885b | |||
| cade2882e4 | |||
| 8c0f2fd527 | |||
| 56809d8d66 | |||
| 14772494be | |||
| 4bbec7344f | |||
| 9907863ef5 | |||
| adfbe36fdf | |||
| 3cfb9ac1c3 | |||
| 2004b85a12 | |||
| 7dd3b5f122 | |||
| c849746a6f | |||
| a9582bc295 | |||
| fd49defe00 | |||
| 650a24775a | |||
| b62a864a7d | |||
| b76e10bdfc | |||
| 4311205e62 | |||
| 69bc1c971d | |||
| f13c720bcc | |||
| 63f66e9714 | |||
| 25d8ed079c | |||
| b923714b42 | |||
| 178295596a | |||
| 2e1dae86e0 | |||
| 4bb0206d2d | |||
| 23cda9c121 | |||
| a1d0b59e28 | |||
| 9de8e61b1b | |||
| be1188e8e4 | |||
| fdaefa52ab | |||
| d667e70b90 | |||
| 6184acc144 | |||
| 6f012dc459 | |||
| 94774c674a | |||
| 3bda3354f0 | |||
| 8a56459375 | |||
| aeb689648f | |||
| 761d4c3354 | |||
| 90899e7d1f | |||
| 9e9d8b7149 | |||
| f774df532c | |||
| d85c4533b7 | |||
| 79aeca832a | |||
| 50931b1fb6 | |||
| 63bd0cdebb | |||
| 8880d381db | |||
| 4eccd3b2ac | |||
| 716ba77d3e | |||
| 4053eec64c | |||
| b11463b0f7 | |||
| 109ada8e8b | |||
| ab32670b40 | |||
| 92f82099b5 | |||
| e41b7434c9 | |||
| 9c79df6d6e | |||
| fe1f491104 | |||
| 652bdf9f1d | |||
| 36b13d6d28 | |||
| 53b58b63a2 | |||
| 6b0f298a2d | |||
| 08bc8bc49e | |||
| c8b436de94 | |||
| 82b6323f72 | |||
| 6664bc9e62 | |||
| 544dc67d0d | |||
| d55c4d12bc | |||
| 707bc9bb1a | |||
| 41806eab54 | |||
| 443c3bf26a | |||
| 7ac6e82624 | |||
| 87106de6d6 | |||
| c52d94b003 | |||
| 5ac13f2107 | |||
| baa22ae9c9 | |||
| dba3854e40 | |||
| 1f06810592 | |||
| 2861e8cfee | |||
| 9269548d64 | |||
| 712399e9da | |||
| 1654d36126 | |||
| 245e113d76 | |||
| 8b35993e99 | |||
| 3dcaf7b50e | |||
| 58d4b5e612 | |||
| caf0852f28 | |||
| 558fe249ac | |||
| 20b0c83fc0 | |||
| 0c3020f7b3 | |||
| fce10714ae | |||
| 8055856dd7 | |||
| a8c540f122 | |||
| ccf117656a | |||
| 6b5cf36957 | |||
| 201f0317a2 | |||
| ea9bb99afa | |||
| 51609dea83 | |||
| d9788434f3 | |||
| b0d433b5c8 | |||
| df3dd297c1 | |||
| 1a9ee5e3cb | |||
| a22da040e0 | |||
| 4c0ee93826 | |||
| 759a22fc52 | |||
| 066b667bd8 | |||
| 91e5e4f53b | |||
| 7cfd1a9c7d | |||
| ed78421d9b | |||
| 0e85be5dc6 | |||
| 23721ad189 | |||
| 50c7f6514e | |||
| 7818370d7e | |||
| 2f05256103 | |||
| ed1dc14bc5 | |||
| ae2b0e9d7e | |||
| b9d23115c6 | |||
| c72da10e56 | |||
| a4f4b0c3f9 | |||
| 5c0a51be73 | |||
| 069b6d7df6 | |||
| fea7aee20b | |||
| 26dd26d7c0 | |||
| 4e06147b82 | |||
| 1065abcd44 | |||
| cf5e40788b | |||
| 93ff2651c4 | |||
| de9689c1a2 | |||
| 24379be99d | |||
| 75bec6e967 | |||
| c3eb5f8d08 | |||
| 13c1866fa2 | |||
| 4ab8a5b7bb | |||
| 821434bd7c | |||
| ab3d29d449 | |||
| 1ee5a1d110 | |||
| 19910ab0a8 | |||
| 727f513431 | |||
| 5eac22f0be | |||
| 360efccf4c | |||
| 57ac0a0bb9 | |||
| 80c2e34460 | |||
| 78e652ea27 | |||
| fc7d36ac22 | |||
| 1a4e4fedb6 | |||
| 5ff7c58503 | |||
| 25488e9100 | |||
| d4bf86f717 | |||
| 1cd463968e | |||
| 6388941e81 | |||
| 48dd87ce26 | |||
| 76643aae59 | |||
| 86c9c077bf | |||
| 6510e620ba | |||
| 7d2149ad23 | |||
| 87b3c35ba2 | |||
| f7fdadd4f4 | |||
| d6ef599b08 | |||
| 4b7a5ad049 | |||
| 6f3ad4bec4 | |||
| 87047fe38d | |||
| 5627cd9ca2 | |||
| 0bfab3ba9c | |||
| 10b692bb2b | |||
| 663c415a57 | |||
| 5f60126333 | |||
| 986b99479d | |||
| cbbf4b71c2 | |||
| 4398bea8d4 | |||
| e85ac755ae | |||
| fa2f91cb24 | |||
| ff30c8d288 | |||
| fd5807d404 | |||
| 719133a636 | |||
| 5650f65214 | |||
| 7bc4c8e661 | |||
| 48c7d94edc | |||
| 2d63db64b2 | |||
| 3a26750e15 | |||
| 517bd63ac0 | |||
| ef77fca3bb | |||
| dde7ed096a | |||
| 834db84d43 | |||
| 93e81879fd | |||
| 9263805bb4 | |||
| 5467df5850 | |||
| 02836a2dee | |||
| 9747ff1056 | |||
| ce38932e86 | |||
| fc76d98fbc | |||
| 4a4f1b86df | |||
| 6f75f212b8 | |||
| 1051d46a79 | |||
| 41bb08d899 | |||
| afef9847b1 | |||
| 2fe83bcf14 | |||
| 8529980040 | |||
| fbf11eff3d | |||
| 1d0e8505f6 | |||
| 332f63e823 | |||
| f5062d554e | |||
| 5d6f3f249b | |||
| f6e524ca14 | |||
| f5768ee8ae | |||
| 53df43b5a8 | |||
| 817004f96d | |||
| e54262a320 | |||
| 26ab8355fd | |||
| 633b5532e2 | |||
| 68809149c5 | |||
| 5d8d65f5b5 | |||
| d29122af52 | |||
| 53898a0465 | |||
| 9038a41301 | |||
| 52349dc043 | |||
| 26eca76036 | |||
| 7deb934b5a | |||
| b8e02f1ab9 | |||
| 07b2cf3d95 | |||
| 0f06b1e401 | |||
| 432553d90b | |||
| 8a51187f01 | |||
| c63a1a1fd2 | |||
| ab03b4d88e | |||
| bcce233795 | |||
| fe77112ca6 | |||
| e3a4dbbbb3 | |||
| 4a19e7beed | |||
| 6b6ed81c4a | |||
| d69717d08d | |||
| e8e43a28d2 | |||
| 03a89a1553 | |||
| 71eb06ba2c | |||
| 4e7a73a450 | |||
| a893303517 | |||
| 4ccb5fe7f2 | |||
| 21f3ff57bc | |||
| d07d743de9 | |||
| 6c41b1cb9f | |||
| 1d5206fa8d | |||
| d2d7a84446 | |||
| 91218c90fb | |||
| 1db3872cbb | |||
| 766aca3708 | |||
| 04a05a4017 | |||
| a46cee919f | |||
| f2877e36a6 | |||
| c8056c5ba9 | |||
| 1eb95269e8 | |||
| 23906131ec | |||
| 23ca0bfb6f | |||
| 8c055620d0 | |||
| ead2d66295 | |||
| 39b9cce4d8 | |||
| 3567909675 | |||
| d79cc1499f | |||
| 9674515171 | |||
| 2ee39c249c | |||
| 2ae6829a65 | |||
| 9c9fb54932 | |||
| 713cb287bb | |||
| b47805cbbf | |||
| 6aa5c7cd74 | |||
| 97da1506dd | |||
| ed193f99a4 | |||
| 96f86ff0eb | |||
| f2bcb18688 | |||
| b5f7d78a26 | |||
| 08cdab0f50 | |||
| 2a2f5b089d | |||
| a21ceabfdf | |||
| fe4dc13b84 | |||
| 70730e8628 | |||
| adceb92796 | |||
| 55336f6be4 | |||
| 25663d114a | |||
| d80592fbb7 | |||
| 7fab331b90 | |||
| 6c5c43d595 | |||
| 1b49aaa6fc | |||
| ed1725f9cc | |||
| 8d5cc4e983 | |||
| 8a03017ccd | |||
| 884d5d81f9 | |||
| 95be563b43 | |||
| 6ae6a4e14a | |||
| 9b069a97d1 | |||
| 25f217217d | |||
| 322f4fd268 | |||
| da55afb712 | |||
| 5788052262 | |||
| 4a56da6f2e | |||
| 770543fea5 | |||
| ed83feb112 | |||
| 223f264972 | |||
| 6c6f9f63f6 | |||
| 58f761862f | |||
| 3a45de8eb3 | |||
| 9a0ffb29e0 | |||
| 1d62818348 | |||
| 5be789d100 | |||
| 7dd79bd4bb | |||
| d0b6ee897c | |||
| 2f03656869 | |||
| 5ac51c84b7 | |||
| ce71384dd9 | |||
| 2a7db59e6b | |||
| e561c13f28 | |||
| 12981bd7ff | |||
| 208250d030 | |||
| d4598ac96f | |||
| 293451e527 | |||
| fe19c84049 | |||
| 7e0d5c3416 | |||
| 319fe2f556 | |||
| 6f6bffdeb7 | |||
| 7c6271d4e9 | |||
| 5d3f082771 | |||
| abf6935653 | |||
| 6eecad6bb6 | |||
| 12cea1f263 | |||
| 3150a182e6 | |||
| 56160193a9 | |||
| 859470aabf | |||
| ad2dc5ac4b | |||
| d32816aa65 | |||
| 64e99338b0 | |||
| 88bcb2883c | |||
| a70520f04f | |||
| 09521ec26a | |||
| f5b8049dd7 | |||
| fe230d647a | |||
| 33daa22e49 | |||
| 80965dcbc9 | |||
| 89f0cfb6a7 | |||
| 89884d4cd7 | |||
| e9590f81be | |||
| 83159e4153 | |||
| 21dc20dff1 | |||
| 3ec6526aa4 | |||
| ba918b9144 | |||
| 3a63d049dc | |||
| 13011804ab | |||
| 1e2e621055 | |||
| f53c3ff8ae | |||
| b30e60dfde | |||
| 34ac30cdfe | |||
| 8bd30d1a0f | |||
| cbc575fcd0 | |||
| 9720812714 | |||
| b9a8f3217f | |||
| cb812d2d6c | |||
| 572b35c4dc | |||
| 043486a53f | |||
| df68f8fb9c | |||
| ee146b20e5 | |||
| 936ca7d4ba | |||
| 57e37419cf | |||
| 86934a789e | |||
| 9552d3ac25 | |||
| 9782e2a615 | |||
| 7b8f5dfc5b | |||
| f3fd311d70 | |||
| 5e7e71f6cc | |||
| 6cc4178cb3 | |||
| 49be7e9d12 | |||
| 8f50626a3d | |||
| 89cfd1a8ba | |||
| 2e9ec0bde0 | |||
| b77491e91e | |||
| 65b84b0e4a | |||
| e9cb8fcde8 | |||
| aa04f67f43 | |||
| 3710a2b729 | |||
| 96cadd05f1 | |||
| 114f014091 | |||
| 960c596db8 | |||
| fe6ebd8aa7 | |||
| f121b04e66 | |||
| 4724b809dd | |||
| 5353581cf1 | |||
| 68f60db4c0 | |||
| e90e514f8b | |||
| 6ab04cf056 | |||
| 219270b10d | |||
| b070998a73 | |||
| 14e3edf5dd | |||
| bb604b3922 | |||
| f43f8e9fb1 | |||
| 9c4c5badcd | |||
| e511d48667 | |||
| 8f6ddfef06 | |||
| 2b9e0b167e | |||
| cb874dc77a | |||
| b561cbc8f7 | |||
| f252e004b2 | |||
| 177c027bf7 | |||
| cc386bfe48 | |||
| 1254dd7209 | |||
| 3054ad8471 | |||
| a3cfa69174 | |||
| 82b32da523 | |||
| 91a1ffe113 | |||
| d3b6b81e64 | |||
| a2b61a8447 | |||
| cd6c9ca460 | |||
| 49a189d19f | |||
| d972b94ce8 | |||
| 0a552fd378 | |||
| 3538a629cb | |||
| ef1652c4f4 | |||
| 9d5250294c | |||
| 8e2aab5dbe | |||
| 75d6267f68 | |||
| 63bbee19a4 | |||
| 67f78c2f95 | |||
| f558954d22 | |||
| f5b1fff4ed | |||
| 0c00164113 | |||
| c1a910e2cb | |||
| 4578984a75 | |||
| c8714c0c16 | |||
| 28b1a3b7de | |||
| f35cf6fa99 | |||
| 265b9b7ec1 | |||
| 561d5026c9 | |||
| 932b39ea09 | |||
| bfb7e6aa71 | |||
| 13e2694dc0 | |||
| 325dd07b4d | |||
| ca197ae2ab | |||
| 8542f3aec6 | |||
| 7b23d7a1a3 | |||
| 55901c219a | |||
| 973f6d2f20 | |||
| 42b05160d8 | |||
| 729c48b8ad | |||
| 4a2d201ac2 | |||
| 22051ab626 | |||
| 8188d8495b | |||
| 6d3e613214 | |||
| b8c2b73874 | |||
| de14cc95ef | |||
| a56814a3aa | |||
| 689f1e3b68 | |||
| 1d280ed079 | |||
| 4a4118958d | |||
| c0010e7bdb | |||
| b03ba1df9d | |||
| 5b28be29ac | |||
| 3ca7b7c9bd | |||
| 40e5a42212 | |||
| 481e2d7925 | |||
| 6c46d4b090 | |||
| 9e5b8b5f29 | |||
| 27f0354db5 | |||
| eb68fe86e6 | |||
| cf4514614a | |||
| f26bc062e1 | |||
| 9f848594a1 | |||
| 4cb92f5d8c | |||
| 692fec5518 | |||
| 1f978c3039 | |||
| 72ca4958c1 | |||
| 7ef693c6d8 | |||
| 32319affb7 | |||
| 04458270d3 | |||
| a4e2f4b90f | |||
| bd390decf4 | |||
| 548430e4a8 | |||
| b29f80942f | |||
| 5be275f8b0 | |||
| 1f84195cc9 | |||
| 8204faef7d | |||
| 0a889f4549 | |||
| c9edf04a45 | |||
| 5fc5d1f68f | |||
| b7ae9d82ff | |||
| 498c626227 | |||
| 24be8be4b2 | |||
| 7700d3af79 | |||
| 95dd96f7f9 | |||
| 2f89ba9707 | |||
| 1460e8cad3 | |||
| 9e68a37205 | |||
| d9591a826a | |||
| 843ae23911 | |||
| bf1559f3bd | |||
| 9baf63ded5 | |||
| 5a5a4eccf0 | |||
| d82270d8e9 | |||
| 39fd038fde | |||
| 0e6192487e | |||
| dee19c5961 | |||
| e18a66dd68 | |||
| 8c7efc7bb4 | |||
| 5c88db4bc4 | |||
| ccce9759d6 | |||
| 857541665a | |||
| 1737f4ffdc | |||
| 85c839ffc8 | |||
| 37168298ff | |||
| 65c004e8cc | |||
| a87f642473 | |||
| 69a8f94607 | |||
| 52438c682b | |||
| c9ea7e3b79 | |||
| d4289efbc6 | |||
| d9b65705ad | |||
| 5b35524f8d | |||
| 540274d8f5 | |||
| e4794c60f8 | |||
| 95676ee4bd | |||
| 42b8a9d5f9 | |||
| a027cb16af | |||
| 5b75bd4c61 | |||
| 3d90f9ee34 | |||
| 52543c828e | |||
| ed9c780e2d | |||
| 904b74be5b | |||
| 629fa23237 | |||
| 9f6d441ad1 | |||
| b0a99ced20 | |||
| 101874fd29 | |||
| 3bae1a1af7 | |||
| b6f1138922 | |||
| c90cc405b5 | |||
| c73690e546 | |||
| 5b4ddcae1f | |||
| 1244d838ec | |||
| 6c5da2d787 | |||
| 9f2225de3d | |||
| 69c809a2c0 | |||
| ba27bd8a4c | |||
| 1da1c6f86d | |||
| 012eb42c8a | |||
| 186a5f8d08 | |||
| 522dac5c6b | |||
| 32c2ab67fb | |||
| 54e0cdee75 | |||
| d5a23f5239 | |||
| bbd035d7b1 | |||
| 140c048b71 | |||
| d0306f311a | |||
| 0c918bd826 | |||
| b2064c3758 | |||
| 11e276a977 | |||
| 14ee8921cf | |||
| 2dcc4e974d | |||
| 5b639d78cf | |||
| 35c4fa1209 | |||
| 8a13d6a60b | |||
| b94c742100 | |||
| 967f281210 | |||
| 1dba6f438f | |||
| fb464aefaa | |||
| 35b6db66b3 | |||
| 396862fc0a | |||
| b6ab058cb4 | |||
| fb4d1df210 | |||
| ffaa32be29 | |||
| 18af7c51c8 | |||
| e45b46e8a5 | |||
| 4419463c01 | |||
| 51115e070b | |||
| 783889f050 | |||
| 547229d017 | |||
| ad05198be1 | |||
| f93f31784e | |||
| 05d4109f0b | |||
| 9ea377b72b | |||
| a4eec37467 | |||
| 14d6c9d6f4 | |||
| 4707112837 | |||
| d4f78631d9 | |||
| dc5c2971c8 | |||
| 07f1180ccd | |||
| e483540d3d | |||
| 362518959b | |||
| 7b1ac0f70c | |||
| fc18da47da | |||
| 6d14af968f | |||
| 2cff450fa4 | |||
| 069b82518d | |||
| 91663c4733 | |||
| d7cf91ec5c | |||
| 4854c15f8c | |||
| 248e63ba04 | |||
| fc19ce037e | |||
| 020b67764b | |||
| 32d25e5490 | |||
| d8cd68025e | |||
| 38a8b190fe | |||
| 3788e8ce20 | |||
| b02a6377ab | |||
| ac550094df | |||
| 2ea75c1664 | |||
| cf07f12cad | |||
| fb00833d3f | |||
| 91046c350c | |||
| 3b2c294323 | |||
| 4507c7e581 | |||
| 6d02fb22a2 | |||
| e926f2ca77 | |||
| 77267add3b | |||
| 460a4eed57 | |||
| 84ea2cd1af | |||
| 68e1b9b700 | |||
| 361d260964 | |||
| 3a66d778ed | |||
| dbf5fcda58 | |||
| a5309f2c9e | |||
| 13b81fa3e8 | |||
| 8c60267997 | |||
| 839efd6e32 | |||
| 54c2788e0a | |||
| 1439e598fc | |||
| 7a9e6bdb97 | |||
| 3b58aead33 | |||
| 69d379d07b | |||
| cc9d5765d5 | |||
| aa9cf8b193 | |||
| b8afc028de | |||
| e7a594003f | |||
| 5605df96dc | |||
| c499c19e5b | |||
| 106f3e932e | |||
| 04b5005218 | |||
| 32442985c5 | |||
| 1ce6946507 | |||
| a1a3481939 | |||
| 2db5b5665c | |||
| a184d018da | |||
| 233c3f728a | |||
| 1102d22919 | |||
| 6c903ea25e | |||
| 602bc61b89 | |||
| 42201b3d28 | |||
| a8889c16eb | |||
| edaab18894 | |||
| d300e74fbd | |||
| 1a804b2096 | |||
| 8c7f1ad596 | |||
| b59548d339 | |||
| 181caf6dfa | |||
| 2eafb6b31f | |||
| 742f497833 | |||
| 5119bdf545 | |||
| ce44d3b2a7 | |||
| bf7ed2cd7d | |||
| 1e287c61fb | |||
| d3e42aa876 | |||
| 58e3629c32 | |||
| 990f395b4d | |||
| b8500b4345 | |||
| b52960c47f | |||
| 50ad63735f | |||
| 89bc3d37f8 | |||
| 9cfb820036 | |||
| 365abc3c1e | |||
| 7a1555e8c0 | |||
| 6345bb55d2 | |||
| b48a274707 | |||
| 55e9bd681e | |||
| aec9ec8294 | |||
| 4229888cc9 | |||
| 103b8d32f5 | |||
| 303c98be96 | |||
| c84da4c061 | |||
| 3a4d466907 | |||
| e7143d8da4 | |||
| 99fc35e632 | |||
| 95cc8a1484 | |||
| c139d6bb8a | |||
| 3d0b5bb8b6 | |||
| 552ab8e8c4 | |||
| 596e2e9673 | |||
| 66c7dc6539 | |||
| 2585098c20 | |||
| 1f5f51da68 | |||
| 25e119202a | |||
| 7b421d0b3a | |||
| 0066135f12 | |||
| b930d3fa54 | |||
| 129a549110 | |||
| 22883dc195 | |||
| 516299ee55 | |||
| a9835ba032 | |||
| dda154a927 | |||
| cd5856778c | |||
| d7db950878 | |||
| 62f184f6ea | |||
| ab0d341bca | |||
| 1b27f481ba | |||
| b68f9be8dd | |||
| e9b0dbdfb6 | |||
| 0b21dca0a4 | |||
| 5e5d84cb65 | |||
| c2661d0586 | |||
| 032348e3fd | |||
| 840a682665 | |||
| 04807a5653 | |||
| 5ebea3f3dd | |||
| 49ca3835c0 | |||
| 566307105e | |||
| e8e75408cc | |||
| b52aa38552 | |||
| 8d55b251c3 | |||
| 386c7b19c1 | |||
| eaaa168ee1 | |||
| d9f5811d86 | |||
| 27d3470abc | |||
| 36f7427613 | |||
| 929c117ddb | |||
| 7d6d77fae5 | |||
| 2297461d91 | |||
| a26a3bebad | |||
| 4a673de424 | |||
| a837c2ccd4 | |||
| 10ee3132fd | |||
| 783fbecb00 | |||
| de1b5ba2f3 | |||
| 9a9e288c44 | |||
| 424b48f631 | |||
| 86d1cd4e12 | |||
| e700ff4744 | |||
| 34729c8c28 | |||
| 5a08611fdd | |||
| a73da1d6e4 | |||
| 28b8c20756 | |||
| 6941821b71 | |||
| 3c2244701c | |||
| 38dc873e2e | |||
| c24ffb2489 | |||
| 929864be30 | |||
| bd87163a9b | |||
| 785c740668 | |||
| 25aa16f774 | |||
| 9ec89c0dc1 | |||
| 3e5bd2b087 | |||
| 9de6cff13b | |||
| 6b98bc9fca | |||
| cdf9b0a071 | |||
| ff57e9c759 | |||
| b253113843 | |||
| b7305337bf | |||
| 455e2ad723 | |||
| 8cf87b991b | |||
| ae0b289c3e | |||
| 9404c3349a | |||
| 28afbb8d35 | |||
| 5b24443121 | |||
| 1f9aacbbbd | |||
| d194b33a5d | |||
| 55010f0ef7 | |||
| 49fab9ed04 | |||
| 1cd1b578ec | |||
| 184c56aac5 | |||
| 7c39037472 | |||
| 786a803793 | |||
| 273f0e185d | |||
| eebc2c3940 | |||
| 3a964d629e | |||
| ff041f705e | |||
| af62fc9a68 | |||
| 6ff415cc0d | |||
| 41de94e6f5 | |||
| 60d91ca04e | |||
| 19004b2073 | |||
| 70b536e6bd | |||
| 5009678587 | |||
| a7a01bbe16 | |||
| 9b2ce51c87 | |||
| c735d4e717 | |||
| 6fb4dac45d | |||
| 3d49258b84 | |||
| c23aa12d09 | |||
| 6f6ddf9fbd | |||
| 63837b5c31 | |||
| 27e245c241 | |||
| 7775494ade | |||
| a3ce139b86 | |||
| ad470f10f4 | |||
| 302d12083b | |||
| d40dd15af4 | |||
| 440eb8a07b | |||
| 361b861d5f | |||
| b518b2961a | |||
| bfae4e1501 | |||
| d3e13dd8c6 | |||
| 073c35ca08 | |||
| 99b4373561 | |||
| 52dcea477e | |||
| 6abb8d715b | |||
| 51016b0704 | |||
| d14c150070 | |||
| f59f8a3e5b | |||
| 965be0b5cd | |||
| 716900fc5d | |||
| 14280d802e | |||
| 39924857e5 | |||
| c88bda6615 | |||
| ecb80ca70d | |||
| 51b03b78ce | |||
| a7fd029ed2 | |||
| 5beb29ad09 | |||
| e7dc2ca810 | |||
| b5ce0db1ff | |||
| c8b52902e9 | |||
| dbc4e0ac26 | |||
| a0d2860970 | |||
| 77c1a05a4a | |||
| aeee2e049d | |||
| 525b184ad4 | |||
| 76e0fe9f9a | |||
| 06ddef114c | |||
| 32cdcc1304 | |||
| 4a2b414b59 | |||
| 937497aec9 | |||
| 38d2c189e8 | |||
| 57aeacf3f5 | |||
| fe4036b768 | |||
| 5dd479c492 | |||
| 5f1ff1fc6f | |||
| b08fb1f170 | |||
| e2f6180d6d | |||
| 90d19ea381 | |||
| 13738f08eb | |||
| 1b76184946 | |||
| 711431f7c9 | |||
| 4ea3f7ccf0 | |||
| 80cd86ea29 | |||
| f87bb6cd06 | |||
| ea726a22bd | |||
| 7e3afe7d70 | |||
| 8131c58fbf | |||
| 674e32a096 | |||
| f5d42a3e01 | |||
| a079a03adc | |||
| 8485f94133 | |||
| 5d60a8f03b | |||
| ec4319b74a | |||
| 41c3f9d073 | |||
| c27990b395 | |||
| 2e9a823ee1 | |||
| 590afccae7 | |||
| 7a82780826 | |||
| c75e363a06 | |||
| 573b7b61cf | |||
| 9f9e1bc9fd | |||
| 34e11b1569 | |||
| cc7b77a8ad | |||
| ed3a75ddc0 | |||
| 983c01df57 | |||
| 9d95b7aa6b | |||
| 5319cb8679 | |||
| b4b1a63c22 | |||
| 2dfd57de80 | |||
| cbc8876656 | |||
| 4e6b8bf6b3 | |||
| da92826f6a | |||
| f1a4e429f3 | |||
| 3cd248a2c5 | |||
| 7f5dd97359 | |||
| c0ee431d1f | |||
| f56de73eb6 | |||
| a0b5cd00d5 | |||
| 66b5f3d896 | |||
| a4346a6f34 | |||
| 83894f6530 | |||
| 9b776bb029 | |||
| ea72fb09e0 | |||
| b2b390cf8b | |||
| 926abe248f | |||
| 95468cf83e | |||
| 259b93eb25 | |||
| f59646643f | |||
| 7130417e60 | |||
| 458a9f2a63 | |||
| 0f85497f75 | |||
| 3c0c6afd43 | |||
| 345cdb41bc | |||
| b78fa40eff | |||
| 193831ae7e | |||
| bcb9dc3ba8 | |||
| 7903cdc44a | |||
| a66c1ea50b | |||
| 978e8f160b | |||
| a49351a146 | |||
| 07d9b416a3 | |||
| f9edb69370 | |||
| deac313ba3 | |||
| b149f9acf2 | |||
| 7c96ba090e | |||
| 11ab908848 | |||
| 3d2978b2e5 | |||
| 7ad3a7ae92 | |||
| 9042488a65 | |||
| b08e13f05a | |||
| 6271fd4998 | |||
| 4d747a3df3 | |||
| 5ce057d40e | |||
| 1e2e8f932f | |||
| 5accb9c1f1 | |||
| 5b102d65c7 | |||
| c609ddd721 | |||
| 0c3783d127 | |||
| f702ab6115 | |||
| 7dd760e0fb | |||
| c6f3b5998c | |||
| 28440d97de | |||
| 2b2b71fe01 | |||
| f5a9e7b487 | |||
| d43842a0e6 | |||
| a557962f17 | |||
| 560c682157 | |||
| a0ae36f511 | |||
| bdee17ffc4 | |||
| 5829f09f8c | |||
| bc6fa5e7db | |||
| 1607cea9ce | |||
| 426019ea7c | |||
| 1b878a50c4 | |||
| 97525189b7 | |||
| 999947751a | |||
| 2def61ab43 | |||
| 5e07ef488c | |||
| 7af47c0caf | |||
| 1a5ed3c05f | |||
| 9cc9b09861 | |||
| cef4432d97 | |||
| 18be6acc34 | |||
| 27d0dd40d0 | |||
| b05fa626f6 | |||
| f1fc84ea5f | |||
| 3942154c05 | |||
| ff182ee3c7 | |||
| 10cc275970 | |||
| 21821d584e | |||
| 6b8716eff8 | |||
| 47434e2943 | |||
| 4c3b327cff | |||
| 3454d13e48 | |||
| 0aad7c59ee | |||
| ee8e4e0338 | |||
| a430c51c97 | |||
| b59508e9e5 | |||
| 08deac1dea | |||
| a2dc3f3d5b | |||
| 679cfab088 | |||
| 9144595aaf | |||
| 8a545180a2 | |||
| 17c5793558 | |||
| 8afc346a2c | |||
| 026bb7f67b | |||
| b971e7dbf6 | |||
| ec39ef16e4 | |||
| ae07bacbb7 | |||
| 0f0d8da6cd | |||
| 2a1c99efac | |||
| caa89d3f4c | |||
| 1602816d08 | |||
| 1062cf5924 | |||
| f6e5cd3fd7 | |||
| c675196cb2 | |||
| 8b9c2668d1 | |||
| c1a927ed88 | |||
| 4d4416c1df | |||
| f4833983c0 | |||
| 89eb99d813 | |||
| 683a68d179 | |||
| 598af67338 | |||
| d9d0ffc3b9 | |||
| 4d8e04580e | |||
| cfaddf2f22 | |||
| c72b194107 | |||
| d7f33ff8b1 | |||
| 91e491b66a | |||
| 31b7e40ab0 | |||
| f2b094fff0 | |||
| 185ee7f0f4 | |||
| f446b15f7a | |||
| 52a833f18b | |||
| 37fc68977c | |||
| 96ee71a594 | |||
| 1c2dda9353 | |||
| 96a9fd0ad7 | |||
| c53c27e350 | |||
| fd4f32bb3c | |||
| cbd2d8ed6c | |||
| 3dd06bc620 | |||
| 3a829e1cfd | |||
| 183e1a85c3 | |||
| 6b696234ab | |||
| 21ac1d1f17 | |||
| 4163b81f70 | |||
| 6c3268ce72 | |||
| 4d87f86fcd | |||
| 4a37401dc2 | |||
| 8cf90193fc | |||
| 9942a51cad | |||
| 4980d96c8c | |||
| f32c8748ed | |||
| 7b886679e1 | |||
| 2620c04b09 | |||
| c22157f2f5 | |||
| 09f02bc225 | |||
| 9fc9549a28 | |||
| 0099afad09 | |||
| 3e512634c6 | |||
| 7045354808 | |||
| dbcc97a250 | |||
| 050081b7b1 | |||
| 993d1e7635 | |||
| a86a3c1f71 | |||
| b0a192ad9a | |||
| ea7b478c6b | |||
| b673383f59 | |||
| 06ae366b74 | |||
| 6b9cf7094e | |||
| 5ae22bd2bc | |||
| e951551531 | |||
| 272e5fb6cc | |||
| 7dc17d09c1 | |||
| cfacbe739d | |||
| 0a72226ba5 | |||
| 5f22a14643 | |||
| 5562e38c2f | |||
| f9027f7a61 | |||
| 6d0e437ad4 | |||
| 3abc53d3b3 | |||
| d0e4c2c3ab | |||
| 5be50c1638 | |||
| 7c525aec79 | |||
| 63d5edf892 | |||
| c9f2cf178a | |||
| fc98de3bc0 | |||
| dd8360f5e8 | |||
| bc9b815b47 | |||
| 2a93995221 | |||
| 0e93f6521c | |||
| b3a6d0ce94 | |||
| de60d05190 | |||
| 2a2ce9a490 | |||
| 639644e3c3 | |||
| 2378e6e94e | |||
| 87d9feae70 | |||
| 4a93d129bb | |||
| 39e5e2e9f9 | |||
| 8a5f777c65 | |||
| 22c693e042 | |||
| 36d04f5841 | |||
| 409123337d | |||
| b180a210cb | |||
| 32dfdc4d08 | |||
| 4d46888995 | |||
| 69db836231 | |||
| f82b9ad308 | |||
| 3ac91b1216 | |||
| 8d4b3e0851 | |||
| 67d8f46217 | |||
| f357136936 | |||
| 9d622d2be9 | |||
| 800525227d | |||
| c9dec9a31e | |||
| 2ae4fda6e8 | |||
| 609702715f | |||
| ec7e138208 | |||
| bfd64a8bce | |||
| 5571b6481f | |||
| 6d6574988c | |||
| af8d075bf2 | |||
| b7db66e90b | |||
| 13ac4658d9 | |||
| 8ad3420822 | |||
| f842ced67e | |||
| e0081e56df | |||
| 3202764f22 | |||
| f477876359 | |||
| 86ffcb92f8 | |||
| a2088e5cd9 | |||
| 6e1247f393 | |||
| c33faa4918 | |||
| d0aeb1c411 | |||
| 485924527e | |||
| ca1bfda326 | |||
| c7c786d662 | |||
| acf9fe308c | |||
| 3b32231709 | |||
| 9dae198af2 | |||
| 29bfd5bb93 | |||
| 8da51d7f5a | |||
| 91964a0ffc | |||
| 479ef20859 | |||
| f458b7dcb8 | |||
| 2d25ff7836 | |||
| 57dd5d0584 | |||
| 757efec05e | |||
| 4979045be2 | |||
| f59af60f70 | |||
| 60bc2a02f4 | |||
| 996be3906e | |||
| 14a054bdbc | |||
| 07a9fd6273 | |||
| a067f7bc43 | |||
| a5eefbb6f4 | |||
| 8d9f83c432 | |||
| ae0df36a89 | |||
| 72539671a1 | |||
| 94277a4aeb | |||
| e276d148cf | |||
| a7152034e8 | |||
| 4a5e9da34a | |||
| 1422365cc5 | |||
| 7f55ff6340 | |||
| 4722626fb7 | |||
| 39d87ad98d | |||
| 85333b9eed | |||
| c99ae6db3e | |||
| c5be98adc2 | |||
| 5321aa2e9f | |||
| 345707ef42 | |||
| 6a9d05d916 | |||
| faf2a89706 | |||
| ada51f90f1 | |||
| 53962116d5 | |||
| 3ea52745b3 | |||
| a8f2289b27 | |||
| 6dd56b5d16 | |||
| eb739cf6cb | |||
| 4853cd9047 | |||
| 4e0f14aeed | |||
| 5e37dac0f6 | |||
| 22bfa9051a | |||
| 0a1dca3aa3 | |||
| 0b20896330 | |||
| 3b934578dd | |||
| c42e1a76bf | |||
| d3f2395d9c | |||
| b5ba1e877f | |||
| eba27d8969 | |||
| fe1d4d3406 | |||
| 28418b0d49 | |||
| f35396c0e3 | |||
| 67cc464607 | |||
| b0fa0392b7 | |||
| 0fc4fddfe7 | |||
| f092966c88 | |||
| 0e1cb515ab | |||
| 35115d0581 | |||
| b1d1fc0e36 | |||
| 91f84cdd5c | |||
| ad2c155e54 | |||
| fc4b383292 | |||
| 1a868d3f12 | |||
| e4dd96e21a | |||
| 8705f8d2e2 | |||
| 65fab5e990 | |||
| 1d92b070eb | |||
| d72102784e | |||
| d7351bf93e | |||
| 6bf40ca237 | |||
| 4be93781b2 | |||
| 13fc6b8453 | |||
| 34cbbdffb9 | |||
| e45eadb6e3 | |||
| 7bf2ef1007 | |||
| 23c46cc4b2 | |||
| 259adbf145 | |||
| 95acc64e42 | |||
| 974d4fcefa | |||
| 298733b192 | |||
| 2ec4c75049 | |||
| bfac5398fc | |||
| d029b1692a | |||
| d7006f25f7 | |||
| ef56910da0 | |||
| dbf73a0385 | |||
| 41b8cae6bd | |||
| 0bea685ce1 | |||
| acd39aa969 | |||
| fd59e71714 | |||
| 47c37a1a7e | |||
| 774f9bac80 | |||
| 316eb738ec | |||
| af493d9dfb | |||
| 3d626abbc2 | |||
| a392f7f8d8 | |||
| 8f8f4c645a | |||
| 1cae62fb99 | |||
| 6db72fa7e7 | |||
| 6ee300c70e | |||
| 0f16790535 | |||
| 524742b8ea | |||
| 8c08bbea6a | |||
| d6c2bd6634 | |||
| 4aeb42dee9 | |||
| 0de7f40958 | |||
| 07fd8d986e | |||
| c821923cd0 | |||
| 6ce247d8d1 | |||
| 473d8c43df | |||
| e082b321eb | |||
| fd236857d4 | |||
| 9290934ec3 | |||
| b6d9118d05 | |||
| 544d21613a | |||
| 68a7720ea9 | |||
| 01a537c0f6 | |||
| 11bd2a5831 | |||
| d615a07f27 | |||
| ef941a7651 | |||
| 928ed40dd4 | |||
| 03f3f174c3 | |||
| 6a1a38fb5e | |||
| 9f4ca9a3bb | |||
| 670786cc2d | |||
| cc3b4ba7e9 | |||
| b8d5246230 | |||
| 37665acd3c | |||
| 5aef4d649a | |||
| 90c050590a | |||
| 3115152f32 | |||
| 923562ad8e | |||
| 1b2b9b3b91 | |||
| 8412044b88 | |||
| ceb2384eb8 | |||
| 1244efd015 | |||
| 1cc572f774 | |||
| f43c9e5d67 | |||
| 22387e8e60 | |||
| 9284af351a | |||
| 07cbd3c031 | |||
| 1d03d171e0 | |||
| 1abb783f4c | |||
| d37c809973 | |||
| 0feffda7f3 | |||
| b5bfbfaff6 | |||
| 25a4171631 | |||
| 8622aa787a | |||
| dd44a34e18 | |||
| da91e7de1d | |||
| c32798cbb0 | |||
| a03754d02b | |||
| a9351b29ab | |||
| 84a27b504d | |||
| 91e2432b48 | |||
| 505da678f0 | |||
| e0b44bf41c | |||
| f856ff5957 | |||
| 65fdb90ccb | |||
| 82372dc33b | |||
| 14fb79b90c | |||
| 050c7f9d86 | |||
| 6efd3a3239 | |||
| f1c0888309 | |||
| 1e9ade68f7 | |||
| 58a0fd8fdb | |||
| cd523bd552 | |||
| 22f68d098c | |||
| 5d3657938d | |||
| f2002ff1ce | |||
| 49600213b7 | |||
| 4d87edb1fd | |||
| b536f263f2 | |||
| 65c1300c63 | |||
| f1cc12eea3 | |||
| 0c5dd84c27 | |||
| df8753e1c4 | |||
| eb9dba3bc7 | |||
| 86247e4a61 | |||
| fc46584735 | |||
| dab87d46fa | |||
| 1968f4b7f3 | |||
| 3b1556f931 | |||
| 249332848c | |||
| 26058934cd | |||
| 11298d26e7 | |||
| 394d558707 | |||
| 058d55ea82 | |||
| 903109f8d5 | |||
| 4876abb0ed | |||
| f75490aec2 | |||
| b2e3ae684d | |||
| 5b4f5e0ef8 | |||
| 5fb6f7dbb2 | |||
| c8e32fd968 | |||
| 15f4f58164 | |||
| 291410cc1c | |||
| dd9d6cc452 | |||
| 8866d7f71e | |||
| 83bcd89c0c | |||
| 0a2160e18a | |||
| acab1d89aa | |||
| 42176d334e | |||
| 5db3563400 | |||
| 50f26101cb | |||
| 20915963f8 | |||
| e0fce2c2bf | |||
| 069340ecd1 | |||
| ca5a34e09d | |||
| 08fe5e8f83 | |||
| 12623fd383 | |||
| d52bd00ab9 | |||
| 11963ef040 | |||
| 03ce6f80a1 | |||
| 42ea33612d | |||
| 1cc0c51390 | |||
| 62740ffcb6 | |||
| 727616c764 | |||
| 1b6fd03ba3 | |||
| 53bb1dee01 | |||
| 467950ae2c | |||
| 5248ad3b6a | |||
| 3e41af7f41 | |||
| c01a9c1140 | |||
| 36def0a511 | |||
| 077f768d09 | |||
| c2eafeb9a4 | |||
| 526538a2a4 | |||
| f84b3a6be1 | |||
| 78f3b286ad | |||
| 83246b49dc | |||
| bb2ac7753f | |||
| 8120b06403 | |||
| 03575b169c | |||
| 5932c7b0a7 | |||
| aac03abf14 | |||
| e1e51131fb | |||
| cb5747a2fb | |||
| d5c8df3d1b | |||
| dad84e1d5a | |||
| 4ad03c196c | |||
| 7168f5391d | |||
| 2c5a21ec2a | |||
| e80af77b8d | |||
| 2ef43e821c | |||
| 42e6b88220 | |||
| a4a280ed34 | |||
| 94c3f0e4aa | |||
| 52783ccefc | |||
| 1926236d0b | |||
| 446ee1d145 | |||
| 5fb5f10d9a | |||
| 6da8d873d3 | |||
| db23aecad9 | |||
| 31bd279b4b | |||
| 8b2d249ea6 | |||
| ab817169e8 | |||
| 408e44636e | |||
| 6145092086 | |||
| a038fae17c | |||
| 779b844138 | |||
| 3fe52c36ef | |||
| fa0c843126 | |||
| 6e0047c632 | |||
| 66d2ae99a6 | |||
| b636bed83b | |||
| 16fc9c0b09 | |||
| ee3b06d4aa | |||
| ccc367a376 | |||
| 054d0c74fc | |||
| 5d9554a46d | |||
| 47a77a5085 | |||
| ef3854ae8d | |||
| 9b0a95aa54 | |||
| 26bc1299ff | |||
| 74c9cfc5b6 | |||
| a930a795db | |||
| 0a5e201936 | |||
| 0989a27fdb | |||
| e9a8b80476 | |||
| 36b0676bfc | |||
| 8702440474 | |||
| 3413100602 | |||
| 882f5bc28e | |||
| 1ffb36e1a3 | |||
| b02ded094f | |||
| 36d9f9100c | |||
| 83d695ee94 | |||
| 4d76cf46f9 | |||
| fa5a1daf68 | |||
| 4563261c52 | |||
| ab5f323159 | |||
| 17aed59317 | |||
| 788817f485 | |||
| 8dfe0cd068 | |||
| 2674ba9d99 | |||
| c7c74de382 | |||
| 60c5b9cb9d | |||
| 5c309142f3 | |||
| 098c4f7f3c | |||
| ac5deca5ae | |||
| 82d4c1c94a | |||
| 9118119901 | |||
| 02d61989fd | |||
| eb826dc612 | |||
| d5dd930932 | |||
| 04ebf421a1 | |||
| 93d9a2ebc1 | |||
| b7697742c6 | |||
| a21543ff79 | |||
| 218f234a18 | |||
| 815d895729 | |||
| 6c4bdef80d | |||
| 6cd801287c | |||
| dd7b93615d | |||
| 682b57597a | |||
| 2de0b6311f | |||
| d3195411bb | |||
| e0527b00d5 | |||
| 9d27c3cac4 | |||
| 8e681a9639 | |||
| 48ade5861a | |||
| 28e55fa01a | |||
| 64288af285 | |||
| 27f9f88c37 | |||
| 32da86ec5c | |||
| da440cdea8 | |||
| 6c651cff01 | |||
| a153e18059 | |||
| 48275aff5f | |||
| b5747cab84 | |||
| 5d22031a32 | |||
| 340123aec2 | |||
| e1827395b5 | |||
| bfb6940402 | |||
| f7c096cd9d | |||
| aa15ce42ce | |||
| cebdc97b83 | |||
| 3cfdbca8f5 | |||
| 0645c32a45 | |||
| 2a985eb6aa | |||
| 647bc29ef1 | |||
| b9a074aceb | |||
| 8207e510dd | |||
| 1348a58175 | |||
| 4b5b2fd3bd | |||
| 8bb852e2ff | |||
| 51b3c0d789 | |||
| 5e7a5a4a38 | |||
| 65a4de0e33 | |||
| b5d8e1cd2e | |||
| c11aede298 | |||
| 0db8171898 | |||
| a24482d9b3 | |||
| 7662fe3645 | |||
| 0950fe64cc | |||
| b25e85ddb1 | |||
| deedd0d413 | |||
| 07a7908486 | |||
| 1eea91a6d0 | |||
| 3fbba5d164 | |||
| 30295699b6 | |||
| 37ca59a1e5 | |||
| 6b0e854f26 | |||
| 7ad972dd23 | |||
| c2168eaf02 | |||
| 60625a7bff | |||
| 43ee952763 | |||
| 8720c63f63 | |||
| 6778142d62 | |||
| e6b6e00bf2 | |||
| a91cee40ba | |||
| c03b6521d5 | |||
| c33ff5fa20 | |||
| 281d98edcd | |||
| 7b84e36387 | |||
| 71a122b671 | |||
| f113328619 | |||
| ad9d8259e6 | |||
| 75834b7668 | |||
| 6ac86c9ce6 | |||
| 8e3b5ae664 | |||
| f22d8b5a47 | |||
| 2260a72c1d | |||
| 4ead5238bc | |||
| 851f6f1940 | |||
| 63f69a6bd5 | |||
| 01800715f8 | |||
| 157b1b8d8b | |||
| ffcd191135 | |||
| 769097544e | |||
| adc93021e7 | |||
| a3f5b5c2c0 | |||
| c08a312111 | |||
| 3c71d9ae93 | |||
| fe8205adae | |||
| 75c332ade1 | |||
| e0202ccda5 | |||
| 275da32584 | |||
| 2f6f508a56 | |||
| 9b7e8841c4 | |||
| 48653665b3 | |||
| 5e1a68de63 | |||
| caa9dd4db4 | |||
| cb891bc063 | |||
| 2ee3adef14 | |||
| 53618e0117 | |||
| 3cdc76b548 | |||
| 7c6a2e9767 | |||
| c44aa52f5f | |||
| 7f6efad8c8 | |||
| f9d82d163f | |||
| b56ecfbf8f | |||
| 42d0f3cf74 | |||
| 27c0b4c497 | |||
| de1558d58f | |||
| 0197355126 | |||
| e66698d2bd | |||
| def5996c49 | |||
| 700fd2e390 | |||
| 21a8eaafeb | |||
| 4391891999 | |||
| 8302e8b5e0 | |||
| a8de52d5cd | |||
| 46a42c9212 | |||
| 9ed97ea32c | |||
| 4f087cdcc7 | |||
| 4c4fcba2d2 | |||
| 69e9bfa7a9 | |||
| c3b29697bc | |||
| f0937e8d1e | |||
| 85f713dc2d | |||
| cd146366c0 | |||
| 08054ad6e5 | |||
| 011b4b536a | |||
| d2e118180c | |||
| 93856925ba | |||
| da0a33798b | |||
| 33f4f2e60b | |||
| 5827583edc | |||
| 2b33d95329 | |||
| 7f0be97170 | |||
| b6a0fa9196 | |||
| 52c624e94b | |||
| de847ac0d5 | |||
| 2bb579fec7 | |||
| 6a6b15fb14 | |||
| 81e6778148 | |||
| 309a6a6425 | |||
| 65e5ca64a1 | |||
| 69825d33ff | |||
| ec4acd0043 | |||
| 22bb168e49 | |||
| b7bea01eb1 | |||
| 82c3591d25 | |||
| 20d8de32ec | |||
| 3976646f39 | |||
| c849d4e0b0 | |||
| 671fab2fee | |||
| 8491609da7 | |||
| 67257748f9 | |||
| 312a3fe7bb | |||
| 2c16c54c96 | |||
| bbae5f0b9c | |||
| 95022da700 | |||
| 6471e95077 | |||
| 707e6f5d11 | |||
| 66dfcc8064 | |||
| 0400b7d396 | |||
| 96d4ca43ff | |||
| d2c0699b66 | |||
| 0e4cf2cd3a | |||
| 8144a7e857 | |||
| ea38698ac3 | |||
| d00b34ebdd | |||
| a4c285df6f | |||
| 6dfd9d5b7a | |||
| 876f7317a8 | |||
| 430a975e98 | |||
| f277319019 | |||
| 6b9fedd289 | |||
| d0ad48ada2 | |||
| a6b7beed75 | |||
| fa257e4a04 | |||
| 8d827b7275 | |||
| 27d73b545c | |||
| 7802d961a3 | |||
| d5d63371e3 | |||
| fcf1d38578 | |||
| fe17f817da | |||
| bfa76c0fda | |||
| 2e1a99f905 | |||
| e7cb8e41b5 | |||
| f88d4bde45 | |||
| b470194807 | |||
| ba5e3cb3eb | |||
| d5440b5d01 | |||
| a8f3f27fb3 | |||
| bec06bfbf4 | |||
| 9c510dc132 | |||
| 8302c99d57 | |||
| 5209e5b463 | |||
| 663e5124fe | |||
| dea2f569a1 | |||
| 03d25eaeae | |||
| e84f56975d | |||
| a3a21efba3 | |||
| 1daa4f91b3 | |||
| ee1ddbcdce | |||
| 772549e543 | |||
| db537e756a | |||
| f9c236fd63 | |||
| f414ecee32 | |||
| 5b1d0d5821 | |||
| 1c80ba56a5 | |||
| a92044f815 | |||
| 00f94bf950 | |||
| e27f061a92 | |||
| 40d28948e1 | |||
| 9b6e29d5f2 | |||
| 0ee000f08a | |||
| 6bdd021856 | |||
| 301e14268a | |||
| 825ea594f4 | |||
| 8fcb072abb | |||
| f17a4e6372 | |||
| a5b1202e5e | |||
| b5e025984c | |||
| 33dba4e9bf | |||
| 92492b21ae | |||
| 1c8ca4b8c2 | |||
| 466061222d | |||
| 905e229142 | |||
| 6906b96ef9 | |||
| fb748df3ce | |||
| 844de786d0 | |||
| 7dfe55014a | |||
| 24f19e2a61 | |||
| f947040241 | |||
| 569bb61545 | |||
| 78ea8b3e73 | |||
| 6b5056da41 | |||
| 2a86546f1a | |||
| d669fec902 | |||
| 3fc14b5194 | |||
| 4a3a039d0e | |||
| 1f43523f04 | |||
| 26e23fa736 | |||
| 958bce8d42 | |||
| 8f15e52eb5 | |||
| 4bedede646 | |||
| f66ee1721e | |||
| 138c5bb4c2 | |||
| d1245a9a1e | |||
| 561d6f7ea2 | |||
| d5992f7ed3 | |||
| d941aa0c71 | |||
| 7fa1d1e11b | |||
| 3edff028bf | |||
| 78d3c529c6 | |||
| f0af2e280b | |||
| 34623163e6 | |||
| c90bd007c7 | |||
| 5f9637ec50 | |||
| 1a05e13b03 | |||
| c835f88695 | |||
| 5674fe76a2 | |||
| e6933b4ded | |||
| 8a10dac03d | |||
| de71ebad52 | |||
| 310d1a2d5c | |||
| 30fcaf190b | |||
| f004b15cf0 | |||
| 480c91feb5 | |||
| 2c70b7eefc | |||
| 2be2513081 | |||
| 48c0d5d2cd | |||
| 3c5a6bcdec | |||
| bd2a3d529a | |||
| 6c0ac67cfa | |||
| cb07b8c9f4 | |||
| e22be3f233 | |||
| fd02f120c2 | |||
| 6496b3dad6 | |||
| 375b57cd3d | |||
| 269265b054 | |||
| d74154080b | |||
| 7471825a7c | |||
| 90580316e8 | |||
| 61e0ef2960 | |||
| 1125bb9b4c | |||
| 1e424a3791 | |||
| a901d95895 | |||
| 1a0a92c542 | |||
| 6ba8344292 | |||
| 38d2429183 | |||
| 36c755f781 | |||
| 093c731ba7 | |||
| eae9c11d72 | |||
| 3faae4b34c | |||
| 04eef35cbd | |||
| 6b08cb2159 | |||
| 0777ca90e0 | |||
| 4a322d07d9 | |||
| df49f98e46 | |||
| 122e3f6aa0 | |||
| b902837b1c | |||
| 62639a9c79 | |||
| 06dc7fc566 | |||
| ece6e099ec | |||
| f3ce82275a | |||
| 4000dd8383 | |||
| d67053ce7c | |||
| 37bca1ee1c | |||
| 229d3e9c88 | |||
| c5d79a014b | |||
| 7d609b9c2a | |||
| 97eabcc600 | |||
| 932863a73f | |||
| 4014fc27af | |||
| fdf7be4a9f | |||
| b0fd801fec | |||
| 34c0bbe434 | |||
| 92c5697565 | |||
| 445759e511 | |||
| a5b32cc099 | |||
| 7a5f24bfe7 | |||
| b40d58f1ae | |||
| ef28fc3616 | |||
| 80d2e2c488 | |||
| ca07f10c9d | |||
| 8a7fa127ba | |||
| 8ee6039a2b | |||
| aac58029f6 | |||
| 640a8d4e0f | |||
| 9f621696c1 | |||
| a45fff7cca | |||
| 8ba45deac9 | |||
| 0c9f741847 | |||
| 696f862633 | |||
| f85e3c2602 | |||
| d2e3635034 | |||
| 8f37cbdfde | |||
| 3ffd6f74f1 | |||
| 72aa1474d3 | |||
| 3f9fb27642 | |||
| 6d134edb0a | |||
| 7834e9d55a | |||
| 36ba95e2fd | |||
| 00deba962e | |||
| 4713594c7e | |||
| 688a169e4e | |||
| 3ace50b526 | |||
| a9dbb4850f | |||
| 910cda8dbc | |||
| 7d29c0d883 | |||
| 3f274cb4ea | |||
| 56d378b6dc | |||
| 03eebf2c07 | |||
| cf41572db7 | |||
| a2361254da | |||
| 233f786ee0 | |||
| 8590614272 | |||
| e179de3d0d | |||
| defe3bb3ff | |||
| 24ad3e0265 | |||
| e54646afcc | |||
| 4c62032c66 | |||
| 627affe0f7 | |||
| b5e21bef1e | |||
| 95999791bd | |||
| 07cba611cf | |||
| 29c2dfc1e5 | |||
| 6b904b9213 | |||
| 7e15307b46 | |||
| 626913c6ff | |||
| 00b98e4da9 | |||
| 67f565bee0 | |||
| 9eedf46294 | |||
| 810783da9c | |||
| 39dfe334ed | |||
| 1a985f2a7e | |||
| 35af46e3eb | |||
| 3eefadd83b | |||
| 0fbbd79bbd | |||
| 84eee14363 | |||
| 8f7ce5d148 | |||
| 5ed2fa4a0c | |||
| e5a06f7a3f | |||
| f0ef1c7a76 | |||
| 76ea9a4ba4 | |||
| 33454005c3 | |||
| 37b6e6bce0 | |||
| aaa9aab066 | |||
| e8669cc0cf | |||
| ddb226823f | |||
| 76eca47979 | |||
| bcac6944a0 | |||
| d9aa1c428d | |||
| 85c779ecd2 | |||
| 87a67470fd | |||
| be4142ad96 | |||
| 5a26f7735d | |||
| 11ec77ad99 | |||
| 2da4182ee1 | |||
| d17ad6a497 | |||
| 1abc0ecc79 | |||
| 51ee8c841b | |||
| 0636d2276b | |||
| bffee14882 | |||
| 93f2ed3a09 | |||
| c7b0ed26ae | |||
| e75ade83cb | |||
| 3e4f5d6361 | |||
| 999bc9f720 | |||
| cca068821b | |||
| 6d05a00488 | |||
| ba3450f2b3 | |||
| 57c084d512 | |||
| c956f35e07 | |||
| c44353fa13 | |||
| 8ebdc924f3 | |||
| 3923dd377d | |||
| 82eea64035 | |||
| 10229e59f6 | |||
| 8c2583eab3 | |||
| f9ef4851fb | |||
| d07b99fd98 | |||
| b23ce2adc3 | |||
| c4f2899e07 | |||
| ebb20f5c38 | |||
| 08aaae1b02 | |||
| 4aaef11f9c | |||
| 2d0d253149 | |||
| 875c0b8c16 | |||
| 3e285a4466 | |||
| 76e91265d5 | |||
| 47482ba793 | |||
| 685c38dcf7 | |||
| 240d97cdd5 | |||
| cd891d4378 | |||
| b9c05483d0 | |||
| 190c534dba | |||
| 5cc13d8161 | |||
| 81ac870c62 | |||
| 9eab5c3d4c | |||
| f4a4ae7eb3 | |||
| 4b2715e97d | |||
| 983e546a64 | |||
| d7161578b0 | |||
| d8683068c1 | |||
| efcea45819 | |||
| 28f89aa0ad | |||
| 309d42fdc1 | |||
| f8f45182ce | |||
| 5f08dee0e0 | |||
| deea0f3f83 | |||
| 2090c5950f | |||
| 02dcbdba02 | |||
| ee44b1986f | |||
| 16bc7b1e75 | |||
| 65bc06b195 | |||
| 06734d6274 | |||
| e1dcd72a79 | |||
| 3429a27354 | |||
| 7af99a5ed5 | |||
| d7833cd07f | |||
| a9b885c97f | |||
| 5eb815dba7 | |||
| 9797841280 | |||
| a2382be034 | |||
| 081ce01664 | |||
| eddb8a933c | |||
| 7a019cc465 | |||
| 08e8846af8 | |||
| 67d6cc6f05 | |||
| 1946478ce4 | |||
| 5689cdbafe | |||
| 44adfdede8 | |||
| 2992e3ca64 | |||
| ffbbd44beb | |||
| 3990515dc5 | |||
| 2bd218fd95 | |||
| 1a02239dd2 | |||
| a5a5e38d5c | |||
| 9ebf2be016 | |||
| 3e488d28cd | |||
| ce311d9b17 | |||
| 843a263b3f | |||
| 7e350cac41 | |||
| 447b7b35ef | |||
| 6e9edabd94 | |||
| 68cfdc57c8 | |||
| 81e0f1d9cc | |||
| 5436775b31 | |||
| b8f5c2ddbd | |||
| da433bfb5b | |||
| 50209aa6ed | |||
| 665fbb0f6c | |||
| fd0921870d | |||
| 568ff5cb1e | |||
| 0cc78b1055 | |||
| 6dc3b5c382 | |||
| 9ac373bf0e | |||
| 02f96f9083 | |||
| c74997f306 | |||
| 58d4f22a6b | |||
| c5cf1c168e | |||
| 36638a63ca | |||
| 07de30ceea | |||
| 35e15263b0 | |||
| 420867378b | |||
| 0cc183df22 | |||
| eb557ca9bd | |||
| 72b39a5982 | |||
| b96ee6bc19 | |||
| 684fa318ec | |||
| 29faea14c6 | |||
| c25f7a13db | |||
| 715edd77e0 | |||
| 25cc825ea6 | |||
| f7e7819b84 | |||
| d305315d7e | |||
| 965d756cba | |||
| 29a19b5df6 | |||
| cb2cdd98e8 | |||
| da79a972f7 | |||
| 3c13eff2cf | |||
| 7050070310 | |||
| 1dca4e8c0a | |||
| 1163e04aaf | |||
| 73bc256ce6 | |||
| df78db5686 | |||
| b64ceaf5d4 | |||
| eb9b4cd132 | |||
| b9eec94644 | |||
| 4e388ec3d7 | |||
| a5069789b3 | |||
| 3797fd85ad | |||
| f0b0423872 | |||
| e5daf1d29f | |||
| 2b9f40a976 | |||
| 05fbf28d2b | |||
| e54d06def9 | |||
| 840eff3cc4 | |||
| a0737d0010 | |||
| 9d93df888e | |||
| 90fbb235c3 | |||
| 9be884c672 | |||
| 550a4cdecf | |||
| 0d883b76fe | |||
| e3c3101cab | |||
| cce289253d | |||
| 2102dd729c | |||
| 347a83cf0f | |||
| 1f8d573fad | |||
| 72b6c2a176 | |||
| 743e3660e9 | |||
| 2ab6a49bec | |||
| 1e31e13384 | |||
| f77fbe680f | |||
| 53c55a3f36 | |||
| 18d11e3421 | |||
| bf42834051 | |||
| ee6337276c | |||
| cdc001b43e | |||
| f3eeaddec8 | |||
| b8e1e4e21c | |||
| 64f2c83894 | |||
| f9211e17a1 | |||
| f0c952848a | |||
| c736068d0e | |||
| e0c9d43f02 | |||
| 0a4b657a85 | |||
| 0121d9601c | |||
| 371a450f5a | |||
| 2796145d26 | |||
| 5a662ac72b | |||
| 6cd62cbd0a | |||
| 299fa1a107 | |||
| c39ba2e17e | |||
| 414b5b3861 | |||
| 6f89f4acce | |||
| 5f09fd1fa3 | |||
| 00f1b0e8a3 | |||
| 4473d0f787 | |||
| d5255f91d0 | |||
| 57a3479144 | |||
| 82c4ebf375 | |||
| 23ca884684 | |||
| cdfa999b05 | |||
| 224092b30a | |||
| 8daefb2e42 | |||
| c0c0ef979d | |||
| 6f0738cebb | |||
| 3c352921bb | |||
| 4df8f18cc4 | |||
| 120acdefc6 | |||
| 7eb31085b0 | |||
| 17a3446be4 | |||
| d713c67c9b | |||
| 76d788ee66 | |||
| 1cf13fc2a1 | |||
| de08d4d32d | |||
| dce3a91156 | |||
| 38bf17c932 | |||
| 5d0ccb9a34 | |||
| b557afde2c | |||
| ea9375c20e | |||
| fa464a9f1d | |||
| b3ff6ea991 | |||
| f9dbdd4aa8 | |||
| 21d06d97ef | |||
| fb28a49537 | |||
| d124504d5b | |||
| 0c69e0c5e5 | |||
| 39aee1ce89 | |||
| b3fe87b79a | |||
| 2dfdc17523 | |||
| c208e7f72d | |||
| 8722d0a65b | |||
| 54f044dfa0 | |||
| b854a6dfef | |||
| badb99da59 | |||
| 30d99dbe54 | |||
| c44c4e8b2d | |||
| 656b2f469b | |||
| 39e17842cc | |||
| 57f7c0bb31 | |||
| 76b03fa68b | |||
| c99d6fb16f | |||
| d29ccc0aca | |||
| bf51be498b | |||
| 6d941975e2 | |||
| 0e075d28a5 | |||
| 4b5e6b574f | |||
| fc79581f8c | |||
| 6176c47e2f | |||
| 9abe0eb158 | |||
| 4d7cedb8a6 | |||
| 2b02fe06ac | |||
| cd5f530fc6 | |||
| b9085c7091 | |||
| 679ee71f89 | |||
| 536f0e038a | |||
| b087e35b30 | |||
| db3df649ce | |||
| bb708277b1 | |||
| c3b694dc6c | |||
| b9ff0b1c88 | |||
| 52be8db71f | |||
| 0e791133dd | |||
| b4f760d69f | |||
| 9bba3c9560 | |||
| bcd61e87d3 | |||
| e8c0e523e6 | |||
| af9e9a87b4 | |||
| 2d1bb6435f | |||
| 5680b8508d | |||
| df0e9197dc | |||
| 79964160ff | |||
| 0d46554b66 | |||
| 2c674896ff | |||
| 3ce1f28ae6 | |||
| 5ef145ed47 | |||
| b478cd6812 | |||
| 7e86187132 | |||
| 58b7a9515f | |||
| 370b2122aa | |||
| c6f1a7d212 | |||
| c04e425550 | |||
| 19543d7d29 | |||
| 12af602066 | |||
| 000515cda7 | |||
| 645e5a94a6 | |||
| c2f69eb03d | |||
| 93a9c41bee | |||
| 02dffc6e22 | |||
| 2658b7ca93 | |||
| 8c3335a7bf | |||
| c0e7b8e3ee | |||
| 9ef3d65aa4 | |||
| 8d188d4798 | |||
| 7bfc84c156 | |||
| 18bc47efe1 | |||
| 4593952cc3 | |||
| 1d3e30f8d3 | |||
| 6fef655e44 | |||
| 552b81c558 | |||
| 6c9a4daf9b | |||
| fbc46c54c4 | |||
| bc7aaa8b08 | |||
| 95af9902e7 | |||
| f340a13212 | |||
| 3d8f17d641 | |||
| 68f7b0f20f | |||
| c3a3060b92 | |||
| c01b96298d | |||
| 26655da185 | |||
| 9d0345303a | |||
| 33d02a0b2e | |||
| f301ab694c | |||
| baa6c0db3c | |||
| d118f54bd3 | |||
| 4a7384d371 | |||
| 6a91b8ae0f | |||
| b5fddfbbd0 | |||
| cfa3ceaae7 | |||
| 7a8f75abfc | |||
| 3db70fcbbe | |||
| 7b74d9fe47 | |||
| 553c211f24 | |||
| 3b153f5967 | |||
| 926b2d070f | |||
| 3e37731d84 | |||
| 24b5b81279 | |||
| 0534294b82 | |||
| a314404b61 | |||
| 71b81b2255 | |||
| c8cb61436e | |||
| 1006bf25c1 | |||
| cb6f03231e | |||
| 8ee2308ee1 | |||
| 719dbeef76 | |||
| 4c34333956 | |||
| bff677d607 | |||
| ba1461c874 | |||
| 7a0e885444 | |||
| 72d4ab6db5 | |||
| dfd6b61123 | |||
| 352d7d032e | |||
| ae6ba7832d | |||
| 9d63a6d0c4 | |||
| e905fb366e | |||
| 27b325f7d9 | |||
| 5c2f8c60dd | |||
| 3ac5905994 | |||
| 0e460b0778 | |||
| 4eea5b99d6 | |||
| 34c60d09f6 | |||
| 48e1ee4e7b | |||
| 46863d09a2 | |||
| ade08dcbee | |||
| e9a381068e | |||
| f5a068937a | |||
| c2bc52e474 | |||
| cd4ce2aa6b | |||
| 257e82e825 | |||
| a705f0ec53 | |||
| 46699a05ce | |||
| 9fd1855daa | |||
| 9a96fffd18 | |||
| 00d6f5e4b1 | |||
| a3adb87a6a | |||
| d0c01f1873 | |||
| 725d0b217a | |||
| 1958c6aefb | |||
| 05be092d69 | |||
| 40fccea23a | |||
| a022526e7e | |||
| 765b4c3afa | |||
| f704a29b38 | |||
| 309bb98036 | |||
| bf7b0b0a82 | |||
| 98629c5e85 | |||
| 461acbd376 | |||
| e0b70b26f3 | |||
| 4a831f4cb9 | |||
| b58bbbe705 | |||
| dc186e2e6b | |||
| 44deb59624 | |||
| 886007eae5 | |||
| 27fc39cb70 | |||
| 5480caf44e | |||
| 877ecbaef1 | |||
| 434bfde292 | |||
| 40c55e716d | |||
| a448a974f1 | |||
| 1738fac5fd | |||
| 7b74318ca5 | |||
| 19e394abb8 | |||
| 6dabbe19dd | |||
| 7b95d991d4 | |||
| e286be7f1e | |||
| 4214c08e76 | |||
| 180c49f9d3 | |||
| ef040f68c7 | |||
| 65e098e1c8 | |||
| 3978ab95f4 | |||
| b134d077cf | |||
| d537cb2383 | |||
| dba866e5c9 | |||
| ce36dd4012 | |||
| ea2b9ef4df | |||
| 69fe3b3d76 | |||
| a34b101a05 | |||
| c134c4bf9e | |||
| b0fe7595da | |||
| 6a7ef44bdd | |||
| 633acb9236 | |||
| cf84205571 | |||
| 5aced2c03c | |||
| 6cfa949493 | |||
| 4131396117 | |||
| e5f8d959ed | |||
| 6f0c9e0b59 | |||
| dcfe3dee0e | |||
| 8348568ea7 | |||
| 1d5dece894 | |||
| 051e0751a5 | |||
| 64594c4457 | |||
| 5f19f55e03 | |||
| da6cfdc4e8 | |||
| c2274d6b6f | |||
| adbdc55bc4 | |||
| 165059ca2d | |||
| 6c1da15ae4 | |||
| ecf05bcd00 | |||
| 3baec32ff8 | |||
| cb95204fac | |||
| 89e05d1a29 | |||
| 41b940a8e9 | |||
| 3d8d612897 | |||
| b3297e3fcd | |||
| 9f00cab409 | |||
| e8a795f97b | |||
| c8c93cac6e | |||
| 96c233ebd0 | |||
| 36ef13b237 | |||
| f54fdd6016 | |||
| a43947077a | |||
| a863b7be13 | |||
| ab1ce8e179 | |||
| d391ab20b7 | |||
| 8403bc3a64 | |||
| 038e736eb1 | |||
| a215192175 | |||
| 22a1895050 | |||
| 2df42c772b | |||
| e68e47e132 | |||
| 72f9e8ed79 | |||
| 3a2c67152e | |||
| 82fea04460 | |||
| 6ccd70dad2 | |||
| ec2d14bffe | |||
| 1d544ff558 | |||
| 867cd29e0f | |||
| d1cf660af6 | |||
| adabe3a227 | |||
| b57ef6c3b4 | |||
| 1b50823843 | |||
| c4c499532a | |||
| 18ddad522a | |||
| 85b034ecfb | |||
| 5a04749ef2 | |||
| bcd32dde85 | |||
| 7832cb810b | |||
| cb652721a7 | |||
| 4ad005fb53 | |||
| ce312aea72 | |||
| 6c5dc556e8 | |||
| 95dc18f1d0 | |||
| f284cc8676 | |||
| 0cc456c4a1 | |||
| 0666146374 | |||
| 5860ca720e | |||
| 91ee8362ba | |||
| d8f043ad71 | |||
| 1706ead392 | |||
| dd81460826 | |||
| 5180916d9f | |||
| 4d92ddcc75 | |||
| f1f0900e13 | |||
| 6edf68d03c | |||
| c643ae507b | |||
| fdc843a93a | |||
| 383c06c72a | |||
| a255ce3e36 | |||
| fa58e820c1 | |||
| fad011e2fc | |||
| 9fad040e14 | |||
| 8d0ab82f15 | |||
| 3d7e994b93 | |||
| 4d40c0f431 | |||
| d9bb60e66b | |||
| 52433ba347 | |||
| 4290846698 | |||
| 6bbd7ec00d | |||
| dc535ddb38 | |||
| dfe087e702 | |||
| 930e0b92eb | |||
| 3199bc6118 | |||
| b1384375a3 | |||
| 81dd98cefd | |||
| 02108b3273 | |||
| c5deb87c23 | |||
| 572274a2e3 | |||
| 7f303b362d | |||
| 41ce6cce05 | |||
| f6e1c55749 | |||
| d24bcf8e6e | |||
| 2b497ff679 | |||
| 627c20f6fd | |||
| cfab918bea | |||
| 89746203fe | |||
| 8bc6947c94 | |||
| 5a264804da | |||
| 1f5e025fea | |||
| 3201e220a0 | |||
| d41129011b | |||
| 6eb1aefb1c | |||
| 433646b455 | |||
| 257e7d1d27 | |||
| f668d6492a | |||
| b8ea968a58 | |||
| 5b361afc67 | |||
| 0947cd1e24 | |||
| f8ab1f108b | |||
| 84f53bbf81 | |||
| ad2656a24b | |||
| 4734fbd651 | |||
| a947755383 | |||
| f4a1283073 | |||
| f37a2c5b24 | |||
| cca7d770f1 | |||
| 2c7f3f2321 | |||
| cc92e025f2 | |||
| ce0e28dad6 | |||
| b483f7cdb6 | |||
| 8ce0694099 | |||
| 910b356a05 | |||
| d74e0310f8 | |||
| ee19879577 | |||
| 5e3d7d2f2b | |||
| f292eb0fc6 | |||
| 475de2281b | |||
| 949c8331d2 | |||
| a5e0fa8402 | |||
| f0066b3dac | |||
| 10480a533c | |||
| d36dcac817 | |||
| d6d49ac7ad | |||
| 573e127fc7 | |||
| 9cb6e599a4 | |||
| f42dd1013e | |||
| 70441658e5 | |||
| 0ca71f25f6 | |||
| 5d3a4e24f9 | |||
| 3b8faf47c4 | |||
| ac21776d3b | |||
| e5127c9040 | |||
| 8533d06943 | |||
| 066dd6103f | |||
| 670f9c280c | |||
| 5ea3c58b77 | |||
| 6e15571ef4 | |||
| ad46fced4f | |||
| 5acf42423e | |||
| 2a2bef8a47 | |||
| 2ffb0f59a2 | |||
| 400bdaa6f5 | |||
| fa449966f3 | |||
| f4078493f6 | |||
| 5007f7e83d | |||
| ca1a8e15cb | |||
| b9f299805f | |||
| acde49012f | |||
| 76c69f0d19 | |||
| c0b91b4a63 | |||
| f6a194ae92 | |||
| 9e7d178972 | |||
| 17b2e2dca7 | |||
| eb73bcd25f | |||
| f96c090120 | |||
| aefdaee424 | |||
| 27ceee37c0 | |||
| e1c2e3c984 | |||
| 48e3718fc2 | |||
| ee20f65a9b | |||
| 235a13855b | |||
| acec42c6af | |||
| 6d009eddf5 | |||
| b0dde281ea | |||
| 1e7d43bc72 | |||
| 8576a1edaf | |||
| 5dc97d2191 | |||
| a32b45e067 | |||
| ff8210c72b | |||
| 85031e89b6 | |||
| f2676532ce | |||
| 7a996ee8f4 | |||
| d09e28d653 | |||
| e446f4190f | |||
| f53534b803 | |||
| fb6792f71b | |||
| 5d66d55db1 | |||
| d3bdd48425 | |||
| c89f675ccf | |||
| f0b989d20e | |||
| 3b950b6b28 | |||
| d10a0f956e | |||
| 2317228642 | |||
| 78a4571a8a | |||
| c7b16ce91b | |||
| 2e84aeaccf | |||
| 49e9a532b8 | |||
| 47f7d70cfb | |||
| a3b03efcbe | |||
| 814d4faf3e | |||
| c487dc2f03 | |||
| f552a06bd7 | |||
| 4de5593802 | |||
| 4294e9f98d | |||
| 05a911f1e3 | |||
| 464f8d7851 | |||
| 370b07be31 | |||
| cb49c71279 | |||
| f637fb9596 | |||
| 5c8072cc9e | |||
| 40cd057c28 | |||
| 0bcd37c1f1 | |||
| 6fce6fd80b | |||
| bc13a6056d | |||
| 00879964e4 | |||
| 64711d6175 | |||
| 0d3704f55d | |||
| 0856eed7fc | |||
| 8efaa9e724 | |||
| 98983ff4eb | |||
| 0ae36ed7a7 | |||
| 8e8b20c3dd | |||
| 82e2aa45c6 | |||
| e4be47e7e7 | |||
| 404c605a1e | |||
| 4966d85634 | |||
| 043eebf013 | |||
| 3b521ddd08 | |||
| bd74d3a1a3 | |||
| 0dc867ce64 | |||
| dde08e2d67 | |||
| 3c5871526d | |||
| 49f4ba2da8 | |||
| 77b660576a | |||
| a15ab62f03 | |||
| c65250973c | |||
| d5872aad55 | |||
| 9d27bba6fd | |||
| caeecce50b | |||
| f6c82dd767 | |||
| f88205f957 | |||
| 3a0a4726b9 | |||
| a113fc1c73 | |||
| 92d122b0a3 | |||
| d96a2d22e0 | |||
| 8d96b9fe7f | |||
| fdf7bdd64d | |||
| 4f4c90f792 |
5
.gitignore
vendored
5
.gitignore
vendored
@ -5,4 +5,7 @@ local.properties
|
||||
# sign.properties
|
||||
.DS_Store
|
||||
captures/
|
||||
build/
|
||||
build/
|
||||
release-app/
|
||||
scripts/apk-channel/
|
||||
app/src/test/java/com/gh/gamecenter
|
||||
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -1,4 +1,4 @@
|
||||
[submodule "libraries/LGLibrary"]
|
||||
path = libraries/LGLibrary
|
||||
url = git@gitlab.ghzhushou.com:client/client-common.git
|
||||
url = git@gitlab.ghzs.com:android/common-library.git
|
||||
branch = master
|
||||
|
||||
89
CHANGELOG.md
89
CHANGELOG.md
@ -1,8 +1,89 @@
|
||||
### Ver 3.0
|
||||
* x
|
||||
# 版本升级备忘
|
||||
|
||||
### Ver 2.5
|
||||
* 此处写本次更新所做的业务和代码修改
|
||||
|
||||
### Ver 2.6
|
||||
* xx
|
||||
|
||||
### Ver 2.5
|
||||
* 此处写本次更新所做的业务和代码修改
|
||||
### Ver 3.0
|
||||
* 升级账号系统(登录流程/用户信息相关/用户账号相关操作(评论,礼包...))
|
||||
* 新增收藏功能(文章/工具箱)
|
||||
* 删除用户相关的所有本地数据库
|
||||
* 重做总开服表
|
||||
* 重做首页插件化模块
|
||||
* 礼包重复领取机制改变(可重复领取的礼包,领取后立刻显示再领一个/再淘一个)
|
||||
* 游戏下载平台面板修改(加快弹出速度,不再读取本地平台图片)
|
||||
* 接入bugly(tinker)
|
||||
|
||||
### VER 3.1
|
||||
### VER 3.2
|
||||
### VER 3.3
|
||||
### VER 3.4
|
||||
### VER 3.5
|
||||
|
||||
### Ver 3.6
|
||||
* 首页游戏增加预览骨架,游戏ITEM样式微调和开服标签
|
||||
* 首页问答增加关注页面
|
||||
* 重构游戏更新管理(游戏更新/插件化/已安装的游戏),具体细节参考PackageRepository & PackageViewModel
|
||||
* 重构APP更新管理(已VersionVode为更新基准,小版本更新改为光环后台控制)
|
||||
- 删除TINKER_VERISON_NAME
|
||||
- tinker打包方式变更(以小版本作为Base包,防止与数据后台小版本更新发生冲突)
|
||||
* 社区增加版主功能(版主可以对存在的相关内容进行修改/隐藏操作,内容包括问题/回答/回答评论)
|
||||
* 社区互动引导优化(问答推荐增加`推荐关注`,回答详情增加一些交互动效)
|
||||
|
||||
### Ver 3.6.1
|
||||
* 可以后台控制关闭资讯功能
|
||||
* 版块、分类、专题详情、游戏详情、礼包详情增加预览骨架
|
||||
* 下载按钮状态可以通过接口屏蔽相应的包
|
||||
|
||||
### Ver 3.6.2
|
||||
* 资讯/问答入口和插件功能线上控制(不可逆)
|
||||
* 首页不显示已安装的游戏
|
||||
* 插件求版本功能增加内部跳转
|
||||
* 下载面板增加公告和版本说明功能
|
||||
* 接入腾讯`广点通`(广告)
|
||||
|
||||
### ver 3.6.3
|
||||
* 社区搜索修改
|
||||
- 增加 `文章/用户` 模块
|
||||
- 增加 `搜索置顶` 功能
|
||||
* 回答详情/社区文章详情修改
|
||||
- 支持文案样式(加粗/斜体/删除线)和段落样式(引用/标题)
|
||||
- 支持关闭评论功能
|
||||
- 回答详情新增上下切换回答
|
||||
* 社区编辑框(回答/文章)修改
|
||||
- 支持批量插入图片(使用知乎Matisse实现)
|
||||
- 新增插入特殊样式,文案样式(加粗/斜体/删除线)和段落样式(引用/标题)
|
||||
* 编辑框部分 JS/CSS 使用远程文件
|
||||
|
||||
### ver 3.6.4
|
||||
* 增加浏览记录(回答/文章/资讯/游戏)
|
||||
* 回答/社区文章 增加反对功能
|
||||
* 社区编辑框增加插入文章/回答/游戏
|
||||
- 低版本兼容方案: 插入的样式默认隐藏,只有在3.6.4及以上才会显示
|
||||
* 游戏详情评分模块增加`小编评论`区域以及样式修改
|
||||
* 游戏评分增加回复功能
|
||||
|
||||
### var 3.6.5
|
||||
* 以补丁方式向外推出,并没有增加需求,只是单纯的修BUG
|
||||
|
||||
### var 3.6.6
|
||||
* 游戏详情:
|
||||
- 支持修改评分
|
||||
- 评分列表增加排序/过滤功能
|
||||
- 增加弹出系统
|
||||
* 社区相关:
|
||||
- 选择社区页面重做
|
||||
- 首页社区推荐增加推荐入口
|
||||
- 首页社区问题模块改版,名称改为全部,去除问题分类(统一为问题列表),增加社区文章列表
|
||||
* 游戏搜索默认页面改版
|
||||
* 权限系统更改,不授权也可以进去App,申请权限细分到功能(用到某个功能时才需要强制授予权限)
|
||||
* 增加隐私系统
|
||||
* 增加游戏预约功能
|
||||
* 增加标签详情模块
|
||||
* 进入今日头条广告SDK
|
||||
* 图片上传压缩机制优化
|
||||
- 支持从后台修改上传配置(本该在早些版本实现,由于代码问题无法引用后台配置)
|
||||
- 对压缩失败是进行catch(由于后台对宽高配置放宽,很容易发生OOM),失败后直接上传原图(这步可能会出现问题)
|
||||
* 游戏相关UI修改
|
||||
58
README.md
58
README.md
@ -1,27 +1,69 @@
|
||||
# 光环助手Android客户端
|
||||
|
||||
### 多渠道打包配置
|
||||
### APK打包配置
|
||||
|
||||
* 使用[ApkChannelPackage](https://github.com/ltlovezh/ApkChannelPackage)的方案
|
||||
* 正式打包命令:请使用./gradlew channelRelease打包渠道包
|
||||
* 打包命令,视情况使用:
|
||||
|
||||
> 打包Tinker基准包:`./scripts/tinker_release_base.sh`
|
||||
|
||||
> 以Tinker基准包打渠道包:`./scripts/tinker_release_channel.sh`
|
||||
|
||||
> 以Tinker基准包打补丁包:`./scripts/tinker_release_patch.sh`
|
||||
|
||||
### 混淆配置
|
||||
|
||||
* 配置文件:Android默认配置+proguard-rules.txt等
|
||||
* 参考libraries下每个项目独立的配置文件``proguard-project.txt``
|
||||
* 参考libraries下每个项目独立的配置文件`proguard-project.txt`
|
||||
|
||||
### apk大小优化
|
||||
|
||||
* 限制resConfig资源集
|
||||
* 开启ShrinkResources
|
||||
* 开启混淆,使用minifyEnabled(仅在release开启)
|
||||
* pngquant对png压缩、png/jpg->webp(未尝试)
|
||||
|
||||
### 第三方appkey等配置
|
||||
* 修改``gradle.properties``文件将各种key填入其中,实现统一管理
|
||||
|
||||
* 修改`gradle.properties`文件将各种key填入其中,实现统一管理
|
||||
* 通过gradle文件内的resValue/buildConfigField/manifestPlaceHolder方式实现编译期间修改,具体情况请参考``./build.gradle``和``./app/build.gradle``配置
|
||||
|
||||
### 拉取代码步骤
|
||||
1. 拉取主项目代码: `git clone -b master git@gitlab.ghzhushou.com:halo/assistant-android.git`
|
||||
2. 初始化公用类库: `git submodule init && git submodule update`
|
||||
|
||||
1. 拉取主项目代码: `git clone -b dev git@gitlab.ghzhushou.com:halo/assistant-android.git`
|
||||
2. 初始化公用类库: `bash ./scripts/submodules_init.sh`
|
||||
|
||||
### submodule管理方式(只拉取master)
|
||||
* 拉取子模块代码:`git submodule foreach git pull origin master`
|
||||
* 提交代码,需要cd到submodule文件夹去做修改
|
||||
|
||||
* 提交代码,需要cd到submodule文件夹去做修改
|
||||
* 更新远端代码,`bash ./scripts/submodules_update.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
|
||||
355
app/build.gradle
355
app/build.gradle
@ -1,56 +1,55 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
apply plugin: 'com.neenbedankt.android-apt'
|
||||
|
||||
apply plugin: 'kotlin-android' // kotlin
|
||||
//tinker插件
|
||||
//apply plugin: 'com.tencent.tinker.patch'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
|
||||
// apkChannelPackage
|
||||
apply plugin: 'channel'
|
||||
|
||||
apply from: 'tinker-support.gradle'
|
||||
|
||||
android {
|
||||
|
||||
androidExtensions {
|
||||
experimental = true
|
||||
}
|
||||
|
||||
dataBinding {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
dexOptions {
|
||||
jumboMode = true
|
||||
// jumboMode = true
|
||||
javaMaxHeapSize "4g"
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
|
||||
multiDexEnabled true
|
||||
javaCompileOptions {
|
||||
annotationProcessorOptions {
|
||||
arguments = [ eventBusIndex : 'com.gh.EventBusIndex' ]
|
||||
arguments = [eventBusIndex: 'com.gh.EventBusIndex']
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 只支持两种架构,减少apk大小,有疑问请参考:
|
||||
* https://developer.android.com/ndk/guides/abis.html
|
||||
* http://allenfeng.com/2016/11/06/what-you-should-know-about-android-abi-and-so/
|
||||
* (为了性能考虑,armeabi可以考虑替换成armeabi-v7a[需要先收集用户设备情况])
|
||||
*/
|
||||
ndk {
|
||||
abiFilters "armeabi", "x86"
|
||||
abiFilters "armeabi-v7a", "x86"
|
||||
}
|
||||
|
||||
// 由于app只针对中文用户,所以仅保留zh资源,其他删掉
|
||||
resConfigs "zh"
|
||||
|
||||
// jackOptions {
|
||||
// enabled true
|
||||
// }
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode rootProject.ext.versionCode
|
||||
versionName rootProject.ext.versionName
|
||||
applicationId rootProject.ext.applicationId
|
||||
|
||||
multiDexEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-fresco.txt'
|
||||
|
||||
/**
|
||||
@ -63,6 +62,11 @@ android {
|
||||
buildConfigField "String", "MTA_APPKEY", "\"${MTA_APPKEY}\""
|
||||
buildConfigField "String", "TD_APPID", "\"${TD_APPID}\""
|
||||
|
||||
/**
|
||||
* Build Time 供区分 jenkins 打包时间用
|
||||
*/
|
||||
buildConfigField "long", "BUILD_TIME", "0"
|
||||
|
||||
}
|
||||
|
||||
// gradle 2.2以上默认同时启用v1和v2(优先用于Android N)
|
||||
@ -82,12 +86,12 @@ android {
|
||||
debuggable true
|
||||
minifyEnabled false
|
||||
zipAlignEnabled false
|
||||
versionNameSuffix "-debug"
|
||||
signingConfig signingConfigs.debug
|
||||
|
||||
buildConfigField "String", "UMENG_APPKEY", "\"${DEBUG_UMENG_APPKEY}\""
|
||||
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${DEBUG_UMENG_MESSAGE_SECRET}\""
|
||||
buildConfigField "String", "MIPUSH_APPID", "\"${DEBUG_MIPUSH_APPID}\""
|
||||
buildConfigField "String", "MIPUSH_APPKEY", "\"${DEBUG_MIPUSH_APPKEY}\""
|
||||
buildConfigField "String", "EXPOSURE_REPO", "\"test\""
|
||||
buildConfigField "String", "EXPOSURE_VERSION", "\"E3\""
|
||||
|
||||
multiDexKeepProguard file("tinker_multidexkeep.pro")
|
||||
}
|
||||
release {
|
||||
debuggable false
|
||||
@ -96,41 +100,54 @@ android {
|
||||
shrinkResources true
|
||||
signingConfig signingConfigs.release
|
||||
|
||||
buildConfigField "String", "UMENG_APPKEY", "\"${UMENG_APPKEY}\""
|
||||
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\""
|
||||
buildConfigField "String", "MIPUSH_APPID", "\"${MIPUSH_APPID}\""
|
||||
buildConfigField "String", "MIPUSH_APPKEY", "\"${MIPUSH_APPKEY}\""
|
||||
buildConfigField "String", "EXPOSURE_REPO", "\"exposure\""
|
||||
buildConfigField "String", "EXPOSURE_VERSION", "\"E3\""
|
||||
|
||||
multiDexKeepProguard file("tinker_multidexkeep.pro")
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions "nonsense"
|
||||
|
||||
/**
|
||||
* 多渠道打包,渠道请参考"channel.txt"文件,所有渠道值均通过java code设置
|
||||
*/
|
||||
productFlavors {
|
||||
// public release host
|
||||
pub {
|
||||
buildConfigField "String", "HOST", "\"${HOST}\""
|
||||
buildConfigField "String", "USER_HOST", "\"${USER_HOST}\""
|
||||
// publish release host
|
||||
publish {
|
||||
dimension "nonsense"
|
||||
buildConfigField "String", "API_HOST", "\"${API_HOST}\""
|
||||
buildConfigField "String", "COMMENT_HOST", "\"${COMMENT_HOST}\""
|
||||
buildConfigField "String", "LIBAO_HOST", "\"${LIBAO_HOST}\""
|
||||
buildConfigField "String", "MESSAGE_HOST", "\"${MESSAGE_HOST}\""
|
||||
buildConfigField "String", "DATA_HOST", "\"${DATA_HOST}\""
|
||||
|
||||
buildConfigField "String", "UMENG_APPKEY", "\"${UMENG_APPKEY}\""
|
||||
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\""
|
||||
buildConfigField "String", "MIPUSH_APPID", "\"${MIPUSH_APPID}\""
|
||||
buildConfigField "String", "MIPUSH_APPKEY", "\"${MIPUSH_APPKEY}\""
|
||||
buildConfigField "String", "MEIZUPUSH_APPID", "\"${MEIZUPUSH_APPID}\""
|
||||
buildConfigField "String", "MEIZUPUSH_APPKEY", "\"${MEIZUPUSH_APPKEY}\""
|
||||
|
||||
buildConfigField "String", "BUGLY_APPID", "\"${BUGLY_APPID}\""
|
||||
}
|
||||
// internal dev host
|
||||
dev {
|
||||
buildConfigField "String", "HOST", "\"${DEV_HOST}\""
|
||||
buildConfigField "String", "USER_HOST", "\"${DEV_USER_HOST}\""
|
||||
// internal test dev host
|
||||
internal {
|
||||
dimension "nonsense"
|
||||
versionNameSuffix "-debug"
|
||||
|
||||
buildConfigField "String", "API_HOST", "\"${DEV_API_HOST}\""
|
||||
buildConfigField "String", "COMMENT_HOST", "\"${DEV_COMMENT_HOST}\""
|
||||
buildConfigField "String", "LIBAO_HOST", "\"${DEV_LIBAO_HOST}\""
|
||||
buildConfigField "String", "MESSAGE_HOST", "\"${DEV_MESSAGE_HOST}\""
|
||||
buildConfigField "String", "DATA_HOST", "\"${DEV_DATA_HOST}\""
|
||||
|
||||
buildConfigField "String", "UMENG_APPKEY", "\"${DEBUG_UMENG_APPKEY}\""
|
||||
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${DEBUG_UMENG_MESSAGE_SECRET}\""
|
||||
buildConfigField "String", "MIPUSH_APPID", "\"${DEBUG_MIPUSH_APPID}\""
|
||||
buildConfigField "String", "MIPUSH_APPKEY", "\"${DEBUG_MIPUSH_APPKEY}\""
|
||||
buildConfigField "String", "MEIZUPUSH_APPID", "\"${DEBUG_MEIZUPUSH_APPID}\""
|
||||
buildConfigField "String", "MEIZUPUSH_APPKEY", "\"${DEBUG_MEIZUPUSH_APPKEY}\""
|
||||
|
||||
buildConfigField "String", "BUGLY_APPID", "\"${DEBUG_BUGLY_APPID}\""
|
||||
}
|
||||
}
|
||||
|
||||
// productFlavors.all { flavor ->
|
||||
// flavor.manifestPlaceholders = [CHANNEL_VALUE: name]//命令 gradlew assembleRelease
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
// apkChannelPackage
|
||||
@ -141,12 +158,6 @@ channel {
|
||||
apkNameFormat = '${appName}-${versionName}-${versionCode}-${flavorName}-${buildType}'
|
||||
}
|
||||
|
||||
apt {
|
||||
arguments {
|
||||
eventBusIndex "com.gh.EventBusIndex"
|
||||
}
|
||||
}
|
||||
|
||||
rebuildChannel {
|
||||
// baseDebugApk = 已有Debug APK
|
||||
// baseReleaseApk = 已有Release APK
|
||||
@ -156,85 +167,155 @@ rebuildChannel {
|
||||
// releaseOutputDir = Release渠道包输出目录
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testCompile test.junit
|
||||
compile fileTree(include: '*.jar', dir: 'libs')
|
||||
compile libs.supportMultidex
|
||||
compile libs.supportDesign
|
||||
compile libs.supportAppCompat
|
||||
compile libs.supportAnnotation
|
||||
compile libs.supportPercent
|
||||
compile libs.supportDesign
|
||||
|
||||
compile libs.switchButton
|
||||
|
||||
compile libs.systemBarTint
|
||||
|
||||
compile libs.fresco
|
||||
compile libs.frescoAnimatedGif
|
||||
|
||||
compile libs.okHttp
|
||||
compile libs.okHttpLogInterceptor
|
||||
|
||||
compile libs.apkChannelPackage
|
||||
|
||||
// debugCompile libs.stetho
|
||||
// debugCompile libs.stethoWithOkHttp
|
||||
|
||||
compile libs.retrofit
|
||||
compile libs.retrofitWithGson // include gson 2.7
|
||||
compile libs.retrofitWithRxJava
|
||||
// compile libs.gson
|
||||
|
||||
compile libs.ormliteAndroid
|
||||
compile libs.ormliteCore
|
||||
|
||||
compile libs.butterKnife
|
||||
apt libs.butterKnifeApt
|
||||
|
||||
compile libs.rxJava
|
||||
compile libs.rxAndroid
|
||||
compile libs.rxBinding
|
||||
compile libs.zxing
|
||||
compile libs.zxingAndroid
|
||||
|
||||
compile libs.swipeLayout
|
||||
compile(libs.autoScrollViewPager) {
|
||||
exclude module: 'support-v4'
|
||||
repositories {
|
||||
flatDir {
|
||||
dirs 'libs/aars'
|
||||
}
|
||||
|
||||
// tinker
|
||||
// provided libs.tinker_anno
|
||||
// compile libs.tinker_lib
|
||||
|
||||
compile libs.weiboSDK
|
||||
|
||||
compile libs.eventbus
|
||||
apt libs.eventbusApt
|
||||
compile project(':libraries:LGLibrary')
|
||||
compile project(':libraries:MiPush')
|
||||
compile project(':libraries:MTA')
|
||||
compile project(':libraries:QQShare')
|
||||
compile project(':libraries:TalkingData')
|
||||
compile project(':libraries:UmengPush')
|
||||
compile project(':libraries:WechatShare')
|
||||
compile project(':libraries:iosched')
|
||||
|
||||
}
|
||||
File propFile = file('sign.properties');
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation fileTree(include: ['*.jar', '*.aar'], dir: '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}"
|
||||
|
||||
implementation "androidx.core:core:${core}"
|
||||
implementation "androidx.fragment:fragment:${fragment}"
|
||||
implementation "androidx.multidex:multidex:${multiDex}"
|
||||
implementation "androidx.appcompat:appcompat:${appCompat}"
|
||||
implementation "androidx.cardview:cardview:${cardView}"
|
||||
implementation "androidx.annotation:annotation:${annotation}"
|
||||
implementation "androidx.constraintlayout:constraintlayout:${constraintLayout}"
|
||||
implementation "androidx.recyclerview:recyclerview:${recyclerView}"
|
||||
implementation "androidx.lifecycle:lifecycle-runtime:${lifeCycle}"
|
||||
implementation "androidx.lifecycle:lifecycle-extensions:${lifeCycle}"
|
||||
kapt "androidx.lifecycle:lifecycle-compiler:${lifeCycle}"
|
||||
implementation "androidx.room:room-runtime:${room}"
|
||||
implementation "androidx.room:room-rxjava2:${room}"
|
||||
implementation "androidx.core:core-ktx:${ktx}"
|
||||
kapt "androidx.room:room-compiler:${room}"
|
||||
kapt "androidx.databinding:databinding-compiler:${databinding}"
|
||||
|
||||
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:${fresco}"
|
||||
implementation "com.facebook.fresco:animated-drawable:${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:1.1.0'
|
||||
|
||||
implementation "pub.devrel:easypermissions:${easypermissions}"
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
|
||||
implementation 'com.contrarywind:Android-PickerView:4.1.3'
|
||||
|
||||
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",{
|
||||
exclude module: "gsyvideoplayer-androidvideocache"
|
||||
})
|
||||
implementation "com.shuyu:gsyVideoPlayer-armv7a:$gsyVideo"
|
||||
implementation "com.shuyu:gsyVideoPlayer-x86:$gsyVideo"
|
||||
|
||||
implementation "com.github.wendux:DSBridge-Android:$dsBridge"
|
||||
|
||||
implementation "android.arch.work:work-runtime:${workManager}"
|
||||
|
||||
implementation "com.llew.huawei:verifier:1.0.6"
|
||||
|
||||
implementation "com.github.tbruyelle:rxpermissions:${rxPermissions}"
|
||||
|
||||
implementation 'com.ethanhua:skeleton:1.1.1'
|
||||
implementation 'io.supercharge:shimmerlayout:2.1.0'
|
||||
implementation "com.tencent.mm.opensdk:wechat-sdk-android-without-mta:5.3.1"
|
||||
implementation 'com.walkud.rom.checker:RomChecker:1.0.0'
|
||||
|
||||
debugImplementation "com.github.nichbar.chucker:library:$chucker"
|
||||
releaseImplementation "com.github.nichbar.chucker:library-no-op:$chucker"
|
||||
implementation "com.bytedance.applog:RangersAppLog-Lite-cn:$bytedanceApplog"
|
||||
|
||||
implementation 'com.aliyun.dpa:oss-android-sdk:2.9.2'
|
||||
|
||||
implementation "com.airbnb.android:lottie:$lottie"
|
||||
|
||||
implementation("com.github.piasy:BigImageViewer:$bigImageViewer", {
|
||||
exclude group: 'com.squareup.okhttp3'
|
||||
})
|
||||
|
||||
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(path: ':libraries:gsyVideoPlayer-proxy_cache')
|
||||
}
|
||||
File propFile = file('sign.properties')
|
||||
if (propFile.exists()) {
|
||||
def Properties props = new Properties()
|
||||
Properties props = new Properties()
|
||||
props.load(new FileInputStream(propFile))
|
||||
|
||||
if (props.containsKey('keyAlias') && props.containsKey('keyPassword') &&
|
||||
props.containsKey('storeFile') && props.containsKey('storePassword')) {
|
||||
android.signingConfigs {
|
||||
debug {
|
||||
keyAlias props.get('keyAlias')
|
||||
keyPassword props.get('keyPassword')
|
||||
storeFile file(props.get('storeFile'))
|
||||
storePassword props.get('storePassword')
|
||||
}
|
||||
// debug 不要使用正式签名,这样tinker才不会打补丁。
|
||||
debug {
|
||||
keyAlias props.get('keyAlias')
|
||||
keyPassword props.get('keyPassword')
|
||||
storeFile file(props.get('storeFile'))
|
||||
storePassword props.get('storePassword')
|
||||
}
|
||||
release {
|
||||
keyAlias props.get('keyAlias')
|
||||
keyPassword props.get('keyPassword')
|
||||
@ -248,3 +329,31 @@ if (propFile.exists()) {
|
||||
} else {
|
||||
android.buildTypes.release.signingConfig = null
|
||||
}
|
||||
|
||||
// 用于测试读取 META-INF 里的 JSON 的代码
|
||||
//task generateMetaJson {
|
||||
// def resDir = new File(buildDir, 'generated/FILES_FOR_META_INF/')
|
||||
// def destDir = new File(resDir, 'META-INF/')
|
||||
// // Add resDir as a resource directory so that it is automatically included in the APK.
|
||||
// android {
|
||||
// sourceSets {
|
||||
// main.resources {
|
||||
// srcDir resDir
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// doLast {
|
||||
// if (!destDir.exists()) destDir.mkdirs()
|
||||
// copy {
|
||||
// into destDir
|
||||
// from new File('generated/FILES_FOR_META_INF/META-INF/halo_skip.json')
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//// Specify when put_files_in_META_INF should run
|
||||
//project.afterEvaluate {
|
||||
// tasks.findAll { task ->
|
||||
// task.name.startsWith('merge') && task.name.endsWith('Resources')
|
||||
// }.each { t -> t.dependsOn generateMetaJson }
|
||||
//}
|
||||
|
||||
BIN
app/libs/GDTActionSDK.min.1.4.9.jar
Normal file
BIN
app/libs/GDTActionSDK.min.1.4.9.jar
Normal file
Binary file not shown.
BIN
app/libs/gid-1.0.jar
Normal file
BIN
app/libs/gid-1.0.jar
Normal file
Binary file not shown.
BIN
app/libs/loghubHelper-bundles-1.2.jar
Normal file
BIN
app/libs/loghubHelper-bundles-1.2.jar
Normal file
Binary file not shown.
@ -16,9 +16,23 @@
|
||||
# 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
|
||||
-dontoptimize
|
||||
|
||||
# OrmLite uses reflection
|
||||
-keep class com.j256.**
|
||||
@ -126,6 +140,7 @@
|
||||
-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 * extends rx.Subscriber
|
||||
@ -161,4 +176,68 @@
|
||||
|
||||
-keepclassmembers enum * { *; }
|
||||
|
||||
##---------------End: proguard configuration for Gson ----------
|
||||
##---------------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.**
|
||||
46
app/src/debug/java/com/gh/gamecenter/Injection.java
Normal file
46
app/src/debug/java/com/gh/gamecenter/Injection.java
Normal file
@ -0,0 +1,46 @@
|
||||
package com.gh.gamecenter;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import com.facebook.stetho.Stetho;
|
||||
import com.facebook.stetho.okhttp3.StethoInterceptor;
|
||||
import com.squareup.leakcanary.LeakCanary;
|
||||
|
||||
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 leakcanary
|
||||
if (LeakCanary.isInAnalyzerProcess(application)) {
|
||||
// This process is dedicated to LeakCanary for heap analysis.
|
||||
// You should not init your app in this process.
|
||||
return false;
|
||||
}
|
||||
LeakCanary.install(application);
|
||||
|
||||
// init stetho
|
||||
Stetho.initializeWithDefaults(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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -1,278 +1,578 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android = "http://schemas.android.com/apk/res/android"
|
||||
package = "com.gh.gamecenter" >
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.gh.gamecenter">
|
||||
|
||||
<!-- 允许应用程序访问网络连接 -->
|
||||
<uses-permission android:name = "android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<!-- 允许应用程序写入外部存储,如SD卡上写文件 -->
|
||||
<uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<!-- 允许应用程序读取扩展存储器 -->
|
||||
<uses-permission android:name = "android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<!-- 允许挂载和反挂载文件系统可移动存储 -->
|
||||
<uses-permission android:name = "android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
|
||||
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
|
||||
<!-- 允许应用程序访问Wi-Fi网络状态信息 -->
|
||||
<uses-permission android:name = "android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<!-- 允许应用程序获取网络信息状态 -->
|
||||
<uses-permission android:name = "android.permission.ACCESS_NETWORK_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.READ_PHONE_STATE" />
|
||||
<!-- 允许应用程序获取当前或最近运行的应用 -->
|
||||
<uses-permission android:name = "android.permission.GET_TASKS" />
|
||||
<uses-permission android:name="android.permission.GET_TASKS" />
|
||||
<!-- 允许访问振动设备 -->
|
||||
<uses-permission android:name = "android.permission.VIBRATE" />
|
||||
<!-- 允许应用程序通过WiFi或移动基站获取粗略的位置信息 -->
|
||||
<uses-permission android:name = "android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<!-- 允许应用程序通过GPS获取精确的位置信息 -->
|
||||
<uses-permission android:name = "android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<!-- 允许应用程序改变Wi-Fi连接状态 -->
|
||||
<uses-permission android:name = "android.permission.CHANGE_WIFI_STATE" />
|
||||
<!-- 允许应用程序管理AccountManager中的账户列表 -->
|
||||
<uses-permission android:name = "android.permission.MANAGE_ACCOUNTS" />
|
||||
<!-- 允许应用程序访问GMail账户列表 -->
|
||||
<uses-permission android:name = "android.permission.GET_ACCOUNTS" />
|
||||
<!-- 允许应用程序连接配对过的蓝牙设备 -->
|
||||
<uses-permission android:name = "android.permission.BLUETOOTH" />
|
||||
<!-- 允许应用程序管理蓝牙,搜索和配对新的蓝牙设备 -->
|
||||
<uses-permission android:name = "android.permission.BLUETOOTH_ADMIN" />
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||
<!-- 允许应用程序打开系统窗口,显示其他应用程序 -->
|
||||
<uses-permission android:name = "android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
<!-- 修改系统设置的权限 -->
|
||||
<uses-permission android:name = "android.permission.WRITE_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
|
||||
|
||||
<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-sdk tools:overrideLibrary="com.shuyu.gsyvideoplayer,
|
||||
com.shuyu.gsyvideoplayer.lib,
|
||||
com.shuyu.gsyvideoplayer.armv7a,
|
||||
com.shuyu.gsyvideoplayer.x86,
|
||||
com.shuyu.gsy.base,
|
||||
shuyu.com.androidvideocache,
|
||||
pl.droidsonroids.gif" />
|
||||
|
||||
<!-- 去掉 SDK 一些流氓权限 -->
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_CONTACTS"
|
||||
tools:node="remove" />
|
||||
|
||||
<supports-screens
|
||||
android:anyDensity = "true"
|
||||
android:largeScreens = "true"
|
||||
android:normalScreens = "true"
|
||||
android:resizeable = "true"
|
||||
android:smallScreens = "true" />
|
||||
android:anyDensity="true"
|
||||
android:largeScreens="true"
|
||||
android:normalScreens="true"
|
||||
android:resizeable="true"
|
||||
android:smallScreens="true" />
|
||||
|
||||
<!--android:largeHeap = "true"-->
|
||||
<application
|
||||
android:name = "com.gh.base.AppController"
|
||||
android:allowBackup = "true"
|
||||
android:icon = "@drawable/logo"
|
||||
android:label = "@string/app_name"
|
||||
android:theme = "@style/AppCompatTheme.APP" >
|
||||
android:name="com.halo.assistant.TinkerApp"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/logo"
|
||||
android:label="@string/app_name"
|
||||
android:largeHeap="true"
|
||||
android:resizeableActivity="true"
|
||||
android:theme="@style/AppCompatTheme.APP"
|
||||
tools:targetApi="n">
|
||||
|
||||
<!--android:launchMode = "singleTask"-->
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.SplashScreenActivity"
|
||||
android:configChanges = "keyboardHidden|orientation|screenSize"
|
||||
android:noHistory = "true"
|
||||
android:screenOrientation = "portrait"
|
||||
android:theme = "@style/AppGuideTheme" >
|
||||
<intent-filter >
|
||||
<action android:name = "android.intent.action.MAIN" />
|
||||
android:name="com.gh.gamecenter.SplashScreenActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/AppTheme.Launcher">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name = "android.intent.category.LAUNCHER" />
|
||||
</intent-filter >
|
||||
</activity >
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.MainActivity"
|
||||
android:launchMode = "singleTask"
|
||||
android:screenOrientation = "portrait"
|
||||
android:windowSoftInputMode = "stateAlwaysHidden|adjustResize" />
|
||||
android:name="com.gh.gamecenter.MainActivity"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/AppCompatTheme.APP"
|
||||
android:windowSoftInputMode="stateAlwaysHidden|adjustResize" />
|
||||
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.DownloadManagerActivity"
|
||||
android:launchMode = "singleTask"
|
||||
android:screenOrientation = "portrait" />
|
||||
android:name="com.gh.gamecenter.DownloadManagerActivity"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<!--android:theme = "@android:style/Theme.Black.NoTitleBar.Fullscreen" 退出时屏幕抖动 -->
|
||||
<activity android:name="com.gh.gamecenter.ViewImageActivity" />
|
||||
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.ViewImageActivity"
|
||||
android:theme = "@android:style/Theme.Black.NoTitleBar.Fullscreen" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.SearchActivity"
|
||||
android:configChanges = "keyboardHidden"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.NewsDetailActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.SettingActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.ConcernActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.SubjectActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.PluginActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.NewsSearchActivity"
|
||||
android:screenOrientation = "portrait"
|
||||
android:windowSoftInputMode = "stateHidden" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.GameNewsActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.CropImageActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.WebActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.ShareCardPicActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.ShareCardActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.MessageDetailActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.LibaoActivity"
|
||||
android:screenOrientation = "portrait"
|
||||
android:windowSoftInputMode = "stateHidden" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.LibaoDetailActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.ShareGhWfifActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.ShareGhActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.CleanApkActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.KcSelectGameActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.ChooseReceiverActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.ReceiverWaitingActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.FileSenderActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.FileReceiverActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.SelectUserIconActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.AboutActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.KaiFuActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.CommentDetailActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.GameDetailActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.SuggestSelectActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.SuggestionActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.VoteActivity"
|
||||
android:screenOrientation = "portrait"
|
||||
android:windowSoftInputMode = "stateAlwaysHidden|adjustResize" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.ToolBoxActivity"
|
||||
android:screenOrientation = "portrait"
|
||||
android:windowSoftInputMode = "stateHidden" />
|
||||
android:name="com.gh.gamecenter.SearchActivity"
|
||||
android:configChanges="keyboardHidden"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/AppCompatTheme.APP" />
|
||||
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.WeiBoShareActivity"
|
||||
android:screenOrientation = "portrait"
|
||||
android:windowSoftInputMode = "stateHidden" />
|
||||
android:name="com.gh.gamecenter.amway.search.AmwaySearchActivity"
|
||||
android:configChanges="keyboardHidden"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/AppCompatTheme.APP" />
|
||||
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.InstallActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.LoginActivity"
|
||||
android:screenOrientation = "portrait"
|
||||
android:windowSoftInputMode = "stateHidden" />
|
||||
android:name="com.gh.gamecenter.ShellActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.UserInfoActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
android:name="com.gh.gamecenter.NewsDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.UserAreaActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
|
||||
<!--非全屏+ScrollView+adjustResize-->
|
||||
android:name="com.gh.gamecenter.SettingActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.UserInfoEditActivity"
|
||||
android:screenOrientation = "portrait"
|
||||
android:windowSoftInputMode = "stateHidden" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.SkipActivity"
|
||||
android:theme = "@style/Theme.AppCompat.Light.Fullscreen.Transparent" >
|
||||
<intent-filter >
|
||||
<data android:scheme = "ghzhushou" />
|
||||
|
||||
<category android:name = "android.intent.category.DEFAULT" />
|
||||
<action android:name = "android.intent.action.VIEW" />
|
||||
<category android:name = "android.intent.category.BROWSABLE" />
|
||||
</intent-filter >
|
||||
</activity >
|
||||
android:name="com.gh.gamecenter.ConcernActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name = ".CommonActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
android:name="com.gh.gamecenter.subject.SubjectActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<receiver android:name = "com.gh.gamecenter.receiver.InstallAndUninstallReceiver" >
|
||||
<intent-filter >
|
||||
<action android:name = "android.intent.action.PACKAGE_ADDED" />
|
||||
<action android:name = "android.intent.action.PACKAGE_REMOVED" />
|
||||
<action android:name = "android.intent.action.PACKAGE_REPLACED" />
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.NewsSearchActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:windowSoftInputMode="stateHidden" />
|
||||
|
||||
<data android:scheme = "package" />
|
||||
</intent-filter >
|
||||
</receiver >
|
||||
<receiver
|
||||
android:name = "com.gh.gamecenter.receiver.NotificationReceiver"
|
||||
android:exported = "false" >
|
||||
<intent-filter >
|
||||
<action android:name = "com.gh.gamecenter.NOTIFICATION" />
|
||||
</intent-filter >
|
||||
</receiver >
|
||||
<receiver
|
||||
android:name = "com.gh.gamecenter.receiver.DownloadReceiver"
|
||||
android:exported = "false" >
|
||||
<intent-filter >
|
||||
<action android:name = "com.gh.gamecenter.DOWNLOAD" />
|
||||
</intent-filter >
|
||||
</receiver >
|
||||
<receiver
|
||||
android:name = "com.gh.gamecenter.receiver.InstallReceiver"
|
||||
android:exported = "false" >
|
||||
<intent-filter >
|
||||
<action android:name = "com.gh.gamecenter.INSTALL" />
|
||||
</intent-filter >
|
||||
</receiver >
|
||||
<receiver android:name = "com.gh.gamecenter.receiver.NetworkStateReceiver" >
|
||||
<intent-filter >
|
||||
<action android:name = "android.net.conn.CONNECTIVITY_CHANGE" />
|
||||
</intent-filter >
|
||||
</receiver >
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.GameNewsActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.CropImageActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.WebActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.ShareCardPicActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.ShareCardActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.MessageDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.LibaoActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:windowSoftInputMode="stateHidden" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.LibaoDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.ShareGhActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.CleanApkActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.SelectUserIconActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.AboutActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.CommentDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.mygame.MyGameActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.GameDetailActivity"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.SuggestionActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.VoteActivity"
|
||||
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"
|
||||
android:windowSoftInputMode="stateHidden" />
|
||||
|
||||
<activity
|
||||
android:name=".category.CategoryDirectoryActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
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" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.UserRegionActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.CollectionActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.MessageActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.UserInfoEditActivity"
|
||||
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" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.ConcernInfoActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.InfoActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
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" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.MessageVoteActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".qa.questions.invite.QuestionsInviteActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
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" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.servers.add.AddKaiFuActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:windowSoftInputMode="stateHidden" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.servers.patch.PatchKaifuActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.BlockActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
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" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.personalhome.fans.FansActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.personalhome.followers.FollowersActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.personalhome.UserHomeActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.article.edit.ArticleEditActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.article.MyArticleActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.article.draft.ArticleDraftActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.article.detail.ArticleDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.draft.CommunityDraftWrapperActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.gamedetail.rating.edit.RatingEditActivity"
|
||||
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" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.editor.GameActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.editor.InsertArticleWrapperActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.gamedetail.rating.RatingReplyActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.history.HistoryActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.personalhome.rating.RatingActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.gamedetail.rating.logs.CommentLogsActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
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" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.video.upload.view.UploadVideoActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.video.game.GameVideoActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.editor.VideoActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.mygame.PlayedGameActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.servers.GameServersActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.game.columncollection.detail.ColumnCollectionDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.game.upload.GameSubmissionActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.halo.assistant.fragment.user.UserPortraitCropImageActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.HelpAndFeedbackActivity"
|
||||
android:windowSoftInputMode="stateHidden"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.help.HelpDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.comment.CommentActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/Theme.Transparent"
|
||||
android:windowSoftInputMode="adjustNothing" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.video.detail.VideoDetailActivity"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/TransparentStatusBarAndNavigationBar" />
|
||||
<activity
|
||||
android:name=".gamedetail.myrating.MyRatingActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<!-- 使用小米/华为推送弹窗功能提高推送成功率-->
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.PushProxyActivity"
|
||||
android:exported="true"
|
||||
android:theme="@android:style/Theme.Translucent" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.SkipActivity"
|
||||
android:theme="@style/Theme.AppCompat.Light.Fullscreen.Transparent">
|
||||
<intent-filter>
|
||||
<data android:scheme="ghzhushou" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
</intent-filter>
|
||||
</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>
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/provider_paths" />
|
||||
</provider>
|
||||
|
||||
<receiver
|
||||
android:name = "com.gh.gamecenter.receiver.ActivitySkipReceiver"
|
||||
android:exported = "true" >
|
||||
<intent-filter >
|
||||
<action android:name = "com.gh.gamecenter.ACTIVITYSKIP" />
|
||||
</intent-filter >
|
||||
</receiver >
|
||||
android:name="com.gh.gamecenter.receiver.DownloadReceiver"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.gh.gamecenter.DOWNLOAD" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name="com.gh.gamecenter.receiver.InstallReceiver"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.gh.gamecenter.INSTALL" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<service android:name = "com.gh.gamecenter.statistics.AppStaticService" />
|
||||
<receiver
|
||||
android:name="com.gh.gamecenter.receiver.ActivitySkipReceiver"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="com.gh.gamecenter.ACTIVITYSKIP" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
</application >
|
||||
<receiver android:name="com.gh.gamecenter.receiver.UmengMessageReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="com.gh.gamecenter.UMENG" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
</manifest >
|
||||
<!--魅族push应用定义消息receiver声明 -->
|
||||
<receiver android:name="com.gh.gamecenter.receiver.MeizuPushReceiver">
|
||||
<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>
|
||||
|
||||
<service android:name="com.gh.base.GHUmengNotificationService" />
|
||||
|
||||
<!--<service android:name = "com.gh.gamecenter.statistics.AppStaticService" />-->
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@ -1,69 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/html">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>光环助手</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
|
||||
<style>
|
||||
body {
|
||||
font: 100%/1.0 'Microsoft YaHei','Helvetica Neue',Helvetica,Arial,sans-serif;
|
||||
background-color: #fff;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
header {
|
||||
}
|
||||
|
||||
article {
|
||||
width:100%;
|
||||
max-width:720px;
|
||||
clear: both;
|
||||
margin: 0 auto;
|
||||
margin-top: 20%;
|
||||
text-align: center;
|
||||
margin-bottom:20%;
|
||||
}
|
||||
.title{margin-top: 4%;font-size:1.7em;color:#191919;text-align:center;}
|
||||
.info{margin-top: 18%;font-size:1.0em;color:#191919;line-height:1.3em;}
|
||||
.download {text-align: center;}
|
||||
.download a{font-size:1.8em;padding:0.2em; text-align:center;color:#ffffff;margin: 0 auto;width:56%;background-color:#2999f9;border-radius:8px; text-decoration:none;display:block;line-height:1.8em;}
|
||||
|
||||
@media only screen and (min-width: 1080px) {
|
||||
article {
|
||||
width:100%;
|
||||
max-width:720px;
|
||||
clear: both;
|
||||
margin: 0 auto;
|
||||
margin-top: 5%;
|
||||
text-align: center;
|
||||
margin-bottom:20%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header>
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<img src="http://192.168.43.1:3100/image/gh_icon.png" width="28%">
|
||||
<p class="title">光环助手</p>
|
||||
<br class="info">乐于分享的人是最帅的^_^ </p>
|
||||
<div class="download">
|
||||
<a href="http://192.168.43.1:3100/download/ghzs.apk">免流量下载</a>
|
||||
</div>
|
||||
<p class="title"><font color="#9A9A9A" size="3em">仅限安卓系统 </font></p>
|
||||
</article>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
163
app/src/main/assets/content.js
Normal file
163
app/src/main/assets/content.js
Normal file
@ -0,0 +1,163 @@
|
||||
function requestContentFocus() {
|
||||
$("#editor").focus();
|
||||
}
|
||||
|
||||
function setupWhenContentEditable() {
|
||||
var editor = $("#editor");
|
||||
if (!editor[0].hasAttribute("contenteditable")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// paste
|
||||
editor.on("paste", function(e) {
|
||||
e.preventDefault();
|
||||
var text = (e.originalEvent || e).clipboardData.getData("text/plain");
|
||||
text = text.replace(/\n/g, "<br>");
|
||||
if ("" != text) {
|
||||
document.execCommand("insertHTML", false, text);
|
||||
} else {
|
||||
window.onPasteListener.onPaste();
|
||||
}
|
||||
});
|
||||
|
||||
requestContentFocus();
|
||||
}
|
||||
|
||||
function getStyle(dom, name) {
|
||||
return window.getComputedStyle(dom)[name];
|
||||
}
|
||||
|
||||
function customLinkgo(self) {
|
||||
var datas = self.dataset.datas;
|
||||
console.log(datas)
|
||||
window.OnLinkClickListener.onClick(datas);
|
||||
}
|
||||
|
||||
var typeClassList = [
|
||||
"community_article-container",
|
||||
"answer-container",
|
||||
"game-container"
|
||||
];
|
||||
|
||||
function removeDomByParent(curDom) {
|
||||
if (curDom.parentElement) {
|
||||
curDom.parentElement.removeChild(curDom);
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("load", function() {
|
||||
var EditorDom = document.querySelector("#editor");
|
||||
setupWhenContentEditable();
|
||||
|
||||
document.addEventListener("keydown", function(e) {
|
||||
var event = e || window.event;
|
||||
|
||||
if (event.keyCode === 8) {
|
||||
var s = document.getSelection();
|
||||
var r = s.getRangeAt(0);
|
||||
|
||||
if (r.startOffset === r.endOffset && r.endOffset === 0) {
|
||||
var preDOM = s.focusNode.previousElementSibling;
|
||||
|
||||
if (
|
||||
preDOM &&
|
||||
preDOM instanceof Element &&
|
||||
preDOM.nodeName === "IMG" &&
|
||||
getStyle(preDOM, "display") === "block"
|
||||
) {
|
||||
preDOM.parentElement.removeChild(preDOM);
|
||||
}
|
||||
}
|
||||
|
||||
var customDom = s.focusNode;
|
||||
if (customDom) {
|
||||
if (
|
||||
r.startContainer.nodeName.toLowerCase() === "blockquote" &&
|
||||
r.startOffset === 0
|
||||
) {
|
||||
RE.formatBlock();
|
||||
e.preventDefault();
|
||||
} else if (
|
||||
customDom.nodeName === "#text" &&
|
||||
customDom.previousElementSibling &&
|
||||
typeClassList.indexOf(customDom.previousElementSibling.className) >
|
||||
-1 &&
|
||||
r.startOffset === 1
|
||||
) {
|
||||
var needDeleteDom = customDom.previousElementSibling;
|
||||
needDeleteDom.insertAdjacentElement(
|
||||
"afterend",
|
||||
document.createElement("br")
|
||||
);
|
||||
} else if (
|
||||
customDom instanceof Element &&
|
||||
customDom.childNodes[s.focusOffset] &&
|
||||
customDom.childNodes[s.focusOffset].previousElementSibling &&
|
||||
typeClassList.indexOf(
|
||||
customDom.childNodes[s.focusOffset].previousElementSibling.className
|
||||
) > -1
|
||||
) {
|
||||
customDom =
|
||||
customDom.childNodes[s.focusOffset].previousElementSibling;
|
||||
customDom.parentElement.removeChild(customDom);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("keyup", function(e) {
|
||||
var event = e || window.event;
|
||||
if (event.keyCode === 13) {
|
||||
var s = document.getSelection();
|
||||
var curDom = s.focusNode;
|
||||
var preDom = curDom.previousElementSibling;
|
||||
|
||||
if (
|
||||
curDom.nodeName.toLowerCase() === "blockquote" &&
|
||||
preDom.nodeName.toLowerCase() === "blockquote"
|
||||
) {
|
||||
if (
|
||||
preDom.childNodes.length > 1 ||
|
||||
(preDom.childNodes.length === 1 &&
|
||||
preDom.childNodes[0].tagName !== "BR")
|
||||
) {
|
||||
curDom.style.marginTop = 0;
|
||||
preDom.style.marginBottom = 0;
|
||||
} else if (
|
||||
(curDom.childNodes.length === 0 ||
|
||||
(curDom.childNodes.length === 1 &&
|
||||
curDom.childNodes[0].tagName === "BR")) &&
|
||||
(preDom.childNodes.length === 0 ||
|
||||
(preDom.childNodes.length === 1 &&
|
||||
preDom.childNodes[0].tagName === "BR"))
|
||||
) {
|
||||
|
||||
removeDomByParent(curDom);
|
||||
|
||||
var startQuoteDom = preDom.previousElementSibling;
|
||||
startQuoteDom && startQuoteDom.nodeName.toLowerCase() === "blockquote"
|
||||
? (startQuoteDom.style.marginBottom = "10px")
|
||||
: null;
|
||||
|
||||
var range = document.createRange();
|
||||
range.selectNode(preDom);
|
||||
s.removeAllRanges();
|
||||
s.addRange(range);
|
||||
|
||||
RE.formatBlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("selectionchange", function(e) {
|
||||
var event = e || window.event;
|
||||
var targetDom = event.target.activeElement;
|
||||
if (targetDom.id === "editor" && targetDom.lastElementChild) {
|
||||
if (typeClassList.indexOf(targetDom.lastElementChild.className) > -1) {
|
||||
var brDom = document.createElement("br");
|
||||
EditorDom.appendChild(brDom);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
18
app/src/main/assets/editor.html
Normal file
18
app/src/main/assets/editor.html
Normal file
@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<link rel="stylesheet" type="text/css" href="normalize.css">
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<link rel="stylesheet" type="text/css" href="video-js.min.css">
|
||||
<!--<link rel="stylesheet" type="text/css" href="https://resource.ghzs.com/css/halo_app.css">-->
|
||||
</head>
|
||||
<body>
|
||||
<div id="editor" contenteditable="false"></div>
|
||||
<script type="text/javascript" src="zepto.min.js"></script>
|
||||
<script type="text/javascript" src="rich_editor.js"></script>
|
||||
<script type="text/javascript" src="video.min.js"></script>
|
||||
<!--<script type="text/javascript" src="content.js"></script>-->
|
||||
<!--<script type="text/javascript" src="https://resource.ghzs.com/js/halo_app.js"></script>-->
|
||||
</body>
|
||||
</html>
|
||||
40
app/src/main/assets/emojikf
Normal file
40
app/src/main/assets/emojikf
Normal file
@ -0,0 +1,40 @@
|
||||
emoji_kf_1.png,:smile:
|
||||
emoji_kf_2.png,:smiley:
|
||||
emoji_kf_3.png,:laughing:
|
||||
emoji_kf_4.png,:blush:
|
||||
emoji_kf_5.png,:heart_eyes:
|
||||
emoji_kf_6.png,:smirk:
|
||||
emoji_kf_7.png,:flushed:
|
||||
emoji_kf_8.png,:kissing_heart:
|
||||
emoji_kf_9.png,:grin:
|
||||
emoji_kf_10.png,:wink:
|
||||
emoji_kf_11.png,:stuck_out_tongue_winking_eye:
|
||||
emoji_kf_12.png,:stuck_out_tongue_closed eyes:
|
||||
emoji_kf_13.png,:worried:
|
||||
emoji_kf_14.png,:sleeping:
|
||||
emoji_kf_15.png,:expressionless:
|
||||
emoji_kf_16.png,:sweat_smile:
|
||||
emoji_kf_17.png,:joy:
|
||||
emoji_kf_18.png,:cold_sweat:
|
||||
emoji_kf_19.png,:sob:
|
||||
emoji_kf_20.png,:angry:
|
||||
emoji_kf_21.png,:mask:
|
||||
emoji_kf_22.png,:scream:
|
||||
emoji_kf_23.png,:sunglasses:
|
||||
emoji_kf_24.png,:heart:
|
||||
emoji_kf_25.png,:broken_heart:
|
||||
emoji_kf_26.png,:star:
|
||||
emoji_kf_27.png,:anger:
|
||||
emoji_kf_28.png,:exclamation:
|
||||
emoji_kf_29.png,:question:
|
||||
emoji_kf_30.png,:zzz:
|
||||
emoji_kf_31.png,:thumbsup:
|
||||
emoji_kf_32.png,:thumbsdown:
|
||||
emoji_kf_33.png,:ok_hand:
|
||||
emoji_kf_34.png,:punch:
|
||||
emoji_kf_35.png,:yeah:
|
||||
emoji_kf_36.png,:clap:
|
||||
emoji_kf_37.png,:muscle:
|
||||
emoji_kf_38.png,:pray:
|
||||
emoji_kf_39.png,:skull:
|
||||
emoji_kf_40.png,:trollface:
|
||||
BIN
app/src/main/assets/iattest.wav
Normal file
BIN
app/src/main/assets/iattest.wav
Normal file
Binary file not shown.
BIN
app/src/main/assets/like.gif
Normal file
BIN
app/src/main/assets/like.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
1
app/src/main/assets/lottie/click_guide.json
Normal file
1
app/src/main/assets/lottie/click_guide.json
Normal file
@ -0,0 +1 @@
|
||||
{"v":"5.5.9","fr":60,"ip":0,"op":90,"w":1080,"h":202,"nm":"click","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"椭圆形","sr":1,"ks":{"o":{"a":0,"k":20,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[204,1455,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":[24,24],"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":120,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"椭圆形","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":63,"s":[10]},{"t":70,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[204,1455,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":39,"s":[100,100,100]},{"t":49,"s":[110,110,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[36,36],"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":120,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"圆环","refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.531],"y":[0]},"t":28,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":38,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.526],"y":[0]},"t":48,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.446],"y":[0]},"t":63,"s":[50]},{"t":82,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[125.951,79.658,0],"ix":2},"a":{"a":0,"k":[205.951,1458.658,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.601,0.601,0.333],"y":[0,0,0]},"t":28,"s":[50,50,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.528,0.528,0.333],"y":[0,0,0]},"t":38,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.526,0.526,0.333],"y":[0,0,0]},"t":48,"s":[120,120,100]},{"t":63,"s":[100,100,100]}],"ix":6}},"ao":0,"w":1080,"h":1920,"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"点击手","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.596],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":10,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.515],"y":[0]},"t":63,"s":[100]},{"t":83,"s":[0]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.507],"y":[0]},"t":10,"s":[6]},{"t":30,"s":[2]}],"ix":10},"p":{"a":0,"k":[178.982,123.325,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.489,0.489,0.333],"y":[0,0,0]},"t":10,"s":[100,100,100]},{"t":30,"s":[90,90,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-5.33,-8.3],[3.89,0.27],[-4.4,-1.68],[-4.33,-0.67],[-4.08,9.32],[3.33,5.44],[3.39,4.6],[0.87,-3.7],[3.6,-0.86],[1.03,-0.21],[2.34,-0.53],[0.96,1.15],[4.22,5.48],[-1.18,-4.56]],"o":[[1.11,1.71],[-3.89,-0.27],[6.42,2.5],[4.33,0.66],[1.63,-5.32],[-3.34,-5.45],[-1.68,-2.1],[-0.71,3.14],[-3.43,0.95],[-0.57,0.08],[-3.86,1.12],[-3.23,-3.94],[-1.89,-2.28],[2.42,4.64]],"v":[[-5.387,9.698],[-10.717,8.498],[-12.327,15.628],[5.813,21.748],[23.313,11.778],[20.273,-1.202],[11.563,-13.962],[5.393,-12.362],[1.083,-13.722],[-2.087,-9.742],[-5.707,-11.752],[-8.777,-7.572],[-18.297,-20.542],[-23.827,-17.832]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","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":"路径备份 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0}],"markers":[]}
|
||||
1
app/src/main/assets/lottie/score_fireworks.json
Normal file
1
app/src/main/assets/lottie/score_fireworks.json
Normal file
File diff suppressed because one or more lines are too long
1
app/src/main/assets/lottie/slide_guide.json
Normal file
1
app/src/main/assets/lottie/slide_guide.json
Normal file
@ -0,0 +1 @@
|
||||
{"v":"5.5.9","fr":60,"ip":0,"op":120,"w":1080,"h":586,"nm":"上滑","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":2,"ty":4,"nm":"手","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":6,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.558],"y":[0]},"t":60,"s":[100]},{"t":71,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.479,"y":0},"t":3,"s":[611,475,0],"to":[0,-62.75,0],"ti":[0,62.75,0]},{"t":40,"s":[611,98.5,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[90,90,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-7.78,-12.06],[5.68,0.39],[-6.42,-2.45],[-6.32,-0.97],[-5.95,13.55],[4.87,7.91],[4.94,6.69],[1.26,-5.37],[5.25,-1.25],[1.5,-0.3],[3.4,-0.77],[1.4,1.68],[6.15,7.98],[-1.73,-6.64]],"o":[[1.62,2.49],[-5.68,-0.39],[9.37,3.63],[6.31,0.98],[2.39,-7.74],[-4.87,-7.92],[-2.45,-3.05],[-1.05,4.57],[-4.99,1.39],[-0.83,0.13],[-5.63,1.63],[-4.71,-5.72],[-2.75,-3.31],[3.52,6.76]],"v":[[-7.86,14.26],[-15.64,12.52],[-17.99,22.89],[8.47,31.78],[33.98,17.29],[29.55,-1.59],[16.85,-20.15],[7.86,-17.83],[1.56,-19.8],[-3.05,-14.02],[-8.33,-16.94],[-12.44,-11.045],[-26.761,-30.19],[-34.75,-25.78]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","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":120,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"矩形","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.715],"y":[0]},"t":57,"s":[100]},{"t":67,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[525,228.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.491,"y":0},"t":3,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[24.328,180.5],[-22,180.5],[-22,204.5],[24.328,204.5]],"c":true}]},{"t":40,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[24.328,-207.5],[-22,-207.5],[-22,204.5],[24.328,204.5]],"c":true}]}],"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"蒙版 1"}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[6,137],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":2,"ix":4},"nm":"矩形路径 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,1,1,1,0.5,1,1,1,1,1,1,1,0,1,0.5,0.5,1,0],"ix":9}},"s":{"a":0,"k":[0,-68.5],"ix":5},"e":{"a":0,"k":[0,68.5],"ix":6},"t":1,"nm":"Gradient Fill 1","mn":"ADBE Vector Graphic - G-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},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":33,"ix":3},"m":1,"ix":2,"nm":"修剪路径 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":3,"op":123,"st":3,"bm":0}],"markers":[]}
|
||||
1
app/src/main/assets/lottie/tab_game.json
Normal file
1
app/src/main/assets/lottie/tab_game.json
Normal file
File diff suppressed because one or more lines are too long
1
app/src/main/assets/lottie/tab_home.json
Normal file
1
app/src/main/assets/lottie/tab_home.json
Normal file
@ -0,0 +1 @@
|
||||
{"v":"5.5.9","fr":30,"ip":0,"op":20,"w":66,"h":66,"nm":"tab_index","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"椭圆形备份","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.596],"y":[0]},"t":0,"s":[0]},{"t":6,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,40.493,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.54,0.54,0.333],"y":[0,0,0]},"t":4,"s":[80,80,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.555,0.555,0.333],"y":[0,0,0]},"t":9,"s":[110,110,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.552,0.552,0.333],"y":[0,0,0]},"t":13,"s":[90,90,100]},{"t":16,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[5,5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.635],"y":[0]},"t":0,"s":[0]},{"t":8,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"修剪路径 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"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":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-0.5,"op":59.5,"st":-0.5,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"路径备份","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,32.993,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.508,0.508,0.333],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.488,0.488,0.333],"y":[0,0,0]},"t":4,"s":[80,80,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.502,0.502,0.333],"y":[0,0,0]},"t":9,"s":[110,110,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.534,0.534,0.333],"y":[0,0,0]},"t":13,"s":[95,95,100]},{"t":16,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.24,-1.21],[-1.93,-1.89],[-0.24,-0.57],[0,-0.06],[0,-2.63],[1.76,0],[0,0],[0,1.72],[0,2.63],[-0.24,0.61],[-0.03,0.02],[-1.93,1.89]],"o":[[1.92,1.89],[0.02,0.02],[0.24,0.57],[0,2.63],[0,1.72],[0,0],[-1.76,0],[0,-2.62],[0,-0.07],[0.25,-0.61],[1.92,-1.89],[1.24,-1.21]],"v":[[2.26,-9.09],[8.03,-3.42],[8.76,-2.38],[9,-1.02],[9,6.88],[5.82,10],[-5.82,10],[-9,6.88],[-9,-0.99],[-8.71,-2.38],[-8.01,-3.43],[-2.23,-9.09]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.266,0.638,1,0.5,0.242,0.595,1,1,0.217,0.552,1],"ix":9}},"s":{"a":0,"k":[-4.902,-4.663],"ix":5},"e":{"a":0,"k":[8.159,8.646],"ix":6},"t":1,"nm":"Gradient Fill 1","mn":"ADBE Vector Graphic - G-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":60,"st":0,"bm":0}],"markers":[]}
|
||||
1
app/src/main/assets/lottie/tab_video.json
Normal file
1
app/src/main/assets/lottie/tab_video.json
Normal file
@ -0,0 +1 @@
|
||||
{"v":"5.5.9","fr":30,"ip":0,"op":20,"w":66,"h":66,"nm":"tab_video","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"形状图层 1","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.771],"y":[0]},"t":0,"s":[0]},{"t":5,"s":[100]}],"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[-3.742,6.835,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[30.937,31.042,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":2,"d":1,"pt":{"a":0,"k":3,"ix":3},"p":{"a":0,"k":[0,0],"ix":4},"r":{"a":0,"k":0,"ix":5},"or":{"a":0,"k":29.286,"ix":7},"os":{"a":0,"k":75,"ix":9},"ix":1,"nm":"多边星形路径 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":13,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-20.75,-13.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[102.743,88.578],"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":"多边星形 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.657],"y":[0]},"t":0,"s":[0]},{"t":8,"s":[100]}],"ix":2},"o":{"a":0,"k":-115,"ix":3},"m":1,"ix":2,"nm":"修剪路径 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":60,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"路径 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,33.004,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.508,0.508,0.333],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.488,0.488,0.333],"y":[0,0,0]},"t":4,"s":[80,80,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.502,0.502,0.333],"y":[0,0,0]},"t":9,"s":[110,110,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.534,0.534,0.333],"y":[0,0,0]},"t":13,"s":[95,95,100]},{"t":16,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[2.16,0.38],[3.22,-0.55],[0.38,-2.16],[-0.55,-3.22],[-2.16,-0.38],[-1.63,0],[-1.61,0.27],[-0.38,2.16],[0.55,3.22]],"o":[[-0.38,-2.16],[-3.22,-0.55],[-2.16,0.38],[-0.55,3.22],[0.38,2.16],[1.61,0.27],[1.63,0],[2.16,-0.38],[0.55,-3.22],[0,0]],"v":[[9.09,-4.86],[4.86,-9.09],[-4.86,-9.09],[-9.09,-4.86],[-9.09,4.86],[-4.86,9.09],[0,9.5],[4.86,9.09],[9.09,4.86],[9.09,-4.86]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.266,0.638,1,0.5,0.242,0.595,1,1,0.217,0.552,1],"ix":9}},"s":{"a":0,"k":[-5.174,-4.43],"ix":5},"e":{"a":0,"k":[8.612,8.214],"ix":6},"t":1,"nm":"Gradient Fill 3","mn":"ADBE Vector Graphic - G-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":60,"st":0,"bm":0}],"markers":[]}
|
||||
5
app/src/main/assets/microlog.properties
Normal file
5
app/src/main/assets/microlog.properties
Normal file
@ -0,0 +1,5 @@
|
||||
# This is a simple Microlog configuration file
|
||||
microlog.level=DEBUG
|
||||
microlog.appender=LogCatAppender;FileAppender
|
||||
microlog.formatter=PatternFormatter
|
||||
microlog.formatter.PatternFormatter.pattern=%c [%P] %m %T
|
||||
413
app/src/main/assets/normalize.css
vendored
Normal file
413
app/src/main/assets/normalize.css
vendored
Normal file
@ -0,0 +1,413 @@
|
||||
/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
|
||||
|
||||
/**
|
||||
* 1. Set default font family to sans-serif.
|
||||
* 2. Prevent iOS text size adjust after orientation change, without disabling
|
||||
* user zoom.
|
||||
*/
|
||||
|
||||
html {
|
||||
font-family: sans-serif; /* 1 */
|
||||
-webkit-text-size-adjust: 100%; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove default margin.
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* HTML5 display definitions
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Correct `block` display not defined for any HTML5 element in IE 8/9.
|
||||
* Correct `block` display not defined for `details` or `summary` in IE 10/11
|
||||
* and Firefox.
|
||||
* Correct `block` display not defined for `main` in IE 11.
|
||||
*/
|
||||
|
||||
article,
|
||||
aside,
|
||||
details,
|
||||
figcaption,
|
||||
figure,
|
||||
footer,
|
||||
header,
|
||||
hgroup,
|
||||
main,
|
||||
menu,
|
||||
nav,
|
||||
section,
|
||||
summary {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct `inline-block` display not defined in IE 8/9.
|
||||
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
|
||||
*/
|
||||
|
||||
audio,
|
||||
canvas,
|
||||
progress,
|
||||
video {
|
||||
display: inline-block; /* 1 */
|
||||
vertical-align: baseline; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent modern browsers from displaying `audio` without controls.
|
||||
* Remove excess height in iOS 5 devices.
|
||||
*/
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address `[hidden]` styling not present in IE 8/9/10.
|
||||
* Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
|
||||
*/
|
||||
|
||||
[hidden],
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Links
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the gray background color from active links in IE 10.
|
||||
*/
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Improve readability when focused and also mouse hovered in all browsers.
|
||||
*/
|
||||
|
||||
a:active,
|
||||
a:hover {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
/* Text-level semantics
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
|
||||
*/
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: 1px dotted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address styling not present in Safari and Chrome.
|
||||
*/
|
||||
|
||||
dfn {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address variable `h1` font-size and margin within `section` and `article`
|
||||
* contexts in Firefox 4+, Safari, and Chrome.
|
||||
*/
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address styling not present in IE 8/9.
|
||||
*/
|
||||
|
||||
mark {
|
||||
background: #ff0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address inconsistent and variable font size in all browsers.
|
||||
*/
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
|
||||
*/
|
||||
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
/* Embedded content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove border when inside `a` element in IE 8/9/10.
|
||||
*/
|
||||
|
||||
img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct overflow not hidden in IE 9/10/11.
|
||||
*/
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Grouping content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Address margin not present in IE 8/9 and Safari.
|
||||
*/
|
||||
|
||||
figure {
|
||||
margin: 1em 40px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address differences between Firefox and other browsers.
|
||||
*/
|
||||
|
||||
hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contain overflow in all browsers.
|
||||
*/
|
||||
|
||||
pre {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address odd `em`-unit font size rendering in all browsers.
|
||||
*/
|
||||
|
||||
code,
|
||||
kbd,
|
||||
pre,
|
||||
samp {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
/* Forms
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Known limitation: by default, Chrome and Safari on OS X allow very limited
|
||||
* styling of `select`, unless a `border` property is set.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 1. Correct color not being inherited.
|
||||
* Known issue: affects color of disabled elements.
|
||||
* 2. Correct font properties not being inherited.
|
||||
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
|
||||
*/
|
||||
|
||||
button,
|
||||
input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
color: inherit; /* 1 */
|
||||
font: inherit; /* 2 */
|
||||
margin: 0; /* 3 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Address `overflow` set to `hidden` in IE 8/9/10/11.
|
||||
*/
|
||||
|
||||
button {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address inconsistent `text-transform` inheritance for `button` and `select`.
|
||||
* All other form control elements do not inherit `text-transform` values.
|
||||
* Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
|
||||
* Correct `select` style inheritance in Firefox.
|
||||
*/
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
|
||||
* and `video` controls.
|
||||
* 2. Correct inability to style clickable `input` types in iOS.
|
||||
* 3. Improve usability and consistency of cursor style between image-type
|
||||
* `input` and others.
|
||||
*/
|
||||
|
||||
button,
|
||||
html input[type="button"], /* 1 */
|
||||
input[type="reset"],
|
||||
input[type="submit"] {
|
||||
-webkit-appearance: button; /* 2 */
|
||||
cursor: pointer; /* 3 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-set default cursor for disabled elements.
|
||||
*/
|
||||
|
||||
button[disabled],
|
||||
html input[disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
|
||||
* the UA stylesheet.
|
||||
*/
|
||||
|
||||
input {
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
/**
|
||||
* It's recommended that you don't attempt to style these elements.
|
||||
* Firefox's implementation doesn't respect box-sizing, padding, or width.
|
||||
*
|
||||
* 1. Address box sizing set to `content-box` in IE 8/9/10.
|
||||
* 2. Remove excess padding in IE 8/9/10.
|
||||
*/
|
||||
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
box-sizing: border-box; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
|
||||
* `font-size` values of the `input`, it causes the cursor style of the
|
||||
* decrement button to change from `default` to `text`.
|
||||
*/
|
||||
|
||||
input[type="number"]::-webkit-inner-spin-button,
|
||||
input[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Address `appearance` set to `searchfield` in Safari and Chrome.
|
||||
* 2. Address `box-sizing` set to `border-box` in Safari and Chrome
|
||||
*/
|
||||
|
||||
input[type="search"] {
|
||||
-webkit-appearance: textfield; /* 1 */
|
||||
-webkit-box-sizing: content-box; /* 2 */
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
|
||||
* Safari (but not Chrome) clips the cancel button when the search input has
|
||||
* padding (and `textfield` appearance).
|
||||
*/
|
||||
|
||||
input[type="search"]::-webkit-search-cancel-button,
|
||||
input[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define consistent border, margin, and padding.
|
||||
*/
|
||||
|
||||
fieldset {
|
||||
border: 1px solid #c0c0c0;
|
||||
margin: 0 2px;
|
||||
padding: 0.35em 0.625em 0.75em;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct `color` not being inherited in IE 8/9/10/11.
|
||||
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
|
||||
*/
|
||||
|
||||
legend {
|
||||
border: 0; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove default vertical scrollbar in IE 8/9/10/11.
|
||||
*/
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't inherit the `font-weight` (applied by a rule above).
|
||||
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
|
||||
*/
|
||||
|
||||
optgroup {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Tables
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove most spacing between table cells.
|
||||
*/
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
td,
|
||||
th {
|
||||
padding: 0;
|
||||
}
|
||||
619
app/src/main/assets/rich_editor.js
Normal file
619
app/src/main/assets/rich_editor.js
Normal file
@ -0,0 +1,619 @@
|
||||
/**
|
||||
* Copyright (C) 2017 Wasabeef
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// alert("")
|
||||
|
||||
var RE = {};
|
||||
|
||||
RE.currentSelection = {
|
||||
"startContainer": 0,
|
||||
"startOffset": 0,
|
||||
"endContainer": 0,
|
||||
"endOffset": 0};
|
||||
|
||||
var isDebug = false;
|
||||
try {
|
||||
isDebug = window.NativeCallBack.isNativeBuildDebug()
|
||||
} catch(error) {
|
||||
}
|
||||
|
||||
// 引用远端的JS 和 CSS
|
||||
var script = document.createElement("script")
|
||||
document.body.appendChild(script)
|
||||
if (isDebug) {
|
||||
script.src = "https://resource.ghzs.com/js/halo_app_test.js" + "?timestamp=" + Math.round(new Date().getTime() / 1000)
|
||||
} else {
|
||||
script.src = "https://resource.ghzs.com/js/halo.js" + "?timestamp=" + Math.round(new Date().getTime() / 1000 / 1000)
|
||||
}
|
||||
|
||||
var style = document.createElement("link")
|
||||
style.rel = "stylesheet"
|
||||
style.type = "text/css"
|
||||
if (isDebug) {
|
||||
style.href = "https://resource.ghzs.com/css/halo_app_test.css" + "?timestamp=" + Math.round(new Date().getTime() / 1000)
|
||||
} else {
|
||||
style.href = "https://resource.ghzs.com/css/halo.css" + "?timestamp=" + Math.round(new Date().getTime() / 1000 / 1000)
|
||||
}
|
||||
|
||||
document.head.appendChild(style)
|
||||
|
||||
RE.editor = document.getElementById('editor');
|
||||
|
||||
document.addEventListener("selectionchange", function() { RE.backuprange(); });
|
||||
|
||||
// Initializations
|
||||
RE.callback = function() {
|
||||
window.location.href = "re-callback://" + encodeURIComponent(RE.getHtml());
|
||||
}
|
||||
|
||||
RE.setHtml = function(contents) {
|
||||
RE.editor.innerHTML = decodeURIComponent(contents.replace(/\+/g, '%20'));
|
||||
}
|
||||
|
||||
// 后续初始化html代码,都用该方法
|
||||
RE.setHtmlByVideoStatus = function(contents) {
|
||||
RE.editor.innerHTML = decodeURIComponent(contents.replace(/\+/g, '%20'));
|
||||
}
|
||||
|
||||
// Deprecated
|
||||
RE.getHtml = function() {
|
||||
return RE.editor.innerHTML;
|
||||
}
|
||||
|
||||
RE.getText = function() {
|
||||
return RE.editor.innerText;
|
||||
}
|
||||
|
||||
RE.setBaseTextColor = function(color) {
|
||||
RE.editor.style.color = color;
|
||||
}
|
||||
|
||||
RE.setBaseFontSize = function(size) {
|
||||
RE.editor.style.fontSize = size;
|
||||
}
|
||||
|
||||
RE.setPadding = function(left, top, right, bottom) {
|
||||
RE.editor.style.paddingLeft = left;
|
||||
RE.editor.style.paddingTop = top;
|
||||
RE.editor.style.paddingRight = right;
|
||||
RE.editor.style.paddingBottom = bottom;
|
||||
}
|
||||
|
||||
RE.setBackgroundColor = function(color) {
|
||||
document.body.style.backgroundColor = color;
|
||||
}
|
||||
|
||||
RE.setBackgroundImage = function(image) {
|
||||
RE.editor.style.backgroundImage = image;
|
||||
}
|
||||
|
||||
RE.setWidth = function(size) {
|
||||
RE.editor.style.minWidth = size;
|
||||
}
|
||||
|
||||
RE.setHeight = function(size) {
|
||||
RE.editor.style.height = size;
|
||||
}
|
||||
|
||||
RE.setTextAlign = function(align) {
|
||||
RE.editor.style.textAlign = align;
|
||||
}
|
||||
|
||||
RE.setVerticalAlign = function(align) {
|
||||
RE.editor.style.verticalAlign = align;
|
||||
}
|
||||
|
||||
RE.setPlaceholder = function(placeholder) {
|
||||
RE.editor.setAttribute("placeholder", placeholder);
|
||||
}
|
||||
|
||||
RE.setEditorFocus = function() {
|
||||
RE.editor.focus();
|
||||
}
|
||||
|
||||
RE.setInputEnabled = function(inputEnabled) {
|
||||
RE.editor.contentEditable = String(inputEnabled);
|
||||
}
|
||||
|
||||
RE.formatBlock = function() {
|
||||
document.execCommand('formatBlock', false, 'p');
|
||||
}
|
||||
|
||||
RE.undo = function() {
|
||||
document.execCommand('undo', false, null);
|
||||
}
|
||||
|
||||
RE.redo = function() {
|
||||
document.execCommand('redo', false, null);
|
||||
}
|
||||
|
||||
RE.setBold = function() {
|
||||
document.execCommand('bold', false, null);
|
||||
}
|
||||
|
||||
RE.setItalic = function() {
|
||||
document.execCommand('italic', false, null);
|
||||
}
|
||||
|
||||
RE.setSubscript = function() {
|
||||
document.execCommand('subscript', false, null);
|
||||
}
|
||||
|
||||
RE.setSuperscript = function() {
|
||||
document.execCommand('superscript', false, null);
|
||||
}
|
||||
|
||||
RE.setStrikeThrough = function() {
|
||||
document.execCommand('strikeThrough', false, null);
|
||||
}
|
||||
|
||||
RE.setUnderline = function() {
|
||||
document.execCommand('underline', false, null);
|
||||
}
|
||||
|
||||
RE.setBullets = function() {
|
||||
document.execCommand('insertUnorderedList', false, null);
|
||||
}
|
||||
|
||||
RE.setNumbers = function() {
|
||||
document.execCommand('insertOrderedList', false, null);
|
||||
}
|
||||
|
||||
RE.setTextColor = function(color) {
|
||||
RE.restorerange();
|
||||
document.execCommand("styleWithCSS", null, true);
|
||||
document.execCommand('foreColor', false, color);
|
||||
document.execCommand("styleWithCSS", null, false);
|
||||
}
|
||||
|
||||
RE.setTextBackgroundColor = function(color) {
|
||||
RE.restorerange();
|
||||
document.execCommand("styleWithCSS", null, true);
|
||||
document.execCommand('hiliteColor', false, color);
|
||||
document.execCommand("styleWithCSS", null, false);
|
||||
}
|
||||
|
||||
RE.setFontSize = function(fontSize){
|
||||
document.execCommand("fontSize", false, fontSize);
|
||||
}
|
||||
|
||||
RE.setHeading = function(heading) {
|
||||
document.execCommand('formatBlock', false, '<h'+heading+'>');
|
||||
RE.sendElementNameToNative()
|
||||
}
|
||||
|
||||
RE.setIndent = function() {
|
||||
document.execCommand('indent', false, null);
|
||||
}
|
||||
|
||||
RE.setOutdent = function() {
|
||||
document.execCommand('outdent', false, null);
|
||||
}
|
||||
|
||||
RE.setJustifyLeft = function() {
|
||||
document.execCommand('justifyLeft', false, null);
|
||||
}
|
||||
|
||||
RE.setJustifyCenter = function() {
|
||||
document.execCommand('justifyCenter', false, null);
|
||||
}
|
||||
|
||||
RE.setJustifyRight = function() {
|
||||
document.execCommand('justifyRight', false, null);
|
||||
}
|
||||
|
||||
RE.setBlockquote = function() {
|
||||
document.execCommand('formatBlock', false, '<blockquote>');
|
||||
// var blockId = window.getSelection().focusNode.parentNode;
|
||||
// $(blockId).addClass("haloBlock")
|
||||
RE.sendElementNameToNative()
|
||||
}
|
||||
|
||||
RE.insertImage = function(url) {
|
||||
var html = "<div><img src =\"" + url + "\" style=\" max-width: 100%; display:block; margin:15px auto; height: auto;\"></div><br>"
|
||||
RE.insertHTML(html);
|
||||
}
|
||||
|
||||
// 替换成缩略图
|
||||
RE.replaceTbImage = function(imgRuleFlag, gifRuleFlag) {
|
||||
var imgs = document.getElementsByTagName("img");
|
||||
var index = 0
|
||||
for (var i = 0; i < imgs.length; i++) {
|
||||
var img = imgs[i];
|
||||
var imageClassName = img.className;
|
||||
// console.log(imageClassName)
|
||||
if (imageClassName == "image-link" || img.className == "poster") continue;
|
||||
if(img.src.indexOf("?") > 0) continue;
|
||||
// console.log(i)
|
||||
var tbImg
|
||||
if(img.src.indexOf(".gif") > 0) {
|
||||
tbImg = img.src + gifRuleFlag
|
||||
} else {
|
||||
tbImg = img.src + imgRuleFlag
|
||||
}
|
||||
|
||||
img.style.cssText = "max-width: 60%; display:block; margin:15px auto; height: auto;"
|
||||
img.src = tbImg;
|
||||
|
||||
if (index == 0) {
|
||||
var bigImg = document.createElement('img');
|
||||
bigImg.src = "file:///android_asset/web_load_dfimg_icon.png";
|
||||
bigImg.style.cssText = "max-width: 20%; margin:15px 0 0 0; height: auto;"
|
||||
img.parentNode.insertBefore(bigImg, img.parentNode.childNodes[0]);
|
||||
i++;
|
||||
|
||||
if(img.parentNode != null) {
|
||||
img.parentNode.style.cssText += "text-align: left;"
|
||||
}
|
||||
|
||||
if(img.parentNode != null && img.parentNode.parentNode != null) {
|
||||
img.parentNode.parentNode.style.cssText += "text-align: left;"
|
||||
}
|
||||
|
||||
}
|
||||
index ++;
|
||||
}
|
||||
}
|
||||
|
||||
// 替换成默认图
|
||||
RE.replaceAllDfImage = function(imgRuleFlag, gifRuleFlag) {
|
||||
var imgs = document.getElementsByTagName("img");
|
||||
for (var i = 0; i < imgs.length; i++) {
|
||||
var img = imgs[i];
|
||||
var imageClassName = img.className;
|
||||
if (imageClassName == "image-link" || img.className == "poster") continue;
|
||||
if(img.src.indexOf("web_load_dfimg_icon") > 0) {
|
||||
img.parentNode.removeChild(img.parentNode.childNodes[0]);
|
||||
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
|
||||
}
|
||||
} else {
|
||||
img.style.cssText = "max-width: 100%; display:block; margin:8px auto; height: auto;"
|
||||
img.src = img.src.split("?")[0] + imgRuleFlag
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 去除显示大图
|
||||
RE.hideShowBigPic = function() {
|
||||
var imgs = document.getElementsByTagName("img");
|
||||
var j = 0;
|
||||
for (var i = 0; i < imgs.length; i++) {
|
||||
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) {
|
||||
j++;
|
||||
}
|
||||
}
|
||||
// 去除显示大图
|
||||
if (j == 0) {
|
||||
var imgs = document.getElementsByTagName("img");
|
||||
for (var i = 0; i < imgs.length; i++) {
|
||||
var img = imgs[i];
|
||||
var imageClassName = img.className;
|
||||
if (imageClassName == "image-link" || img.className == "poster") continue;
|
||||
if(img.src.indexOf("web_load_dfimg_icon") > 0) {
|
||||
img.parentNode.removeChild(img.parentNode.childNodes[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RE.replaceDfImageByUrl = function(imgUrl, imgRuleFlag, gifRuleFlag) {
|
||||
var imgs = document.getElementsByTagName("img");
|
||||
for (var i = 0; i < imgs.length; i++) {
|
||||
var img = imgs[i];
|
||||
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 {
|
||||
img.src = img.src.split("?")[0] + imgRuleFlag
|
||||
}
|
||||
}
|
||||
}
|
||||
RE.hideShowBigPic();
|
||||
}
|
||||
|
||||
RE.ImageClickListener = function() {
|
||||
var imgs = document.getElementsByTagName("img");
|
||||
for (var i = 0; i < imgs.length; i++) {
|
||||
var img = imgs[i];
|
||||
var imageClassName = img.className;
|
||||
if (imageClassName == "image-link"|| img.className == "poster") continue;
|
||||
window.imagelistener.imageArr(img.src);
|
||||
img.onclick = function() {
|
||||
window.imagelistener.imageClick(this.src);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RE.insertHTML = function(html) {
|
||||
RE.restorerange();
|
||||
document.execCommand('insertHTML', false, html);
|
||||
}
|
||||
|
||||
RE.insertLink = function(url, title) {
|
||||
RE.restorerange();
|
||||
var sel = document.getSelection();
|
||||
if (sel.toString().length == 0) {
|
||||
document.execCommand("insertHTML",false,"<a href='"+url+"'>"+title+"</a>");
|
||||
} else if (sel.rangeCount) {
|
||||
var el = document.createElement("a");
|
||||
el.setAttribute("href", url);
|
||||
el.setAttribute("title", title);
|
||||
|
||||
var range = sel.getRangeAt(0).cloneRange();
|
||||
range.surroundContents(el);
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range);
|
||||
}
|
||||
RE.callback();
|
||||
}
|
||||
|
||||
RE.setTodo = function(text) {
|
||||
var html = '<input type="checkbox" name="'+ text +'" value="'+ text +'"/> ';
|
||||
document.execCommand('insertHTML', false, html);
|
||||
}
|
||||
|
||||
RE.prepareInsert = function() {
|
||||
RE.backuprange();
|
||||
}
|
||||
|
||||
RE.backuprange = function(){
|
||||
var selection = window.getSelection();
|
||||
if (selection.rangeCount > 0) {
|
||||
var range = selection.getRangeAt(0);
|
||||
RE.currentSelection = {
|
||||
"startContainer": range.startContainer,
|
||||
"startOffset": range.startOffset,
|
||||
"endContainer": range.endContainer,
|
||||
"endOffset": range.endOffset};
|
||||
}
|
||||
}
|
||||
|
||||
RE.restorerange = function(){
|
||||
try {
|
||||
var selection = window.getSelection();
|
||||
selection.removeAllRanges();
|
||||
var range = document.createRange();
|
||||
range.setStart(RE.currentSelection.startContainer, RE.currentSelection.startOffset);
|
||||
range.setEnd(RE.currentSelection.endContainer, RE.currentSelection.endOffset);
|
||||
selection.addRange(range);
|
||||
} catch(error) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
RE.enabledEditingItems = function(e) {
|
||||
var items = [];
|
||||
if (document.queryCommandState('bold')) {
|
||||
items.push('bold');
|
||||
}
|
||||
if (document.queryCommandState('italic')) {
|
||||
items.push('italic');
|
||||
}
|
||||
if (document.queryCommandState('subscript')) {
|
||||
items.push('subscript');
|
||||
}
|
||||
if (document.queryCommandState('superscript')) {
|
||||
items.push('superscript');
|
||||
}
|
||||
if (document.queryCommandState('strikeThrough')) {
|
||||
items.push('strikeThrough');
|
||||
}
|
||||
if (document.queryCommandState('underline')) {
|
||||
items.push('underline');
|
||||
}
|
||||
if (document.queryCommandState('insertOrderedList')) {
|
||||
items.push('orderedList');
|
||||
}
|
||||
if (document.queryCommandState('insertUnorderedList')) {
|
||||
items.push('unorderedList');
|
||||
}
|
||||
if (document.queryCommandState('justifyCenter')) {
|
||||
items.push('justifyCenter');
|
||||
}
|
||||
if (document.queryCommandState('justifyFull')) {
|
||||
items.push('justifyFull');
|
||||
}
|
||||
if (document.queryCommandState('justifyLeft')) {
|
||||
items.push('justifyLeft');
|
||||
}
|
||||
if (document.queryCommandState('justifyRight')) {
|
||||
items.push('justifyRight');
|
||||
}
|
||||
if (document.queryCommandState('insertHorizontalRule')) {
|
||||
items.push('horizontalRule');
|
||||
}
|
||||
var formatBlock = document.queryCommandValue('formatBlock');
|
||||
if (formatBlock.length > 0) {
|
||||
items.push(formatBlock);
|
||||
}
|
||||
|
||||
window.location.href = "re-state://" + encodeURI(items.join(','));
|
||||
}
|
||||
|
||||
RE.focus = function() {
|
||||
var range = document.createRange();
|
||||
range.selectNodeContents(RE.editor);
|
||||
range.collapse(false);
|
||||
var selection = window.getSelection();
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
RE.editor.focus();
|
||||
}
|
||||
|
||||
RE.blurFocus = function() {
|
||||
RE.editor.blur();
|
||||
}
|
||||
|
||||
RE.removeFormat = function() {
|
||||
document.execCommand('removeFormat', false, null);
|
||||
}
|
||||
|
||||
RE.insertCustomStyleLink = function(data) {
|
||||
var entity = JSON.parse(data)
|
||||
var html = "<br/><div class='"+ entity.type +"-container'>\n" +
|
||||
" <a class='"+ entity.type +"' href=\"javascript:void(0);\" contenteditable=\"false\" onclick=\"customLinkgo(this)\" data-datas='"+ data +"'>\n" +
|
||||
" <div class='flex-container'>\n" +
|
||||
" <div class='gh-internal-content img-left'>\n" +
|
||||
" <img class = \"image-link\" src='"+ entity.icon +"' />\n" +
|
||||
" </div>\n" +
|
||||
" <div class='gh-internal-content content-right'>\n" +
|
||||
" <p class='content-title'>"+ entity.title +"</p>\n" +
|
||||
" <p class='contents'>"+ entity.brief +"</p>\n" +
|
||||
" </div>\n" +
|
||||
" </div>\n" +
|
||||
" </a>\n" +
|
||||
" </div><br/>"
|
||||
var tags = "", gameHtml = ""
|
||||
if (entity.tags != null) {
|
||||
for (var i = 0; i < entity.tags.length; i++) {
|
||||
tags += "<label>"+ entity.tags[i]+"</label>"
|
||||
}
|
||||
|
||||
gameHtml = "<br/><div class='"+ entity.type +"-container'>\n" +
|
||||
" <a class='"+ entity.type +"' href=\"javascript:void(0);\" contenteditable=\"false\" onclick=\"customLinkgo(this)\" data-datas='"+ data +"'>\n" +
|
||||
" <div class='flex-container'>\n" +
|
||||
" <div class='gh-internal-content img-left'>\n" +
|
||||
" <img class='image-link' src='"+ entity.icon +"' />\n" +
|
||||
" </div>\n" +
|
||||
" <div class='gh-internal-content content-right'>\n" +
|
||||
" <p class='content-title'>"+ entity.title +"</p>\n" +
|
||||
" <p class='tags'>"+ tags +"</p>\n" +
|
||||
" </div>\n" +
|
||||
" </div>\n" +
|
||||
" </a></div><br/>"
|
||||
}
|
||||
|
||||
switch(entity.type) {
|
||||
case "answer":
|
||||
document.execCommand("insertHTML",false, html);
|
||||
break
|
||||
case "community_article":
|
||||
document.execCommand("insertHTML",false, html);
|
||||
break
|
||||
case "game":
|
||||
document.execCommand("insertHTML",false, gameHtml);
|
||||
break
|
||||
}
|
||||
RE.callback();
|
||||
}
|
||||
|
||||
RE.showLinkStyle = function() {
|
||||
var answerElement = document.getElementsByClassName("answer-container");
|
||||
for (var i=0;i<answerElement.length;i+=1){
|
||||
answerElement[i].style.display = 'inline';
|
||||
}
|
||||
var articleElement = document.getElementsByClassName("community_article-container");
|
||||
for (var i=0;i<articleElement.length;i+=1){
|
||||
articleElement[i].style.display = 'inline';
|
||||
}
|
||||
var gameElement = document.getElementsByClassName("game-container");
|
||||
for (var i=0;i<gameElement.length;i+=1){
|
||||
gameElement[i].style.display = 'inline';
|
||||
}
|
||||
}
|
||||
|
||||
RE.hideLinkStyle = function() {
|
||||
var answerElement = document.getElementsByClassName("answer-container");
|
||||
for (var i=0;i<answerElement.length;i+=1){
|
||||
answerElement[i].style.display = 'none';
|
||||
}
|
||||
var articleElement = document.getElementsByClassName("community_article-container");
|
||||
for (var i=0;i<articleElement.length;i+=1){
|
||||
articleElement[i].style.display = 'none';
|
||||
}
|
||||
var gameElement = document.getElementsByClassName("game-container");
|
||||
for (var i=0;i<gameElement.length;i+=1){
|
||||
gameElement[i].style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// Event Listeners
|
||||
RE.editor.addEventListener("input", RE.callback);
|
||||
|
||||
RE.editor.addEventListener("keyup", function(e) {
|
||||
var KEY_LEFT = 37, KEY_RIGHT = 39;
|
||||
if (e.which == KEY_LEFT || e.which == KEY_RIGHT) {
|
||||
RE.enabledEditingItems(e);
|
||||
}
|
||||
RE.sendElementNameToNative()
|
||||
});
|
||||
|
||||
RE.editor.addEventListener("click", function(e) {
|
||||
RE.enabledEditingItems
|
||||
RE.sendElementNameToNative()
|
||||
var s = document.getSelection()
|
||||
var isNeedRemoveR = RE.recursion(e.target)
|
||||
if (isNeedRemoveR && s.rangeCount) {
|
||||
s.removeAllRanges()
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("selectionchange", function(e) {
|
||||
RE.sendElementNameToNative()
|
||||
});
|
||||
|
||||
RE.recursion = function(dom) {
|
||||
var parenDom = dom.parentElement
|
||||
if (parenDom && parenDom instanceof Element &&
|
||||
typeClassList.indexOf(parenDom.className) > -1) {
|
||||
return parenDom
|
||||
} else if(parenDom && parenDom instanceof Element &&
|
||||
typeClassList.indexOf(parenDom.className) === -1 && parenDom.nodeName !== 'BODY') {
|
||||
return RE.recursion(parenDom)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
// 返回组件标签 多个标签以"空格"划分
|
||||
RE.sendElementNameToNative = function() {
|
||||
if (window.getSelection) {
|
||||
var selection = window.getSelection()
|
||||
if (selection.rangeCount > 0) {
|
||||
var range = selection.getRangeAt(0);
|
||||
var container = range.startContainer;
|
||||
var elements = " " + container.localName + " ";
|
||||
var parentElement;
|
||||
while(true) {
|
||||
if(parentElement != null) {
|
||||
parentElement = parentElement.parentElement
|
||||
} else {
|
||||
parentElement = container.parentElement
|
||||
}
|
||||
if (parentElement == null || parentElement.localName == null) {
|
||||
break;
|
||||
}
|
||||
elements = elements + " " + parentElement.localName + " "
|
||||
}
|
||||
// console.log(elements)
|
||||
window.OnCursorChangeListener.onElements(elements);
|
||||
}
|
||||
}
|
||||
}
|
||||
43
app/src/main/assets/style.css
Normal file
43
app/src/main/assets/style.css
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (C) 2017 Wasabeef
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@charset "UTF-8";
|
||||
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow: scroll;
|
||||
display: table;
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
min-height:100%;
|
||||
}
|
||||
|
||||
#editor {
|
||||
display: table-cell;
|
||||
outline: 0px solid transparent;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
#editor[placeholder]:empty:not(:focus):before {
|
||||
content: attr(placeholder);
|
||||
opacity: .5;
|
||||
}}
|
||||
BIN
app/src/main/assets/tab_community.gif
Normal file
BIN
app/src/main/assets/tab_community.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
BIN
app/src/main/assets/tab_mine.gif
Normal file
BIN
app/src/main/assets/tab_mine.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
BIN
app/src/main/assets/web_load_dfimg_icon.png
Normal file
BIN
app/src/main/assets/web_load_dfimg_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
2
app/src/main/assets/zepto.min.js
vendored
Normal file
2
app/src/main/assets/zepto.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -1,53 +0,0 @@
|
||||
package com.gc.materialdesign.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
public class CustomView extends RelativeLayout {
|
||||
|
||||
|
||||
final static String MATERIALDESIGNXML = "http://schemas.android.com/apk/res-auto";
|
||||
final static String ANDROIDXML = "http://schemas.android.com/apk/res/android";
|
||||
|
||||
final int disabledBackgroundColor = Color.parseColor("#E2E2E2");
|
||||
// Indicate if user touched this view the last time
|
||||
public boolean isLastTouch = false;
|
||||
int beforeBackground;
|
||||
boolean animation = false;
|
||||
|
||||
public CustomView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
super.setEnabled(enabled);
|
||||
if (enabled)
|
||||
setBackgroundColor(beforeBackground);
|
||||
else
|
||||
setBackgroundColor(disabledBackgroundColor);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
if (animation)
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAnimationStart() {
|
||||
super.onAnimationStart();
|
||||
animation = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAnimationEnd() {
|
||||
super.onAnimationEnd();
|
||||
animation = false;
|
||||
}
|
||||
}
|
||||
@ -1,174 +0,0 @@
|
||||
package com.gc.materialdesign.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.RectF;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
public class ProgressBarCircularIndeterminate extends CustomView {
|
||||
|
||||
final static String ANDROIDXML = "http://schemas.android.com/apk/res/android";
|
||||
|
||||
int backgroundColor = Color.parseColor("#1E88E5");
|
||||
float radius1 = 0;
|
||||
float radius2 = 0;
|
||||
int cont = 0;
|
||||
boolean firstAnimationOver = false;
|
||||
int arcD = 1;
|
||||
int arcO = 0;
|
||||
float rotateAngle = 0;
|
||||
int limite = 0;
|
||||
|
||||
public ProgressBarCircularIndeterminate(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
setAttributes(attrs);
|
||||
}
|
||||
|
||||
// Set atributtes of XML to View
|
||||
protected void setAttributes(AttributeSet attrs) {
|
||||
|
||||
setMinimumHeight(Utils.dpToPx(32, getResources()));
|
||||
setMinimumWidth(Utils.dpToPx(32, getResources()));
|
||||
|
||||
// Set background Color
|
||||
// Color by resource
|
||||
int bacgroundColor = attrs.getAttributeResourceValue(ANDROIDXML, "background", -1);
|
||||
if (bacgroundColor != -1) {
|
||||
setBackgroundColor(ContextCompat.getColor(getContext(), bacgroundColor));
|
||||
} else {
|
||||
// Color by hexadecimal
|
||||
int background = attrs.getAttributeIntValue(ANDROIDXML, "background", -1);
|
||||
if (background != -1) {
|
||||
setBackgroundColor(background);
|
||||
} else {
|
||||
setBackgroundColor(Color.parseColor("#1E88E5"));
|
||||
}
|
||||
}
|
||||
|
||||
setMinimumHeight(Utils.dpToPx(3, getResources()));
|
||||
|
||||
}
|
||||
|
||||
// Set color of background
|
||||
public void setBackgroundColor(int color) {
|
||||
super.setBackgroundColor(ContextCompat.getColor(getContext(), android.R.color.transparent));
|
||||
if (isEnabled()) {
|
||||
beforeBackground = backgroundColor;
|
||||
}
|
||||
this.backgroundColor = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
if (!firstAnimationOver) {
|
||||
drawFirstAnimation(canvas);
|
||||
}
|
||||
if (cont > 0) {
|
||||
drawSecondAnimation(canvas);
|
||||
}
|
||||
invalidate();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw first animation of view
|
||||
*
|
||||
* @param canvas
|
||||
*/
|
||||
private void drawFirstAnimation(Canvas canvas) {
|
||||
if (radius1 < getWidth() / 2) {
|
||||
Paint paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
paint.setColor(makePressColor());
|
||||
radius1 = (radius1 >= getWidth() / 2) ? (float) getWidth() / 2 : radius1 + 1;
|
||||
canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius1, paint);
|
||||
} else {
|
||||
Bitmap bitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
|
||||
Canvas temp = new Canvas(bitmap);
|
||||
Paint paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
paint.setColor(makePressColor());
|
||||
temp.drawCircle(getWidth() / 2, getHeight() / 2, getHeight() / 2, paint);
|
||||
Paint transparentPaint = new Paint();
|
||||
transparentPaint.setAntiAlias(true);
|
||||
transparentPaint.setColor(ContextCompat.getColor(getContext(), android.R.color.transparent));
|
||||
transparentPaint.setXfermode(new PorterDuffXfermode(
|
||||
PorterDuff.Mode.CLEAR));
|
||||
if (cont >= 50) {
|
||||
radius2 = (radius2 >= getWidth() / 2) ? (float) getWidth() / 2 : radius2 + 1;
|
||||
} else {
|
||||
radius2 = (radius2 >= getWidth() / 2 - Utils.dpToPx(4, getResources())) ?
|
||||
(float) getWidth() / 2 - Utils.dpToPx(4, getResources()) : radius2 + 1;
|
||||
}
|
||||
temp.drawCircle(getWidth() / 2, getHeight() / 2, radius2, transparentPaint);
|
||||
canvas.drawBitmap(bitmap, 0, 0, new Paint());
|
||||
if (radius2 >= getWidth() / 2 - Utils.dpToPx(4, getResources())) {
|
||||
cont++;
|
||||
}
|
||||
if (radius2 >= getWidth() / 2) {
|
||||
firstAnimationOver = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw second animation of view
|
||||
*
|
||||
* @param canvas
|
||||
*/
|
||||
private void drawSecondAnimation(Canvas canvas) {
|
||||
if (arcO == limite) {
|
||||
arcD += 6;
|
||||
}
|
||||
if (arcD >= 290 || arcO > limite) {
|
||||
arcO += 6;
|
||||
arcD -= 6;
|
||||
}
|
||||
if (arcO > limite + 290) {
|
||||
limite = arcO;
|
||||
arcO = limite;
|
||||
arcD = 1;
|
||||
}
|
||||
rotateAngle += 4;
|
||||
canvas.rotate(rotateAngle, getWidth() / 2, getHeight() / 2);
|
||||
|
||||
Bitmap bitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
|
||||
Canvas temp = new Canvas(bitmap);
|
||||
Paint paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
paint.setColor(backgroundColor);
|
||||
// temp.drawARGB(0, 0, 0, 255);
|
||||
temp.drawArc(new RectF(0, 0, getWidth(), getHeight()), arcO, arcD, true, paint);
|
||||
Paint transparentPaint = new Paint();
|
||||
transparentPaint.setAntiAlias(true);
|
||||
transparentPaint.setColor(ContextCompat.getColor(getContext(), android.R.color.transparent));
|
||||
transparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
|
||||
temp.drawCircle(getWidth() / 2, getHeight() / 2, (getWidth() / 2)
|
||||
- Utils.dpToPx(4, getResources()), transparentPaint);
|
||||
|
||||
canvas.drawBitmap(bitmap, 0, 0, new Paint());
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a dark color to ripple effect
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected int makePressColor() {
|
||||
int r = (this.backgroundColor >> 16) & 0xFF;
|
||||
int g = (this.backgroundColor >> 8) & 0xFF;
|
||||
int b = (this.backgroundColor >> 0) & 0xFF;
|
||||
// r = (r+90 > 245) ? 245 : r+90;
|
||||
// g = (g+90 > 245) ? 245 : g+90;
|
||||
// b = (b+90 > 245) ? 245 : b+90;
|
||||
return Color.argb(128, r, g, b);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
package com.gc.materialdesign.views;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
|
||||
public class Utils {
|
||||
|
||||
|
||||
/**
|
||||
* Convert Dp to Pixel
|
||||
*/
|
||||
public static int dpToPx(float dp, Resources resources) {
|
||||
float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, resources.getDisplayMetrics());
|
||||
return (int) px;
|
||||
}
|
||||
|
||||
public static int getRelativeTop(View myView) {
|
||||
// if (myView.getParent() == myView.getRootView())
|
||||
if (myView.getId() == android.R.id.content)
|
||||
return myView.getTop();
|
||||
else
|
||||
return myView.getTop() + getRelativeTop((View) myView.getParent());
|
||||
}
|
||||
|
||||
public static int getRelativeLeft(View myView) {
|
||||
// if (myView.getParent() == myView.getRootView())
|
||||
if (myView.getId() == android.R.id.content)
|
||||
return myView.getLeft();
|
||||
else
|
||||
return myView.getLeft() + getRelativeLeft((View) myView.getParent());
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,244 +0,0 @@
|
||||
package com.gh.base;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManager.RunningAppProcessInfo;
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.os.Process;
|
||||
import android.support.multidex.MultiDex;
|
||||
import android.support.v4.util.ArrayMap;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.gh.EventBusIndex;
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.common.util.DataUtils;
|
||||
import com.gh.common.util.StringUtils;
|
||||
import com.gh.common.util.TokenUtils;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.leon.channel.helper.ChannelReaderUtil;
|
||||
import com.lightgame.utils.Utils;
|
||||
import com.umeng.message.IUmengRegisterCallback;
|
||||
import com.umeng.message.PushAgent;
|
||||
import com.umeng.message.UTrack;
|
||||
import com.xiaomi.channel.commonutils.logger.LoggerInterface;
|
||||
import com.xiaomi.mipush.sdk.Logger;
|
||||
import com.xiaomi.mipush.sdk.MiPushClient;
|
||||
import com.xiaomi.mipush.sdk.MiPushCommandMessage;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class AppController extends Application {
|
||||
|
||||
public static final String TAG = AppController.class.getSimpleName();
|
||||
public static final String KEY_FILE_INFO = "FileInfo";
|
||||
//快传文件发送单线程
|
||||
public static Executor FILE_SENDER_EXECUTOR = Executors.newSingleThreadExecutor();
|
||||
//快传文件发送主要的线程池
|
||||
public static Executor MAIN_EXECUTOR = Executors.newCachedThreadPool();
|
||||
private static AppController mInstance;
|
||||
private static ArrayMap<String, Object> objectMap = new ArrayMap<>();
|
||||
|
||||
private String mChannel;
|
||||
|
||||
public static void put(String key, Object object) {
|
||||
if (objectMap == null) {
|
||||
objectMap = new ArrayMap<>();
|
||||
}
|
||||
objectMap.put(key, object);
|
||||
}
|
||||
|
||||
public static Object get(String key, boolean isRemove) {
|
||||
if (objectMap == null) {
|
||||
return null;
|
||||
}
|
||||
if (isRemove) {
|
||||
return objectMap.remove(key);
|
||||
} else {
|
||||
return objectMap.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
public static void remove(String key) {
|
||||
if (objectMap == null) {
|
||||
return;
|
||||
}
|
||||
objectMap.remove(key);
|
||||
}
|
||||
|
||||
public static synchronized AppController getInstance() {
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
public String getChannel() {
|
||||
return mChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context base) {
|
||||
super.attachBaseContext(base);
|
||||
MultiDex.install(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
mInstance = this;
|
||||
|
||||
//TODO 强烈不建议开发阶段开启这个Handler,必须处理错误
|
||||
if (!BuildConfig.DEBUG) {
|
||||
AppUncaughtHandler appUncaughtHandler = new AppUncaughtHandler(this);
|
||||
Thread.setDefaultUncaughtExceptionHandler(appUncaughtHandler);
|
||||
}
|
||||
|
||||
mChannel = ChannelReaderUtil.getChannel(this);
|
||||
if (TextUtils.isEmpty(mChannel)) {
|
||||
//默认用Android Studio run时并没有写入channel magic number到apk包里面,所以需要fallback
|
||||
mChannel = "GH_TEST";
|
||||
}
|
||||
|
||||
Log.e("CHANNEL_ID", mChannel);
|
||||
|
||||
//初始化Fresco
|
||||
Fresco.initialize(this);
|
||||
|
||||
DataUtils.init(this, BuildConfig.DEBUG, mChannel);
|
||||
|
||||
//测试MTA崩溃的,坑爹
|
||||
// if (BuildConfig.DEBUG) {
|
||||
// StatConfig.setDebugEnable(true);
|
||||
// StatConfig.setStatSendStrategy(StatReportStrategy.DEVELOPER);
|
||||
// throw new RuntimeException("test again");
|
||||
// }
|
||||
|
||||
// if (BuildConfig.DEBUG) {
|
||||
// Stetho.initializeWithDefaults(this);
|
||||
// }
|
||||
|
||||
/**
|
||||
* 注册push服务,注册成功后会向{@link GHPushMessageReceiver}发送广播
|
||||
* 可以从{@link GHPushMessageReceiver#onCommandResult(Context, MiPushCommandMessage)}
|
||||
* 的{@link MiPushCommandMessage} 对象参数中获取注册信息
|
||||
*/
|
||||
try {
|
||||
if (shouldInit()) {
|
||||
MiPushClient.registerPush(this, Config.MIPUSH_APPID, Config.MIPUSH_APPKEY);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
LoggerInterface newLogger = new LoggerInterface() {
|
||||
|
||||
@Override
|
||||
public void setTag(String tag) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String content) {
|
||||
Log.d(TAG, content);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String content, Throwable t) {
|
||||
Log.d(TAG, content, t);
|
||||
}
|
||||
};
|
||||
Logger.setLogger(this, newLogger);
|
||||
}
|
||||
|
||||
try {
|
||||
//友盟推送
|
||||
final PushAgent pushAgent = PushAgent.getInstance(this);
|
||||
pushAgent.setAppkeyAndSecret(Config.UMENG_APPKEY, Config.UMENG_MESSAGE_SECRET);
|
||||
|
||||
//注册推送服务,每次调用register方法都会回调该接口
|
||||
pushAgent.register(new IUmengRegisterCallback() {
|
||||
|
||||
@Override
|
||||
public void onSuccess(String deviceToken) {
|
||||
//注册成功会返回device token
|
||||
Utils.log("deviceToken::" + deviceToken);
|
||||
|
||||
//设置别名
|
||||
pushAgent.addExclusiveAlias(TokenUtils.getDeviceId(getApplicationContext()),
|
||||
"GHDID", new UTrack.ICallBack() {
|
||||
@Override
|
||||
public void onMessage(boolean b, String s) {
|
||||
Utils.log(StringUtils.buildString("ExclusiveAlias::", String.valueOf(b), "==", s));
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(String s, String s1) {
|
||||
Utils.log("deviceToken::" + "注册失败");
|
||||
}
|
||||
});
|
||||
|
||||
// 友盟推送数据处理
|
||||
pushAgent.setNotificationClickHandler(new GHUmengNotificationClickHandler());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// // 监听屏幕状态广播
|
||||
// if (shouldInit()) {
|
||||
// UnlockScreenReceiver unlockScreenReceiver = new UnlockScreenReceiver();
|
||||
// IntentFilter intentFilter = new IntentFilter();
|
||||
// intentFilter.addAction(Intent.ACTION_SCREEN_ON);
|
||||
// intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
// registerReceiver(unlockScreenReceiver, intentFilter);
|
||||
//
|
||||
// // 用户App运行数据统计服务
|
||||
// Intent intent = new Intent(getApplicationContext(), AppStaticService.class);
|
||||
// startService(intent);
|
||||
//
|
||||
// AppRunTimeDao dao = new AppRunTimeDao(getApplicationContext());
|
||||
// for (AppRunTimeInfo appRunTimeInfo : dao.getAll()) {
|
||||
// Utils.log(appRunTimeInfo.getPackageName() + "====1111=====" + appRunTimeInfo.getRunTime());
|
||||
// }
|
||||
// }
|
||||
|
||||
// 启用EventBus3.0加速功能
|
||||
EventBus.builder().addIndex(new EventBusIndex()).installDefaultEventBus();
|
||||
}
|
||||
|
||||
private boolean shouldInit() {
|
||||
ActivityManager am = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE));
|
||||
List<RunningAppProcessInfo> processInfos = am.getRunningAppProcesses();
|
||||
String mainProcessName = getPackageName();
|
||||
Log.d(TAG, mainProcessName);
|
||||
int myPid = Process.myPid();
|
||||
for (RunningAppProcessInfo info : processInfos) {
|
||||
if (info.pid == myPid && mainProcessName.equals(info.processName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// public static String getProcessName(Context cxt, int pid) {
|
||||
// ActivityManager am = (ActivityManager) cxt.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
// List<RunningAppProcessInfo> runningApps = am.getRunningAppProcesses();
|
||||
// if (runningApps == null) {
|
||||
// return null;
|
||||
// }
|
||||
// for (RunningAppProcessInfo procInfo : runningApps) {
|
||||
// if (procInfo.pid == pid) {
|
||||
// return procInfo.processName;
|
||||
// }
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
|
||||
}
|
||||
@ -5,16 +5,18 @@ import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Looper;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
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.RuntimeUtils;
|
||||
import com.tencent.stat.StatService;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
@ -26,80 +28,58 @@ import java.util.Locale;
|
||||
|
||||
public class AppUncaughtHandler implements UncaughtExceptionHandler {
|
||||
|
||||
private UncaughtExceptionHandler mDefaultHandler;
|
||||
private Context mContext;
|
||||
|
||||
public AppUncaughtHandler(Context context) {
|
||||
// 获取系统默认的UncaughtException处理器
|
||||
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uncaughtException(Thread thread, Throwable ex) {
|
||||
if (!handleException(ex) && mDefaultHandler != null) {
|
||||
// 如果用户没有处理则让系统默认的异常处理器来处理
|
||||
mDefaultHandler.uncaughtException(thread, ex);
|
||||
} else {
|
||||
RuntimeUtils.getInstance().runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(mContext.getApplicationContext(),
|
||||
"\"光环助手\"发生错误", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Looper.prepare();
|
||||
Utils.toast(mContext.getApplicationContext(), "\"光环助手\"发生错误");
|
||||
Looper.loop();
|
||||
}
|
||||
|
||||
// 防止重复奔溃,导致助手一直重启,20秒内不做处理
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||
long time = sp.getLong("last_restart_time", 0);
|
||||
if (System.currentTimeMillis() - time > 20 * 1000) {
|
||||
sp.edit().putLong("last_restart_time", System.currentTimeMillis()).apply();
|
||||
Intent intent = new Intent(mContext, SplashScreenActivity.class);
|
||||
intent.setAction(Intent.ACTION_MAIN);
|
||||
intent.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||
PendingIntent restartIntent = PendingIntent.getActivity(mContext, 0, intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
// 退出程序并重启
|
||||
AlarmManager mgr = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
|
||||
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, restartIntent); // 1秒钟后重启应用
|
||||
}
|
||||
AppManager.getInstance().finishAllActivity();
|
||||
}
|
||||
});
|
||||
saveLocalLog(mContext, ex);
|
||||
restart(mContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
|
||||
*
|
||||
* @param ex
|
||||
* @return true:如果处理了该异常信息;否则返回false.
|
||||
*/
|
||||
private boolean handleException(Throwable ex) {
|
||||
if (ex == null) {
|
||||
return false;
|
||||
public static void restart(final Context context) {
|
||||
|
||||
// 防止重复奔溃,导致助手一直重启,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秒钟后重启应用
|
||||
}
|
||||
saveLog(ex);
|
||||
return true;
|
||||
|
||||
//error restart
|
||||
// System.exit(2);
|
||||
AppManager.getInstance().finishAllActivity();
|
||||
}
|
||||
|
||||
// 保存log到本地
|
||||
private void saveLog(Throwable ex) {
|
||||
public static void saveLocalLog(Context context, Throwable ex) {
|
||||
String errorMsg = Log.getStackTraceString(ex);
|
||||
|
||||
// MTA主动上传错误
|
||||
// StatService.reportError(mContext.getApplicationContext(), errorMsg);
|
||||
StatService.reportException(mContext, ex);
|
||||
|
||||
// 上传错误数据
|
||||
DataCollectionUtils.uploadError(mContext, errorMsg);
|
||||
Config.setExceptionMsg(errorMsg);
|
||||
|
||||
// 保存到本地
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.getDefault());
|
||||
File file = new File(FileUtils.getLogPath(mContext.getApplicationContext(),
|
||||
File file = new File(FileUtils.getLogPath(context.getApplicationContext(),
|
||||
format.format(new Date()) + "_gh_assist" + ".log"));
|
||||
FileWriter writer = null;
|
||||
try {
|
||||
@ -120,4 +100,25 @@ public class AppUncaughtHandler implements UncaughtExceptionHandler {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 下次应用启动再上报
|
||||
*
|
||||
* @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,153 +1,238 @@
|
||||
package com.gh.base;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.text.TextUtils;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.gh.common.util.DataUtils;
|
||||
import com.gh.common.constant.Constants;
|
||||
import com.gh.common.util.DialogUtils;
|
||||
import com.gh.common.util.MtaHelper;
|
||||
import com.gh.common.util.PackageUtils;
|
||||
import com.gh.common.util.RunningUtils;
|
||||
import com.gh.common.util.ShareUtils;
|
||||
import com.gh.download.DownloadManager;
|
||||
import com.gh.common.util.StringUtils;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.LoginActivity;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.eventbus.EBShowDialog;
|
||||
import com.lightgame.BaseAppCompatActivity;
|
||||
import com.lightgame.download.FileUtils;
|
||||
import com.lightgame.utils.AppManager;
|
||||
import com.readystatesoftware.systembartint.SystemBarTintManager.SystemBarConfig;
|
||||
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.util.ArrayList;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import butterknife.ButterKnife;
|
||||
import pub.devrel.easypermissions.EasyPermissions;
|
||||
|
||||
import static com.gh.common.util.EntranceUtils.KEY_DATA;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_ENTRANCE;
|
||||
|
||||
public abstract class BaseActivity extends BaseAppCompatToolBarActivity {
|
||||
/**
|
||||
* 只提供基础的服务(EventBus/ButterKnife/Share/GlobalDialog/Permissions)
|
||||
* <p>
|
||||
* 需要工具栏的页面请继承{@link ToolBarActivity}
|
||||
*/
|
||||
|
||||
public abstract class BaseActivity extends BaseAppCompatActivity implements EasyPermissions.PermissionCallbacks {
|
||||
|
||||
// global dialog key
|
||||
public final static String DOWNLOAD_HIJACK = "hijack";
|
||||
public final static String LOGIN_EXCEPTION = "loginException";
|
||||
public final static String PLUGGABLE = "plugin";
|
||||
|
||||
@NonNull
|
||||
protected String mEntrance;
|
||||
private boolean mIsPause;
|
||||
|
||||
private boolean mIsExistLogoutDialog;
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
init(mContentView);
|
||||
AppManager.getInstance().addActivity(this);
|
||||
EventBus.getDefault().register(this);
|
||||
mEntrance = getIntent().getStringExtra(KEY_ENTRANCE);
|
||||
if (getIntent().getBundleExtra(KEY_DATA) != null) {
|
||||
mEntrance = getIntent().getBundleExtra(KEY_DATA).getString(KEY_ENTRANCE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onNavigationIconClicked() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void init(View contentView) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
SystemBarConfig config = getTintManager().getConfig();
|
||||
contentView.setPadding(0, config.getPixelInsetTop(false), 0, config.getPixelInsetBottom());
|
||||
}
|
||||
setContentView(contentView);
|
||||
|
||||
ButterKnife.bind(this);
|
||||
|
||||
View back = findViewById(R.id.actionbar_rl_back);
|
||||
if (back != null)
|
||||
back.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void initTitle(String title) {
|
||||
TextView actionbar_tv_title = (TextView) findViewById(R.id.actionbar_tv_title);
|
||||
actionbar_tv_title.setText(title);
|
||||
// setNavigationTitle(title);
|
||||
}
|
||||
|
||||
public void toast(String msg) {
|
||||
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
public void toast(int msg) {
|
||||
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
//如果是游戏分享,newsTitle默认为空
|
||||
public void showShare(String url, String gameName, String icon, String newsTitle, ArrayList<String> tag, boolean isToolsBox) {
|
||||
|
||||
//判断是否是官方版
|
||||
boolean isPlugin = false;
|
||||
if (tag != null) {
|
||||
for (String s : tag) {
|
||||
if (!"官方版".equals(s)) {
|
||||
isPlugin = true;
|
||||
}
|
||||
}
|
||||
mEntrance = getIntent().getStringExtra(KEY_ENTRANCE);
|
||||
if (TextUtils.isEmpty(mEntrance)) {
|
||||
mEntrance = Constants.ENTRANCE_UNKNOWN;
|
||||
}
|
||||
|
||||
ShareUtils.getInstance(this).showShareWindows(getWindow().getDecorView(), url, gameName, icon, newsTitle, isPlugin, true, isToolsBox);
|
||||
|
||||
if (newsTitle == null) {
|
||||
DataUtils.onEvent(this, "内容分享", gameName);
|
||||
} else {
|
||||
DataUtils.onEvent(this, "内容分享", newsTitle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onEventMainThread(final EBShowDialog showDialog) {
|
||||
if (!mIsPause && this.getClass().getName().equals(RunningUtils.getTopActivity(this))) {
|
||||
if ("hijack".equals(showDialog.getType())) {
|
||||
DialogUtils.showQqSessionDialog(this, "2586716223");// 建议用户联系客服
|
||||
} else if ("plugin".equals(showDialog.getType())) {
|
||||
DialogUtils.showPluginDialog(this, new DialogUtils.ConfirmListener() {
|
||||
@Override
|
||||
public void onConfirm() {
|
||||
if (FileUtils.isEmptyFile(showDialog.getPath())) {
|
||||
Toast.makeText(BaseActivity.this, "解析包出错(可能被误删了),请重新下载", Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
startActivity(PackageUtils.getUninstallIntent(BaseActivity.this, showDialog.getPath()));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("ACTIVITY_ENTRANCE -> " + mEntrance);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
EventBus.getDefault().unregister(this);
|
||||
AppManager.getInstance().finishActivity(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.ShareType shareType) {
|
||||
ShareUtils.getInstance(this).showShareWindows(this,
|
||||
getWindow().getDecorView(),
|
||||
url,
|
||||
icon,
|
||||
shareTitle,
|
||||
shareSummary,
|
||||
shareType);
|
||||
if (shareType == ShareUtils.ShareType.game || shareType == ShareUtils.ShareType.plugin) {
|
||||
MtaHelper.onEvent("内容分享", shareTitle + shareSummary);
|
||||
} else {
|
||||
MtaHelper.onEvent("内容分享", shareTitle);
|
||||
}
|
||||
}
|
||||
|
||||
@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())) {
|
||||
DialogUtils.showPluginDialog(this, () -> {
|
||||
if (FileUtils.isEmptyFile(showDialog.getPath())) {
|
||||
toast(R.string.install_failure_hint);
|
||||
} else {
|
||||
startActivity(PackageUtils.getUninstallIntent(BaseActivity.this, showDialog.getPath()));
|
||||
}
|
||||
});
|
||||
} 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
|
||||
, () -> startActivity(LoginActivity.getIntent(BaseActivity.this,
|
||||
"你的账号已在另外一台设备登录多设备-重新登录"))
|
||||
);
|
||||
mBaseHandler.postDelayed(() -> mIsExistLogoutDialog = false, 5000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
DataUtils.onPause(this);
|
||||
mIsPause = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
DataUtils.onResume(this);
|
||||
mIsPause = false;
|
||||
DownloadManager.getInstance(this).initGameMap();
|
||||
}
|
||||
|
||||
@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, ")");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
113
app/src/main/java/com/gh/base/BaseActivity_TabLayout.java
Normal file
113
app/src/main/java/com/gh/base/BaseActivity_TabLayout.java
Normal file
@ -0,0 +1,113 @@
|
||||
package com.gh.base;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
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.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
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 65;
|
||||
}
|
||||
|
||||
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);
|
||||
mFragmentsList = new ArrayList<>();
|
||||
initFragmentList(mFragmentsList);
|
||||
mTabTitleList = new ArrayList<>();
|
||||
initTabTitleList(mTabTitleList);
|
||||
|
||||
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;
|
||||
View tabView = provideTabView(i, tab.getText() != null ? tab.getText().toString() : "");
|
||||
if (tabView == null) continue;
|
||||
tab.setCustomView(tabView);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,154 +0,0 @@
|
||||
package com.gh.base;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.gh.gamecenter.R;
|
||||
import com.lightgame.BaseAppCompatActivity;
|
||||
import com.lightgame.ToolbarContainer;
|
||||
import com.lightgame.ToolbarController;
|
||||
import com.readystatesoftware.systembartint.SystemBarTintManager;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Created by csheng on 15-10-12.
|
||||
*/
|
||||
@ToolbarContainer
|
||||
public abstract class BaseAppCompatToolBarActivity extends BaseAppCompatActivity implements ToolbarController {
|
||||
|
||||
private Toolbar mToolbar;
|
||||
private SystemBarTintManager mTintManager;
|
||||
|
||||
// TODO 获取沉浸栏管理,要进行版本判断或者判断是否为空
|
||||
public SystemBarTintManager getTintManager() {
|
||||
return mTintManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
initToolbar();
|
||||
// Util_Window.initStatusBarColor(getWindow(), ContextCompat.getColor(this, R.color.theme));
|
||||
initStatusBar();
|
||||
}
|
||||
|
||||
private void initToolbar() {
|
||||
mToolbar = (Toolbar) findViewById(R.id.toolbar_navigation);
|
||||
if (mToolbar != null) {
|
||||
// mToolbar.setTitle("");
|
||||
setSupportActionBar(mToolbar);
|
||||
mToolbar.addView(View.inflate(this, R.layout.reuse_actionbar, null));
|
||||
getSupportActionBar().setHomeButtonEnabled(false);
|
||||
// getSupportActionBar().setDisplayHomeAsUpEnabled(false);
|
||||
// getSupportActionBar().setDisplayShowHomeEnabled(false);
|
||||
// getSupportActionBar().setDisplayOptions();
|
||||
}
|
||||
}
|
||||
|
||||
private void initStatusBar() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
setTranslucentStatus(true);
|
||||
mTintManager = new SystemBarTintManager(this);
|
||||
mTintManager.setStatusBarTintEnabled(true);
|
||||
// mTintManager.setNavigationBarTintEnabled(true);
|
||||
if (Build.MANUFACTURER.equals("Meizu") || Build.MANUFACTURER.equals("Xiaomi")) {
|
||||
mTintManager.setStatusBarTintColor(Color.WHITE);
|
||||
} else {
|
||||
mTintManager.setStatusBarTintColor(Color.BLACK);
|
||||
}
|
||||
|
||||
switch (Build.MANUFACTURER) {
|
||||
case "Meizu":
|
||||
try {
|
||||
Window window = getWindow();
|
||||
if (window != null) {
|
||||
WindowManager.LayoutParams lp = window.getAttributes();
|
||||
Field darkFlag = WindowManager.LayoutParams.class.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
|
||||
Field meizuFlags = WindowManager.LayoutParams.class.getDeclaredField("meizuFlags");
|
||||
darkFlag.setAccessible(true);
|
||||
meizuFlags.setAccessible(true);
|
||||
int bit = darkFlag.getInt(null);
|
||||
int value = meizuFlags.getInt(lp);
|
||||
value |= bit;
|
||||
meizuFlags.setInt(lp, value);
|
||||
window.setAttributes(lp);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
break;
|
||||
case "Xiaomi":
|
||||
try {
|
||||
Window window = getWindow();
|
||||
if (window != null) {
|
||||
Class<?> clazz = window.getClass();
|
||||
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(window, darkModeFlag, darkModeFlag);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||
protected void setTranslucentStatus(boolean status) {
|
||||
Window window = getWindow();
|
||||
WindowManager.LayoutParams winParams = window.getAttributes();
|
||||
final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
|
||||
if (status) {
|
||||
winParams.flags |= bits;
|
||||
} else {
|
||||
winParams.flags &= ~bits;
|
||||
}
|
||||
window.setAttributes(winParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
return onNavigationIconClicked();
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
protected abstract boolean onNavigationIconClicked();
|
||||
|
||||
@Override
|
||||
public void setNavigationTitle(int res) {
|
||||
if (mToolbar != null) {
|
||||
mToolbar.setTitle(res);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNavigationTitle(CharSequence res) {
|
||||
if (mToolbar != null) {
|
||||
mToolbar.setTitle(res);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Toolbar getToolBar() {
|
||||
return mToolbar;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,397 +0,0 @@
|
||||
//package com.gh.base;
|
||||
//
|
||||
//import android.content.Intent;
|
||||
//import android.os.Bundle;
|
||||
//import android.support.v4.content.ContextCompat;
|
||||
//import android.support.v7.widget.RecyclerView;
|
||||
//import android.text.TextUtils;
|
||||
//import android.view.View;
|
||||
//import android.widget.ImageView;
|
||||
//import android.widget.LinearLayout;
|
||||
//import android.widget.ProgressBar;
|
||||
//import android.widget.RelativeLayout;
|
||||
//import android.widget.TextView;
|
||||
//
|
||||
//import com.gh.common.constant.Config;
|
||||
//import com.gh.common.util.ApkActiveUtils;
|
||||
//import com.gh.common.util.DataUtils;
|
||||
//import com.gh.common.util.DialogUtils;
|
||||
//import com.gh.common.util.DisplayUtils;
|
||||
//import com.gh.common.util.GameUtils;
|
||||
//import com.gh.common.util.NetworkUtils;
|
||||
//import com.gh.common.util.PackageUtils;
|
||||
//import com.gh.common.util.ShareUtils;
|
||||
//import com.gh.common.view.DownloadDialog;
|
||||
//import com.gh.download.DownloadManager;
|
||||
//import com.gh.gamecenter.DownloadManagerActivity;
|
||||
//import com.gh.gamecenter.R;
|
||||
//import com.gh.gamecenter.entity.ApkEntity;
|
||||
//import com.gh.gamecenter.entity.GameEntity;
|
||||
//import com.gh.gamecenter.eventbus.EBDownloadStatus;
|
||||
//import com.gh.gamecenter.eventbus.EBPackage;
|
||||
//import com.gh.gamecenter.manager.PackageManager;
|
||||
//import com.lightgame.download.DataWatcher;
|
||||
//import com.lightgame.download.DownloadEntity;
|
||||
//import com.lightgame.download.FileUtils;
|
||||
//import com.tencent.tauth.Tencent;
|
||||
//
|
||||
//import org.greenrobot.eventbus.Subscribe;
|
||||
//import org.greenrobot.eventbus.ThreadMode;
|
||||
//
|
||||
///**
|
||||
// * Created by Administrator on 2016/9/19.
|
||||
// * 游戏详情、新闻详情基类(控制底部下载栏)
|
||||
// */
|
||||
//public abstract class BaseDetailActivity extends BaseActivity implements View.OnClickListener {
|
||||
//
|
||||
// protected TextView actionbar_tv_title;
|
||||
// protected RecyclerView detail_rv_show;
|
||||
// protected LinearLayout detail_ll_bottom;
|
||||
// protected TextView detail_tv_download;
|
||||
// protected ProgressBar detail_pb_progressbar;
|
||||
// protected TextView detail_tv_per;
|
||||
// protected LinearLayout reuse_ll_loading;
|
||||
// protected LinearLayout reuse_no_connection;
|
||||
// protected LinearLayout reuse_none_data;
|
||||
// protected TextView reuse_tv_none_data;
|
||||
// protected ImageView iv_share;
|
||||
//
|
||||
// protected GameEntity gameEntity;
|
||||
// protected DownloadEntity mDownloadEntity;
|
||||
//
|
||||
// protected String name;
|
||||
// protected String title;
|
||||
// protected String downloadAddWord;
|
||||
// protected String downloadOffText;
|
||||
//
|
||||
// private DataWatcher dataWatcher = new DataWatcher() {
|
||||
// @Override
|
||||
// public void onDataChanged(DownloadEntity downloadEntity) {
|
||||
// if (gameEntity != null && gameEntity.getApk().size() == 1) {
|
||||
// String url = gameEntity.getApk().get(0).getUrl();
|
||||
// if (url.equals(downloadEntity.getUrl())) {
|
||||
// if (!"pause".equals(DownloadManager.getInstance(BaseDetailActivity.this).
|
||||
// getStatus(downloadEntity.getUrl()))) {
|
||||
// mDownloadEntity = downloadEntity;
|
||||
// invalidate();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// @Override
|
||||
// protected int getLayoutId() {
|
||||
// return R.layout.activity_detail;
|
||||
// }
|
||||
//
|
||||
// //接收QQ或者QQ空间分享回调
|
||||
// @Override
|
||||
// protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
// super.onActivityResult(requestCode, resultCode, data);
|
||||
//
|
||||
// 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);
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// protected void onCreate(Bundle savedInstanceState) {
|
||||
// super.onCreate(savedInstanceState);
|
||||
//
|
||||
// // 添加分享图标
|
||||
// iv_share = new ImageView(this);
|
||||
// iv_share.setImageResource(R.drawable.ic_share);
|
||||
// iv_share.setOnClickListener(this);
|
||||
// iv_share.setVisibility(View.GONE);
|
||||
// iv_share.setPadding(DisplayUtils.dip2px(this, 13), DisplayUtils.dip2px(this, 11)
|
||||
// , DisplayUtils.dip2px(this, 11), DisplayUtils.dip2px(this, 13));
|
||||
// RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
|
||||
// DisplayUtils.dip2px(this, 48), DisplayUtils.dip2px(this, 48));
|
||||
// params.addRule(RelativeLayout.CENTER_VERTICAL);
|
||||
// params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
|
||||
// RelativeLayout reuse_actionbar = (RelativeLayout) mContentView.findViewById(
|
||||
// R.id.reuse_actionbar);
|
||||
// reuse_actionbar.addView(iv_share, params);
|
||||
//
|
||||
// actionbar_tv_title = (TextView) findViewById(R.id.actionbar_tv_title);
|
||||
// detail_rv_show = (RecyclerView) findViewById(R.id.detail_rv_show);
|
||||
// detail_ll_bottom = (LinearLayout) findViewById(R.id.detail_ll_bottom);
|
||||
// detail_tv_download = (TextView) findViewById(R.id.detail_tv_download);
|
||||
// detail_pb_progressbar = (ProgressBar) findViewById(R.id.detail_pb_progressbar);
|
||||
// detail_tv_per = (TextView) findViewById(R.id.detail_tv_per);
|
||||
// reuse_ll_loading = (LinearLayout) findViewById(R.id.reuse_ll_loading);
|
||||
// reuse_no_connection = (LinearLayout) findViewById(R.id.reuse_no_connection);
|
||||
// reuse_none_data = (LinearLayout) findViewById(R.id.reuse_none_data);
|
||||
// reuse_tv_none_data = (TextView) findViewById(R.id.reuse_tv_none_data);
|
||||
//
|
||||
// detail_ll_bottom.setOnClickListener(this);
|
||||
// detail_tv_download.setOnClickListener(this);
|
||||
// detail_pb_progressbar.setOnClickListener(this);
|
||||
// detail_tv_per.setOnClickListener(this);
|
||||
// reuse_no_connection.setOnClickListener(this);
|
||||
//
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// protected void onPause() {
|
||||
// super.onPause();
|
||||
// DownloadManager.getInstance(this).removeObserver(dataWatcher);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// protected void onResume() {
|
||||
// super.onResume();
|
||||
// if (gameEntity != null
|
||||
// && gameEntity.getApk() != null
|
||||
// && gameEntity.getApk().size() == 1) {
|
||||
// initDownload(true);
|
||||
// }
|
||||
// DownloadManager.getInstance(this).addObserver(dataWatcher);
|
||||
// }
|
||||
//
|
||||
// protected void initDownload(boolean isCheck) {
|
||||
// if (Config.isShow(this)) {
|
||||
// detail_ll_bottom.setVisibility(View.VISIBLE);
|
||||
// detail_rv_show.setPadding(0, 0, 0,
|
||||
// DisplayUtils.dip2px(getApplicationContext(), 60));
|
||||
// } else {
|
||||
// detail_ll_bottom.setVisibility(View.GONE);
|
||||
// detail_rv_show.setPadding(0, 0, 0, 0);
|
||||
// }
|
||||
// if (gameEntity != null && "光环助手".equals(gameEntity.getName())) {
|
||||
// detail_ll_bottom.setVisibility(View.GONE);
|
||||
// detail_rv_show.setPadding(0, 0, 0, 0);
|
||||
// } else if (gameEntity == null || gameEntity.getApk().isEmpty()) {
|
||||
// detail_tv_download.setVisibility(View.VISIBLE);
|
||||
// detail_pb_progressbar.setVisibility(View.GONE);
|
||||
// detail_tv_per.setVisibility(View.GONE);
|
||||
// if (TextUtils.isEmpty(downloadOffText)) {
|
||||
// detail_tv_download.setText("暂无下载");
|
||||
// } else {
|
||||
// detail_tv_download.setText(downloadOffText);
|
||||
// }
|
||||
// detail_tv_download.setBackgroundResource(R.drawable.game_item_btn_pause_style);
|
||||
// detail_tv_download.setTextColor(0xFF999999);
|
||||
// detail_tv_download.setClickable(false);
|
||||
// } else {
|
||||
// detail_tv_download.setVisibility(View.VISIBLE);
|
||||
// detail_pb_progressbar.setVisibility(View.GONE);
|
||||
// detail_tv_per.setVisibility(View.GONE);
|
||||
// boolean isInstalled = false;
|
||||
// if (gameEntity.getApk() != null && gameEntity.getApk().size() == 1
|
||||
// && PackageManager.isInstalled(gameEntity.getApk().get(0).getPackageName())) {
|
||||
// isInstalled = true;
|
||||
// }
|
||||
// if (isInstalled) {
|
||||
// if (PackageManager.isCanUpdate(gameEntity.getId(), gameEntity.getApk().get(0).getPackageName())) {
|
||||
// if (TextUtils.isEmpty(downloadAddWord)) {
|
||||
// detail_tv_download.setBackgroundResource(
|
||||
// R.drawable.game_item_btn_download_style);
|
||||
// detail_tv_download.setText(String.format("更新《%s》",
|
||||
// gameEntity.getName()));
|
||||
// } else {
|
||||
// detail_tv_download.setBackgroundResource(
|
||||
// R.drawable.game_item_btn_download_style);
|
||||
// detail_tv_download.setText(String.format("更新《%s》%s",
|
||||
// gameEntity.getName(), downloadAddWord));
|
||||
// }
|
||||
// } else {
|
||||
// if (gameEntity.getTag() != null && gameEntity.getTag().size() != 0
|
||||
// && !TextUtils.isEmpty(gameEntity.getApk().get(0).getGhVersion())
|
||||
// && !PackageUtils.isSignature(this, gameEntity.getApk().get(0).getPackageName())) {
|
||||
// if (TextUtils.isEmpty(downloadAddWord)) {
|
||||
// detail_tv_download.setBackgroundResource(
|
||||
// R.drawable.game_item_btn_plugin_style);
|
||||
// detail_tv_download.setText(String.format("插件化《%s》",
|
||||
// gameEntity.getName()));
|
||||
// } else {
|
||||
// detail_tv_download.setBackgroundResource(
|
||||
// R.drawable.game_item_btn_plugin_style);
|
||||
// detail_tv_download.setText(String.format("插件化《%s》%s",
|
||||
// gameEntity.getName(), downloadAddWord));
|
||||
// }
|
||||
// } else {
|
||||
// if (TextUtils.isEmpty(downloadAddWord)) {
|
||||
// detail_tv_download.setBackgroundResource(
|
||||
// R.drawable.game_item_btn_launch_style);
|
||||
// detail_tv_download.setText(String.format("启动《%s》",
|
||||
// gameEntity.getName()));
|
||||
// } else {
|
||||
// detail_tv_download.setBackgroundResource(
|
||||
// R.drawable.game_item_btn_launch_style);
|
||||
// detail_tv_download.setText(String.format("启动《%s》%s",
|
||||
// gameEntity.getName(), downloadAddWord));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// String status = GameUtils.getDownloadBtnText(this, gameEntity);
|
||||
//
|
||||
// switch (status) {
|
||||
// case "插件化":
|
||||
// detail_tv_download.setBackgroundResource(R.drawable.game_item_btn_plugin_style);
|
||||
// break;
|
||||
// case "打开":
|
||||
// detail_tv_download.setBackgroundResource(R.drawable.game_item_btn_launch_style);
|
||||
// break;
|
||||
// default:
|
||||
// detail_tv_download.setBackgroundResource(R.drawable.game_item_btn_download_style);
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// if (TextUtils.isEmpty(downloadAddWord)) {
|
||||
// detail_tv_download.setText(String.format(status + "《%s》",
|
||||
// gameEntity.getName()));
|
||||
// } else {
|
||||
// detail_tv_download.setText(String.format(status + "《%s》%s",
|
||||
// gameEntity.getName(), downloadAddWord));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (isCheck && gameEntity != null
|
||||
// && gameEntity.getApk() != null
|
||||
// && gameEntity.getApk().size() == 1) {
|
||||
// String url = gameEntity.getApk().get(0).getUrl();
|
||||
// DownloadEntity downloadEntity = DownloadManager.getInstance(getApplicationContext()).get(url);
|
||||
// if (downloadEntity != null) {
|
||||
// mDownloadEntity = downloadEntity;
|
||||
// detail_tv_download.setVisibility(View.GONE);
|
||||
// detail_pb_progressbar.setVisibility(View.VISIBLE);
|
||||
// detail_tv_per.setVisibility(View.VISIBLE);
|
||||
// invalidate();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void invalidate() {
|
||||
// detail_pb_progressbar.setProgress((int) (mDownloadEntity.getPercent() * 10));
|
||||
// detail_tv_per.setTextColor(0xFFFFFFFF);
|
||||
// switch (mDownloadEntity.getStatus()) {
|
||||
// case downloading:
|
||||
// case pause:
|
||||
// case timeout:
|
||||
// case neterror:
|
||||
// case waiting:
|
||||
// detail_tv_per.setText("下载中");
|
||||
// break;
|
||||
// case done:
|
||||
// detail_tv_per.setText("安装");
|
||||
// if (mDownloadEntity.isPluggable()
|
||||
// && PackageManager.isInstalled(mDownloadEntity.getPackageName())) {
|
||||
// detail_pb_progressbar.setProgressDrawable(ContextCompat.getDrawable(this, R.drawable.progressbar_plugin_radius_style));
|
||||
// } else {
|
||||
// detail_pb_progressbar.setProgressDrawable(ContextCompat.getDrawable(this, R.drawable.progressbar_normal_radius_style));
|
||||
// }
|
||||
// break;
|
||||
// case cancel:
|
||||
// case hijack:
|
||||
// case notfound:
|
||||
// initDownload(false);
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 接收下载被删除消息
|
||||
// @Subscribe(threadMode = ThreadMode.MAIN)
|
||||
// public void onEvent(EBDownloadStatus status) {
|
||||
// if ("delete".equals(status.getStatus())
|
||||
// && gameEntity != null
|
||||
// && gameEntity.getApk() != null
|
||||
// && gameEntity.getApk().size() == 1) {
|
||||
// String url = gameEntity.getApk().get(0).getUrl();
|
||||
// if (url.equals(status.getUrl())) {
|
||||
// initDownload(false);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 接受安装、卸载消息
|
||||
// @Subscribe(threadMode = ThreadMode.MAIN)
|
||||
// public void onEventMainThread(EBPackage busFour) {
|
||||
// if (gameEntity != null
|
||||
// && gameEntity.getApk() != null
|
||||
// && gameEntity.getApk().size() > 0) {
|
||||
// for (ApkEntity apkEntity : gameEntity.getApk()) {
|
||||
// String packageName = apkEntity.getPackageName();
|
||||
// if (packageName.equals(busFour.getPackageName())) {
|
||||
// ApkActiveUtils.filterHideApk(gameEntity);
|
||||
// initDownload(false);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onClick(View v) {
|
||||
// if (v == detail_tv_download) {
|
||||
// if (gameEntity != null && !gameEntity.getApk().isEmpty()) {
|
||||
// if (gameEntity.getApk().size() == 1) {
|
||||
// if (NetworkUtils.isWifiConnected(this)) {
|
||||
// download();
|
||||
// } else {
|
||||
// DialogUtils.showDownloadDialog(this, new DialogUtils.ConfirmListener() {
|
||||
// @Override
|
||||
// public void onConfirm() {
|
||||
// download();
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// } else {
|
||||
// DownloadDialog.getInstance(this).showPopupWindow(v, gameEntity, mEntrance, name + ":" + title);
|
||||
// }
|
||||
// } else {
|
||||
// toast("稍等片刻~!游戏正在上传中...");
|
||||
// }
|
||||
// } else if (v == detail_pb_progressbar || v == detail_tv_per) {
|
||||
// String str = detail_tv_per.getText().toString();
|
||||
// if ("下载中".equals(str)) {
|
||||
// DownloadManagerActivity.startDownloadManagerActivity(this, gameEntity.getApk().get(0).getUrl()
|
||||
// , mEntrance + "+(" + name + "[" + title + "])");
|
||||
// } else if ("安装".equals(str)) {
|
||||
// PackageUtils.launchSetup(this, mDownloadEntity.getPath());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void download() {
|
||||
// String str = detail_tv_download.getText().toString();
|
||||
// if (str.contains("启动")) {
|
||||
// DataUtils.onGameLaunchEvent(this, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), name);
|
||||
//
|
||||
// PackageUtils.launchApplicationByPackageName(this, gameEntity.getApk().get(0).getPackageName());
|
||||
// } else {
|
||||
// String method;
|
||||
// if (str.contains("更新")) {
|
||||
// method = "更新";
|
||||
// } else if (str.contains("插件化")) {
|
||||
// method = "插件化";
|
||||
// } else {
|
||||
// method = "下载";
|
||||
// }
|
||||
// ApkEntity apkEntity = gameEntity.getApk().get(0);
|
||||
// String msg = FileUtils.isCanDownload(this, apkEntity.getSize());
|
||||
// if (TextUtils.isEmpty(msg)) {
|
||||
// DataUtils.onGameDownloadEvent(this, gameEntity.getName(), apkEntity.getPlatform(), mEntrance, "下载开始");
|
||||
//
|
||||
// DownloadManager.createDownload(this, apkEntity, gameEntity, method, mEntrance, name + ":" + title);
|
||||
//
|
||||
// detail_tv_download.setVisibility(View.GONE);
|
||||
// detail_pb_progressbar.setVisibility(View.VISIBLE);
|
||||
// detail_tv_per.setVisibility(View.VISIBLE);
|
||||
// detail_pb_progressbar.setProgress(0);
|
||||
// detail_tv_per.setText("0.0%");
|
||||
//
|
||||
//// DownloadManager.getInstance(BaseDetailActivity.this).putStatus(apkEntity.getUrl(), "downloading");
|
||||
// } else {
|
||||
// toast(msg);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//}
|
||||
//>>>>>>> b239407c25cb85374c0f50c257411b4b98e10e77
|
||||
@ -1,6 +1,6 @@
|
||||
package com.gh.base;
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
|
||||
import butterknife.ButterKnife;
|
||||
@ -13,11 +13,45 @@ import butterknife.ButterKnife;
|
||||
* @Time 9:55 AM
|
||||
*/
|
||||
|
||||
public abstract class BaseRecyclerViewHolder extends RecyclerView.ViewHolder {
|
||||
public abstract class BaseRecyclerViewHolder<T> extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||
|
||||
private T mData;
|
||||
private OnListClickListener mListClickListener;
|
||||
|
||||
public BaseRecyclerViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
ButterKnife.bind(this, itemView);
|
||||
}
|
||||
|
||||
/**
|
||||
* 具体的设置监听在childViewHolder 设置
|
||||
*
|
||||
* @param itemView
|
||||
* @param data 一般情况下只传列表数据
|
||||
* @param listClickListener 列表事件接口
|
||||
*/
|
||||
public BaseRecyclerViewHolder(View itemView, T data, OnListClickListener listClickListener) {
|
||||
this(itemView);
|
||||
this.mData = data;
|
||||
this.mListClickListener = listClickListener;
|
||||
}
|
||||
|
||||
public BaseRecyclerViewHolder(View itemView, OnListClickListener listClickListener) {
|
||||
this(itemView);
|
||||
this.mListClickListener = listClickListener;
|
||||
}
|
||||
|
||||
public void setClickData(T clickData) {
|
||||
this.mData = clickData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
try {
|
||||
mListClickListener.onListClick(view, getAdapterPosition(), mData);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
270
app/src/main/java/com/gh/base/BaseRichEditorActivity.kt
Normal file
270
app/src/main/java/com/gh/base/BaseRichEditorActivity.kt
Normal file
@ -0,0 +1,270 @@
|
||||
package com.gh.base
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import android.webkit.JavascriptInterface
|
||||
import butterknife.OnClick
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.common.util.MtaHelper
|
||||
import com.gh.common.view.RichEditor
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.entity.MyVideoEntity
|
||||
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.qa.entity.AnswerEntity
|
||||
import com.gh.gamecenter.qa.entity.ArticleEntity
|
||||
import com.gh.gamecenter.qa.entity.EditorInsertEntity
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import com.lightgame.view.CheckableImageView
|
||||
import kotterknife.bindView
|
||||
|
||||
abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
|
||||
val mRichEditor by bindView<RichEditor>(R.id.rich_editor)
|
||||
|
||||
private val mEditorFont by bindView<CheckableImageView>(R.id.editor_font)
|
||||
private val mEditorLink by bindView<CheckableImageView>(R.id.editor_link)
|
||||
private val mEditorParagraph by bindView<CheckableImageView>(R.id.editor_paragraph)
|
||||
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 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 mEditorInsertDetail by bindView<View>(R.id.editor_insert_detail)
|
||||
|
||||
private var mCurrentParagraphStyle = ""
|
||||
|
||||
|
||||
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
|
||||
when (requestCode) {
|
||||
INSERT_ANSWER_CODE -> {
|
||||
val answer = data?.getParcelableExtra<AnswerEntity>(AnswerEntity::class.java.simpleName)
|
||||
if (answer != null) insertData = EditorInsertEntity.transform(answer)
|
||||
}
|
||||
INSERT_ARTICLE_CODE -> {
|
||||
val article = data?.getParcelableExtra<ArticleEntity>(ArticleEntity::class.java.simpleName)
|
||||
if (article != null) insertData = EditorInsertEntity.transform(article)
|
||||
}
|
||||
INSERT_GAME_CODE -> {
|
||||
val game = data?.getParcelableExtra<GameEntity>(GameEntity::class.java.simpleName)
|
||||
if (game != null) insertData = EditorInsertEntity.transform(game)
|
||||
}
|
||||
VideoActivity.INSERT_VIDEO_CODE -> {
|
||||
val video = data?.getParcelableExtra<MyVideoEntity>(MyVideoEntity::class.java.simpleName)
|
||||
if (video != null) mRichEditor.insertCustomVideo(video)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
mRichEditor.insertCustomStyleLink(insertData)
|
||||
}
|
||||
|
||||
@SuppressLint("AddJavascriptInterface")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
mRichEditor.setPadding(20, 15, 20, 15)
|
||||
// 防止个别手机在Js里无法获取粘贴内容
|
||||
mRichEditor.addJavascriptInterface(OnPasteListener(), "onPasteListener")
|
||||
mRichEditor.addJavascriptInterface(OnCursorChangeListener(), "OnCursorChangeListener")
|
||||
mRichEditor.setInputEnabled(true)
|
||||
}
|
||||
|
||||
@OnClick(R.id.editor_image, R.id.editor_font, R.id.editor_link, R.id.editor_paragraph,
|
||||
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 -> {
|
||||
mEditorFont.isChecked = !mEditorFont.isChecked
|
||||
mEditorParagraph.isChecked = false
|
||||
mEditorLink.isChecked = false
|
||||
mEditorFontContainer.visibility = if (mEditorFont.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorParagraphContainer.visibility = if (!mEditorFont.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorLinkContainer.visibility = if (!mEditorFont.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorInsertDetail.visibility = mEditorFontContainer.visibility
|
||||
}
|
||||
R.id.editor_paragraph -> {
|
||||
mEditorParagraph.isChecked = !mEditorParagraph.isChecked
|
||||
mEditorFont.isChecked = false
|
||||
mEditorLink.isChecked = false
|
||||
mEditorParagraphContainer.visibility = if (mEditorParagraph.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorFontContainer.visibility = if (!mEditorParagraph.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorLinkContainer.visibility = if (!mEditorParagraph.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorInsertDetail.visibility = mEditorParagraphContainer.visibility
|
||||
}
|
||||
R.id.editor_link -> {
|
||||
mEditorLink.isChecked = !mEditorLink.isChecked
|
||||
mEditorFont.isChecked = false
|
||||
mEditorParagraph.isChecked = false
|
||||
mEditorLinkContainer.visibility = if (mEditorLink.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorParagraphContainer.visibility = if (!mEditorLink.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorFontContainer.visibility = if (!mEditorLink.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorInsertDetail.visibility = mEditorLinkContainer.visibility
|
||||
}
|
||||
R.id.editor_font_bold -> {
|
||||
mEditorFontBold.isChecked = !mEditorFontBold.isChecked
|
||||
mRichEditor.setBold()
|
||||
if (mEditorFontBold.isChecked) {
|
||||
MtaHelper.onEvent(mtaEventName(), "文字样式", "文字样式-加粗")
|
||||
}
|
||||
}
|
||||
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_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, "插入游戏"), INSERT_GAME_CODE)
|
||||
}
|
||||
R.id.editor_link_video -> {
|
||||
MtaHelper.onEvent(mtaEventName(), "插入链接", "插入链接-视频")
|
||||
startActivityForResult(VideoActivity.getIntent(this), VideoActivity.INSERT_VIDEO_CODE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inner class OnCursorChangeListener {
|
||||
@JavascriptInterface
|
||||
fun onElements(elements: String) {
|
||||
Utils.log("-----------------------")
|
||||
Utils.log(elements)
|
||||
Utils.log(mRichEditor.html)
|
||||
Utils.log("-----------------------")
|
||||
|
||||
mCurrentParagraphStyle = when {
|
||||
elements.contains(ELEMENT_PARAGRAPH_QUOTE) -> ELEMENT_PARAGRAPH_QUOTE
|
||||
elements.contains(ELEMENT_PARAGRAPH_P) -> ELEMENT_PARAGRAPH_P
|
||||
else -> ""
|
||||
}
|
||||
|
||||
mBaseHandler.post {
|
||||
mEditorFontBold.isChecked = elements.contains(ELEMENT_NAME_BOLD)
|
||||
mEditorFontItalic.isChecked = elements.contains(ELEMENT_NAME_ITALIC)
|
||||
mEditorFontStrikeThrough.isChecked = elements.contains(ELEMENT_NAME_STRIKE)
|
||||
mEditorParagraphH1.isChecked = elements.contains(ELEMENT_PARAGRAPH_H1)
|
||||
mEditorParagraphH2.isChecked = elements.contains(ELEMENT_PARAGRAPH_H2)
|
||||
mEditorParagraphH3.isChecked = elements.contains(ELEMENT_PARAGRAPH_H3)
|
||||
mEditorParagraphH4.isChecked = elements.contains(ELEMENT_PARAGRAPH_H4)
|
||||
mEditorParagraphQuote.isChecked = elements.contains(ELEMENT_PARAGRAPH_QUOTE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inner class OnPasteListener {
|
||||
@JavascriptInterface
|
||||
fun onPaste() {
|
||||
val clipboard =
|
||||
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/>")
|
||||
mBaseHandler.post { mRichEditor.insertHtml(text) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun mtaEventName(): String
|
||||
|
||||
companion object {
|
||||
const val ELEMENT_NAME_BOLD = " b "
|
||||
const val ELEMENT_NAME_ITALIC = " i "
|
||||
const val ELEMENT_NAME_STRIKE = " strike "
|
||||
const val ELEMENT_PARAGRAPH_H1 = " h1 "
|
||||
const val ELEMENT_PARAGRAPH_H2 = " h2 "
|
||||
const val ELEMENT_PARAGRAPH_H3 = " h3 "
|
||||
const val ELEMENT_PARAGRAPH_H4 = " h4 "
|
||||
const val ELEMENT_PARAGRAPH_P = " p "
|
||||
const val ELEMENT_PARAGRAPH_QUOTE = " blockquote "
|
||||
const val INSERT_ANSWER_CODE = 411
|
||||
const val INSERT_ARTICLE_CODE = 412
|
||||
const val INSERT_GAME_CODE = 413
|
||||
}
|
||||
}
|
||||
19
app/src/main/java/com/gh/base/CurrentActivityHolder.kt
Normal file
19
app/src/main/java/com/gh/base/CurrentActivityHolder.kt
Normal file
@ -0,0 +1,19 @@
|
||||
package com.gh.base
|
||||
|
||||
import android.app.Activity
|
||||
|
||||
object CurrentActivityHolder {
|
||||
|
||||
@JvmStatic
|
||||
val activitySet = HashSet<Activity>()
|
||||
|
||||
@JvmStatic
|
||||
fun getCurrentActivity(): Activity? {
|
||||
return if (activitySet.isEmpty()) {
|
||||
null
|
||||
} else {
|
||||
activitySet.iterator().next()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -4,6 +4,12 @@ import android.app.Activity;
|
||||
import android.app.Application.ActivityLifecycleCallbacks;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.gh.common.im.ImManager;
|
||||
import com.gh.common.notifier.Notifier;
|
||||
import com.gh.common.util.DataUtils;
|
||||
import com.gh.download.DownloadManager;
|
||||
import com.lightgame.utils.AppManager;
|
||||
|
||||
/**
|
||||
* 1、写点针对生命周期的统计代码
|
||||
* 2、写点通用的逻辑
|
||||
@ -15,10 +21,10 @@ import android.os.Bundle;
|
||||
*/
|
||||
public class GHActivityLifecycleCallbacksImpl implements ActivityLifecycleCallbacks {
|
||||
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
|
||||
|
||||
AppManager.getInstance().addActivity(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -29,16 +35,27 @@ public class GHActivityLifecycleCallbacksImpl implements ActivityLifecycleCallba
|
||||
@Override
|
||||
public void onActivityResumed(Activity activity) {
|
||||
|
||||
DataUtils.onResume(activity);
|
||||
CurrentActivityHolder.getActivitySet().add(activity);
|
||||
ImManager.updateFloatingWindow();
|
||||
//FIXME 这里应该只是部分Activity需要
|
||||
try {
|
||||
// 初始化gameMap
|
||||
DownloadManager.getInstance(activity).initGameMap();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityPaused(Activity activity) {
|
||||
|
||||
DataUtils.onPause(activity);
|
||||
CurrentActivityHolder.getActivitySet().remove(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityStopped(Activity activity) {
|
||||
|
||||
Notifier.hide();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -48,7 +65,7 @@ public class GHActivityLifecycleCallbacksImpl implements ActivityLifecycleCallba
|
||||
|
||||
@Override
|
||||
public void onActivityDestroyed(Activity activity) {
|
||||
|
||||
AppManager.getInstance().finishActivity(activity);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,323 +0,0 @@
|
||||
package com.gh.base;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.support.v4.util.ArrayMap;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import com.gh.common.util.AppDebugConfig;
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.lightgame.download.FileUtils;
|
||||
import com.gh.common.util.PackageUtils;
|
||||
import com.gh.common.util.TokenUtils;
|
||||
import com.lightgame.utils.Utils;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.xiaomi.mipush.sdk.ErrorCode;
|
||||
import com.xiaomi.mipush.sdk.MiPushClient;
|
||||
import com.xiaomi.mipush.sdk.MiPushCommandMessage;
|
||||
import com.xiaomi.mipush.sdk.MiPushMessage;
|
||||
import com.xiaomi.mipush.sdk.PushMessageReceiver;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import static com.gh.common.util.EntranceUtils.ENTRANCE_MIPUSH;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_ARTICLE;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_GAME;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_WEB;
|
||||
import static com.gh.common.util.EntranceUtils.HOSt_COLUMN;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_ENTRANCE;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_GAMEID;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_ID;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_NEWSID;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_TARGET;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_TO;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_TYPE;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_URL;
|
||||
|
||||
/**
|
||||
* 1、PushMessageReceiver是个抽象类,该类继承了BroadcastReceiver。
|
||||
* 2、需要将自定义的DemoMessageReceiver注册在AndroidManifest.xml文件中 <receiver
|
||||
* android:exported="true"
|
||||
* android:name="com.xiaomi.mipushdemo.DemoMessageReceiver"> <intent-filter>
|
||||
* <action android:name="com.xiaomi.mipush.RECEIVE_MESSAGE" /> </intent-filter>
|
||||
* <intent-filter> <action android:name="com.xiaomi.mipush.ERROR" />
|
||||
* </intent-filter> <intent-filter> <action
|
||||
* android:name="com.xiaomi.mipush.MESSAGE_ARRIVED" /></intent-filter>
|
||||
* </receiver>
|
||||
* 3、DemoMessageReceiver的onReceivePassThroughMessage方法用来接收服务器向客户端发送的透传消息
|
||||
* 4、DemoMessageReceiver的onNotificationMessageClicked方法用来接收服务器向客户端发送的通知消息,
|
||||
* 这个回调方法会在用户手动点击通知后触发
|
||||
* 5、DemoMessageReceiver的onNotificationMessageArrived方法用来接收服务器向客户端发送的通知消息,
|
||||
* 这个回调方法是在通知消息到达客户端时触发。另外应用在前台时不弹出通知的通知消息到达客户端也会触发这个回调函数
|
||||
* 6、DemoMessageReceiver的onCommandResult方法用来接收客户端向服务器发送命令后的响应结果
|
||||
* 7、DemoMessageReceiver的onReceiveRegisterResult方法用来接收客户端向服务器发送注册命令后的响应结果
|
||||
* 8、以上这些方法运行在非UI线程中
|
||||
*
|
||||
* @author mayixiang
|
||||
* //TODO 请勿更改此类路径,若需更改时请注意更改./libraries/MiPush/proguard-library.txt混淆对应配置
|
||||
*/
|
||||
public class GHPushMessageReceiver extends PushMessageReceiver {
|
||||
|
||||
private String mAlias;
|
||||
|
||||
@Override
|
||||
public void onReceivePassThroughMessage(Context context, MiPushMessage message) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
AppDebugConfig.logMethodWithParams(this, message);
|
||||
}
|
||||
// 1判断notifyid是否为4
|
||||
try {
|
||||
//TODO what is magic number 4?
|
||||
if (message.getNotifyId() == 4) {
|
||||
JSONObject jsonObject = new JSONObject(message.getContent());
|
||||
Utils.log(jsonObject.toString());
|
||||
String channel = jsonObject.getString("channel");
|
||||
Utils.log("channel = " + channel);
|
||||
|
||||
// 1判断渠道号是否一致或是否为ALL
|
||||
String packageChannel = AppController.getInstance().getChannel();
|
||||
if ("ALL".equals(channel) || channel.equalsIgnoreCase(packageChannel)) {
|
||||
String type = jsonObject.getString(KEY_TYPE);
|
||||
Utils.log("type = " + type);
|
||||
JSONArray jsonArray;
|
||||
ArrayMap<String, Boolean> map;
|
||||
switch (type) {
|
||||
case "NEWS":
|
||||
// 新闻推送
|
||||
jsonArray = jsonObject.getJSONArray("package");
|
||||
map = getInstalledMapFromLocal(context);
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
Boolean b = map.get(jsonArray.getString(i));
|
||||
if (b != null) {
|
||||
// 显示推送的消息
|
||||
showNotification(context, jsonObject, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "PLUGIN_UPDATE":
|
||||
// 插件更新推送
|
||||
jsonArray = jsonObject.getJSONArray("apk");
|
||||
map = getInstalledMapFromLocal(context);
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
JSONObject apk = jsonArray.getJSONObject(i);
|
||||
String packageName = apk.getString("package");
|
||||
Boolean b = map.get(packageName);
|
||||
if (b != null) {
|
||||
// 判断是否gh_version是否相同
|
||||
String gh_version = (String) PackageUtils
|
||||
.getMetaData(context, packageName, "gh_version");
|
||||
if (gh_version != null) {
|
||||
gh_version = gh_version.substring(2);
|
||||
// 判断gh_version是否相同
|
||||
if (gh_version.equals(apk.getString("gh_version"))) {
|
||||
// 判断version是否相同
|
||||
String version = PackageUtils.getVersionByPackage(context, packageName);
|
||||
if (apk.getString("version").equals(version)) {
|
||||
// 版本相同,无需显示插件更新,继续查看是否有可更新的游戏包
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 显示推送的消息
|
||||
showNotification(context, jsonObject, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "NEW_GAME":
|
||||
// 新游推送
|
||||
showNotification(context, jsonObject, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private ArrayMap<String, Boolean> getInstalledMapFromLocal(Context context) {
|
||||
ArrayMap<String, Boolean> map = new ArrayMap<>();
|
||||
ArrayList<String> list = getAllPackageName(context);
|
||||
for (String str : list) {
|
||||
map.put(str, true);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private void showNotification(Context context, JSONObject jsonObject, int id) throws JSONException {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction("com.gh.gamecenter.NOTIFICATION");
|
||||
intent.putExtra("notifyId", id);
|
||||
intent.putExtra("notifyData", jsonObject.toString());
|
||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, id, intent, PendingIntent.FLAG_ONE_SHOT);
|
||||
|
||||
NotificationManager nManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
Notification notification = new NotificationCompat.Builder(context)
|
||||
.setSmallIcon(R.drawable.logo)
|
||||
.setTicker(jsonObject.getString("pushTitle"))
|
||||
.setContentTitle(jsonObject.getString("pushTitle"))
|
||||
.setContentText(jsonObject.getString("pushDesc"))
|
||||
.setContentIntent(pendingIntent).build();
|
||||
|
||||
RemoteViews remoteViews = null;
|
||||
|
||||
if (Build.MANUFACTURER.equals("Meizu") &&
|
||||
(Build.MODEL.startsWith("m") || Build.MODEL.startsWith("MX"))) {
|
||||
remoteViews = new RemoteViews(context.getPackageName(), R.layout.notification_meizu);
|
||||
SimpleDateFormat format = new SimpleDateFormat("HH:mm", Locale.getDefault());
|
||||
remoteViews.setTextViewText(R.id.time, format.format(new Date()));
|
||||
} else if (Build.MANUFACTURER.equals("Xiaomi") &&
|
||||
(Build.MODEL.startsWith("MI") || Build.MODEL.startsWith("HM") || Build.MODEL.startsWith("Redmi"))) {
|
||||
// 小米系统
|
||||
remoteViews = new RemoteViews(context.getPackageName(), R.layout.notification_xiaomi);
|
||||
SimpleDateFormat format = new SimpleDateFormat("ah:mm", Locale.getDefault());
|
||||
remoteViews.setTextViewText(R.id.time, format.format(new Date()));
|
||||
} else if (Build.MANUFACTURER.equals("HUAWEI")) {
|
||||
// 华为系统
|
||||
remoteViews = new RemoteViews(context.getPackageName(), R.layout.notification_huawei);
|
||||
}
|
||||
|
||||
String url = jsonObject.getString("icon");
|
||||
String path = context.getCacheDir() + File.separator + url.substring(url.lastIndexOf("/") + 1);
|
||||
int result = FileUtils.downloadFile(url, path);
|
||||
if (result != 200) {
|
||||
// 下载出错,使用光环logo
|
||||
path = null;
|
||||
}
|
||||
|
||||
if (remoteViews != null) {
|
||||
if (path == null) {
|
||||
remoteViews.setImageViewBitmap(R.id.icon, BitmapFactory.decodeResource(context.getResources(), R.drawable.logo));
|
||||
} else {
|
||||
remoteViews.setImageViewBitmap(R.id.icon, BitmapFactory.decodeFile(path));
|
||||
}
|
||||
remoteViews.setTextViewText(R.id.title, jsonObject.getString("pushTitle"));
|
||||
remoteViews.setTextViewText(R.id.intro, jsonObject.getString("pushDesc"));
|
||||
notification.contentView = remoteViews;
|
||||
} else {
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
|
||||
.setSmallIcon(R.drawable.logo_black)
|
||||
.setTicker(jsonObject.getString("pushTitle"))
|
||||
.setContentTitle(jsonObject.getString("pushTitle"))
|
||||
.setContentText(jsonObject.getString("pushDesc"))
|
||||
.setContentIntent(pendingIntent);
|
||||
if (path == null) {
|
||||
builder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.logo));
|
||||
} else {
|
||||
builder.setLargeIcon(BitmapFactory.decodeFile(path));
|
||||
}
|
||||
notification = builder.build();
|
||||
}
|
||||
|
||||
notification.defaults = Notification.DEFAULT_SOUND;// 添加系统默认声音
|
||||
notification.flags |= Notification.FLAG_AUTO_CANCEL; // FLAG_AUTO_CANCEL表明当通知被用户点击时,通知将被清除。
|
||||
nManager.notify(((int) System.currentTimeMillis() / 1000), notification);// 通过通知管理器来发起通知。如果id不同,则每click,在status哪里增加一个提示
|
||||
}
|
||||
|
||||
private ArrayList<String> getAllPackageName(Context context) {
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
List<PackageInfo> packageInfos = context.getPackageManager().getInstalledPackages(0);
|
||||
for (PackageInfo packageInfo : packageInfos) {
|
||||
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
|
||||
list.add(packageInfo.packageName);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotificationMessageClicked(Context context, MiPushMessage message) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
AppDebugConfig.logMethodWithParams(this, message);
|
||||
}
|
||||
try {
|
||||
String content = message.getContent();
|
||||
JSONObject response = new JSONObject(content);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(KEY_ENTRANCE, ENTRANCE_MIPUSH);
|
||||
String type = response.getString(KEY_TYPE);
|
||||
String target = response.getString(KEY_TARGET);
|
||||
|
||||
switch (type) {
|
||||
case HOST_ARTICLE:
|
||||
bundle.putString(KEY_TO, "NewsDetailActivity");
|
||||
bundle.putString(KEY_NEWSID, target);
|
||||
break;
|
||||
case HOST_GAME:
|
||||
bundle.putString(KEY_TO, "GameDetailActivity");
|
||||
bundle.putString(KEY_GAMEID, target);
|
||||
break;
|
||||
case HOSt_COLUMN:
|
||||
bundle.putString(KEY_TO, "SubjectActivity");
|
||||
bundle.putString(KEY_ID, target);
|
||||
break;
|
||||
case HOST_WEB:
|
||||
bundle.putString(KEY_TO, "WebActivity");
|
||||
bundle.putString(KEY_URL, target);
|
||||
break;
|
||||
}
|
||||
EntranceUtils.jumpActivity(context, bundle);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotificationMessageArrived(Context context,
|
||||
MiPushMessage message) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
AppDebugConfig.logMethodWithParams(this, message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceiveRegisterResult(Context context, MiPushCommandMessage message) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
AppDebugConfig.logMethodWithParams(this, message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCommandResult(Context context, MiPushCommandMessage message) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
AppDebugConfig.logMethodWithParams(this, message);
|
||||
}
|
||||
|
||||
String command = message.getCommand();
|
||||
List<String> arguments = message.getCommandArguments();
|
||||
|
||||
if (MiPushClient.COMMAND_SET_ALIAS.equals(command)) {
|
||||
if (message.getResultCode() == ErrorCode.SUCCESS) {
|
||||
mAlias = arguments.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(mAlias)) {
|
||||
//添加别名
|
||||
MiPushClient.setAlias(context, TokenUtils.getDeviceId(context), null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,51 +0,0 @@
|
||||
package com.gh.base;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.umeng.message.UmengNotificationClickHandler;
|
||||
import com.umeng.message.entity.UMessage;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
||||
public class GHUmengNotificationClickHandler extends UmengNotificationClickHandler {
|
||||
|
||||
@Override
|
||||
public void launchApp(Context context, UMessage uMessage) {
|
||||
// super.launchApp(context, uMessage);
|
||||
|
||||
try {
|
||||
String content = uMessage.extra.get(EntranceUtils.KEY_DATA);
|
||||
JSONObject response = new JSONObject(content);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(EntranceUtils.KEY_ENTRANCE, EntranceUtils.ENTRANCE_UMENG);
|
||||
String type = response.getString(EntranceUtils.KEY_TYPE);
|
||||
String target = response.getString(EntranceUtils.KEY_TARGET);
|
||||
switch (type) {
|
||||
case EntranceUtils.HOST_ARTICLE:
|
||||
bundle.putString(EntranceUtils.KEY_TO, "NewsDetailActivity");
|
||||
bundle.putString(EntranceUtils.KEY_NEWSID, target);
|
||||
break;
|
||||
case EntranceUtils.HOST_GAME:
|
||||
bundle.putString(EntranceUtils.KEY_TO, "GameDetailActivity");
|
||||
bundle.putString(EntranceUtils.KEY_GAMEID, target);
|
||||
break;
|
||||
case EntranceUtils.HOSt_COLUMN:
|
||||
bundle.putString(EntranceUtils.KEY_TO, "SubjectActivity");
|
||||
bundle.putString(EntranceUtils.KEY_ID, target);
|
||||
break;
|
||||
case EntranceUtils.HOST_WEB:
|
||||
bundle.putString(EntranceUtils.KEY_TO, "WebActivity");
|
||||
bundle.putString(EntranceUtils.KEY_URL, target);
|
||||
break;
|
||||
}
|
||||
EntranceUtils.jumpActivity(context, bundle);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
231
app/src/main/java/com/gh/base/GHUmengNotificationService.kt
Normal file
231
app/src/main/java/com/gh/base/GHUmengNotificationService.kt
Normal file
@ -0,0 +1,231 @@
|
||||
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 com.gh.common.notifier.Notifier
|
||||
import com.gh.common.util.EntranceUtils
|
||||
import com.gh.common.util.MtaHelper
|
||||
import com.gh.common.util.StringUtils
|
||||
import com.gh.common.util.toObject
|
||||
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?.target == "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)
|
||||
.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!!
|
||||
}
|
||||
}
|
||||
32
app/src/main/java/com/gh/base/OnDoubleTapListener.java
Normal file
32
app/src/main/java/com/gh/base/OnDoubleTapListener.java
Normal file
@ -0,0 +1,32 @@
|
||||
package com.gh.base;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Created by khy on 25/04/18.
|
||||
*/
|
||||
|
||||
public abstract class OnDoubleTapListener implements View.OnTouchListener {
|
||||
private GestureDetector mGestureDetector;
|
||||
|
||||
protected OnDoubleTapListener(Context context) {
|
||||
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
|
||||
@Override
|
||||
public boolean onDoubleTap(MotionEvent e) {
|
||||
OnDoubleTapListener.this.onDoubleTap();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
mGestureDetector.onTouchEvent(event);
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract void onDoubleTap();
|
||||
}
|
||||
19
app/src/main/java/com/gh/base/OnListClickListener.java
Normal file
19
app/src/main/java/com/gh/base/OnListClickListener.java
Normal file
@ -0,0 +1,19 @@
|
||||
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);
|
||||
}
|
||||
@ -2,7 +2,11 @@ package com.gh.base;
|
||||
|
||||
/**
|
||||
* Created by Administrator on 2016/9/8.
|
||||
*
|
||||
* 逐步移除
|
||||
*/
|
||||
|
||||
@Deprecated
|
||||
public interface OnRequestCallBackListener<T> {
|
||||
|
||||
void loadDone();
|
||||
|
||||
7
app/src/main/java/com/gh/base/OnViewClickListener.java
Normal file
7
app/src/main/java/com/gh/base/OnViewClickListener.java
Normal file
@ -0,0 +1,7 @@
|
||||
package com.gh.base;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
public interface OnViewClickListener<T> {
|
||||
void onClick(View v, T data);
|
||||
}
|
||||
@ -1,48 +0,0 @@
|
||||
//package com.gh.base;
|
||||
//
|
||||
//import java.io.Serializable;
|
||||
//
|
||||
//public enum SuggestionType implements Serializable {
|
||||
//
|
||||
// FEEDBACK("普通反馈", 1),
|
||||
// SUGGESTION("功能建议", 2),
|
||||
// CRASH("发生闪退", 3),
|
||||
// GAME("游戏问题", 4),
|
||||
// COLLECT("游戏收录", 5),
|
||||
// POST("文章投稿", 6);
|
||||
//
|
||||
// private String mName;
|
||||
// private int mIndex;
|
||||
//
|
||||
// private SuggestionType(String name, int index) {
|
||||
// mName = name;
|
||||
// mIndex = index;
|
||||
// }
|
||||
//
|
||||
// public static String getName(int index) {
|
||||
// for (SuggestionType c : SuggestionType.values()) {
|
||||
// if (c.mIndex == index) {
|
||||
// return c.mName;
|
||||
// }
|
||||
// }
|
||||
// return "";
|
||||
// }
|
||||
//
|
||||
// public static int getIndex(String name) {
|
||||
// for (SuggestionType c : SuggestionType.values()) {
|
||||
// if (c.mName == name) {
|
||||
// return c.mIndex;
|
||||
// }
|
||||
// }
|
||||
// return -1;
|
||||
// }
|
||||
//
|
||||
// public int getIndex() {
|
||||
// return mIndex;
|
||||
// }
|
||||
//
|
||||
// public String getName() {
|
||||
// return mName;
|
||||
// }
|
||||
//
|
||||
//}
|
||||
256
app/src/main/java/com/gh/base/ToolBarActivity.java
Normal file
256
app/src/main/java/com/gh/base/ToolBarActivity.java
Normal file
@ -0,0 +1,256 @@
|
||||
package com.gh.base;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
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.view.WindowManager;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.common.util.MtaHelper;
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* 需要用到工具栏的页面使用
|
||||
* <p>
|
||||
* 特殊页面请参考{@link BaseActivity}
|
||||
*/
|
||||
|
||||
public abstract class ToolBarActivity extends BaseActivity implements ToolbarController, Toolbar.OnMenuItemClickListener {
|
||||
|
||||
@Nullable
|
||||
private PackageViewModel mPackageViewModel;
|
||||
|
||||
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() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,9 @@
|
||||
package com.gh.base.adapter;
|
||||
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentPagerAdapter;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentPagerAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -14,11 +15,19 @@ public class FragmentAdapter extends FragmentPagerAdapter {
|
||||
|
||||
private List<Fragment> mFragmentList;
|
||||
|
||||
private List<String> mTitleList;
|
||||
|
||||
public FragmentAdapter(FragmentManager fm, List<Fragment> fragmentList) {
|
||||
super(fm);
|
||||
this.mFragmentList = fragmentList;
|
||||
}
|
||||
|
||||
public FragmentAdapter(FragmentManager fm, List<Fragment> fragmentList, List<String> titleList) {
|
||||
super(fm);
|
||||
this.mFragmentList = fragmentList;
|
||||
this.mTitleList = titleList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
return mFragmentList.get(position);
|
||||
@ -29,4 +38,12 @@ public class FragmentAdapter extends FragmentPagerAdapter {
|
||||
return mFragmentList.size();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
if (mTitleList != null && mTitleList.size() > position) {
|
||||
return mTitleList.get(position);
|
||||
}
|
||||
return super.getPageTitle(position);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
package com.gh.base.adapter;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentStatePagerAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by khy on 7/12/28.
|
||||
*/
|
||||
public class FragmentStateAdapter extends FragmentStatePagerAdapter {
|
||||
|
||||
private List<Fragment> mFragmentList;
|
||||
|
||||
public FragmentStateAdapter(FragmentManager fm, List<Fragment> fragmentList) {
|
||||
super(fm);
|
||||
this.mFragmentList = fragmentList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
return mFragmentList.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mFragmentList.size();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
package com.gh.base.fragment;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
|
||||
import com.gh.common.util.ClickUtils;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.lightgame.utils.RuntimeUtils;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
/**
|
||||
* @author CsHeng
|
||||
* @Date 17/05/2017
|
||||
* @Time 4:30 PM
|
||||
*/
|
||||
|
||||
public class BaseDialogFragment extends DialogFragment {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
final Dialog dialog = new Dialog(getActivity(), R.style.DialogWindowTransparent);
|
||||
dialog.setCanceledOnTouchOutside(false);
|
||||
dialog.setOnKeyListener((dialog1, keyCode, event) -> {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK && !ClickUtils.isFastDoubleClick()) {
|
||||
return onBack();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
dialog.setCancelable(false);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public void toast(@StringRes int res) {
|
||||
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED))
|
||||
toast(getString(res));
|
||||
}
|
||||
|
||||
public void toast(String msg) {
|
||||
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED))
|
||||
Utils.toast(getContext(), msg);
|
||||
}
|
||||
|
||||
public void toastLong(@StringRes int msg) {
|
||||
toastLong(getString(msg));
|
||||
}
|
||||
|
||||
public void toastLong(String msg) {
|
||||
RuntimeUtils.getInstance().toastLong(getContext(), msg);
|
||||
}
|
||||
|
||||
public boolean onBack() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,65 @@
|
||||
package com.gh.base.fragment;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.gh.gamecenter.R;
|
||||
|
||||
/**
|
||||
* Wrap another fragment with dialog fragment.
|
||||
*/
|
||||
public class BaseDialogWrapperFragment extends BaseDialogFragment {
|
||||
|
||||
private Fragment mFragmentToWrap;
|
||||
|
||||
public static BaseDialogWrapperFragment getInstance(Fragment fragmentToWrap) {
|
||||
BaseDialogWrapperFragment fragment = new BaseDialogWrapperFragment();
|
||||
fragment.mFragmentToWrap = fragmentToWrap;
|
||||
return fragment;
|
||||
}
|
||||
|
||||
public static BaseDialogWrapperFragment getInstance(Fragment fragmentToWrap, boolean isCancelable) {
|
||||
BaseDialogWrapperFragment fragment = new BaseDialogWrapperFragment();
|
||||
fragment.mFragmentToWrap = fragmentToWrap;
|
||||
fragment.setCancelable(isCancelable);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_dialog_wrapper, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (mFragmentToWrap != null) {
|
||||
getChildFragmentManager().beginTransaction().replace(R.id.fragment_placeholder, mFragmentToWrap).commitNowAllowingStateLoss();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
||||
getDialog().getWindow().setGravity(Gravity.BOTTOM);
|
||||
getDialog().getWindow().setLayout(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
Dialog dialog = super.onCreateDialog(savedInstanceState);
|
||||
dialog.setCanceledOnTouchOutside(true);
|
||||
return dialog;
|
||||
}
|
||||
}
|
||||
@ -1,45 +1,90 @@
|
||||
package com.gh.base.fragment;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.LayoutRes;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.gh.base.OnListClickListener;
|
||||
import com.gh.base.OnRequestCallBackListener;
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.gh.common.constant.Constants;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.eventbus.EBMiPush;
|
||||
import com.lightgame.ToolbarController;
|
||||
import com.lightgame.OnTitleClickListener;
|
||||
import com.lightgame.utils.RuntimeUtils;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import butterknife.ButterKnife;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
import static com.gh.common.util.EntranceUtils.KEY_ENTRANCE;
|
||||
|
||||
/**
|
||||
* Created by LGT on 2016/9/4.
|
||||
* Fragment 基类
|
||||
*/
|
||||
public abstract class BaseFragment<T> extends Fragment implements OnRequestCallBackListener<T>,
|
||||
View.OnClickListener, ToolbarController {
|
||||
View.OnClickListener, OnListClickListener, OnTitleClickListener {
|
||||
|
||||
// TODO private view
|
||||
protected View view;
|
||||
public static final int RESULT_REFRESH = 9528;
|
||||
|
||||
protected View mCachedView;
|
||||
|
||||
protected boolean isEverPause;
|
||||
|
||||
@NonNull
|
||||
protected String mEntrance;
|
||||
|
||||
protected final Handler mBaseHandler = new BaseFragment.BaseHandler(this);
|
||||
|
||||
protected static class BaseHandler extends Handler {
|
||||
private final WeakReference<BaseFragment> mFragmentWeakReference;
|
||||
|
||||
BaseHandler(BaseFragment fragment) {
|
||||
mFragmentWeakReference = new WeakReference<>(fragment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
super.handleMessage(msg);
|
||||
BaseFragment fragment = mFragmentWeakReference.get();
|
||||
if (fragment != null) fragment.handleMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleMessage(Message msg) {
|
||||
|
||||
}
|
||||
|
||||
@LayoutRes
|
||||
protected abstract int getLayoutId();
|
||||
|
||||
/**
|
||||
* 提供 Inflated 的 view ,可用于 data binding.
|
||||
*/
|
||||
protected View getInflatedLayout() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 责任链,谁处理了就返回true,否则返回super.handleOnClick(View view)
|
||||
*
|
||||
@ -54,6 +99,7 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
|
||||
handleOnClick(v);
|
||||
}
|
||||
|
||||
|
||||
protected void initView(View view) {
|
||||
}
|
||||
|
||||
@ -61,56 +107,55 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
|
||||
RuntimeUtils.getInstance().runOnUiThread(runnable);
|
||||
}
|
||||
|
||||
// 定时任务全部改用这个方法, 在onDestroy做统一取消定时
|
||||
protected void postDelayedRunnable(Runnable runnable, long delayMillis) {
|
||||
RuntimeUtils.getInstance().runOnUiThread(runnable, delayMillis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNavigationTitle(@StringRes int res) {
|
||||
if (getActivity() instanceof ToolbarController) {
|
||||
((ToolbarController) getActivity()).setNavigationTitle(res);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNavigationTitle(CharSequence res) {
|
||||
if (getActivity() instanceof ToolbarController) {
|
||||
((ToolbarController) getActivity()).setNavigationTitle(res);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Toolbar getToolBar() {
|
||||
if (getActivity() instanceof ToolbarController) {
|
||||
return ((ToolbarController) getActivity()).getToolBar();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mEntrance = getActivity().getIntent().getStringExtra(EntranceUtils.KEY_ENTRANCE);
|
||||
final Intent intent = getActivity().getIntent();
|
||||
mEntrance = intent.getStringExtra(KEY_ENTRANCE);
|
||||
if (TextUtils.isEmpty(mEntrance) && getArguments() != null) {
|
||||
mEntrance = getArguments().getString(KEY_ENTRANCE);
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(mEntrance)) {
|
||||
mEntrance = Constants.ENTRANCE_UNKNOWN;
|
||||
}
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("FRAGMENT_ENTRANCE -> " + mEntrance);
|
||||
}
|
||||
|
||||
isEverPause = false;
|
||||
EventBus.getDefault().register(this);
|
||||
view = View.inflate(getContext(), getLayoutId(), null);
|
||||
ButterKnife.bind(this, view);
|
||||
initView(view);
|
||||
|
||||
// For data binding.
|
||||
if (getInflatedLayout() != null) {
|
||||
mCachedView = getInflatedLayout();
|
||||
} else {
|
||||
mCachedView = View.inflate(getContext(), getLayoutId(), null);
|
||||
}
|
||||
ButterKnife.bind(this, mCachedView);
|
||||
|
||||
initView(mCachedView);
|
||||
}
|
||||
|
||||
//TODO 尴尬,必须的有subscribe才能register
|
||||
// 必须的有subscribe才能register
|
||||
@Subscribe(threadMode = ThreadMode.BACKGROUND)
|
||||
public void onDummyEvent(EBMiPush push) {
|
||||
//
|
||||
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
if (container != null) {
|
||||
container.removeView(view);
|
||||
container.removeView(mCachedView);
|
||||
}
|
||||
return view;
|
||||
return mCachedView;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -128,11 +173,29 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
mBaseHandler.removeCallbacksAndMessages(null);
|
||||
RuntimeUtils.getInstance().removeRunnable();
|
||||
EventBus.getDefault().unregister(this);
|
||||
}
|
||||
|
||||
public void toast(@StringRes int res) {
|
||||
toast(getString(res));
|
||||
}
|
||||
|
||||
public void toast(String msg) {
|
||||
Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show();
|
||||
try {
|
||||
Utils.toast(getContext(), msg);
|
||||
} catch (Exception ignore) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void toastLong(@StringRes int msg) {
|
||||
toastLong(getString(msg));
|
||||
}
|
||||
|
||||
public void toastLong(String msg) {
|
||||
RuntimeUtils.getInstance().toastLong(getContext(), msg);
|
||||
}
|
||||
|
||||
public boolean isEverPause() {
|
||||
@ -145,7 +208,7 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadDone(Object obj) {
|
||||
public void loadDone(T obj) {
|
||||
|
||||
}
|
||||
|
||||
@ -159,4 +222,37 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public <LIST> void onListClick(View view, int position, LIST data) {
|
||||
|
||||
}
|
||||
|
||||
protected <K> Observable<K> asyncCall(Observable<K> observable) {
|
||||
return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
|
||||
}
|
||||
|
||||
// 将所有的Fragment都置为隐藏状态。
|
||||
protected void hideFragments(FragmentTransaction transaction) {
|
||||
List<Fragment> list = getChildFragmentManager().getFragments();
|
||||
for (Fragment fragment : list) {
|
||||
transaction.hide(fragment);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTitleClick() {
|
||||
List<Fragment> list = getChildFragmentManager().getFragments();
|
||||
for (Fragment fragment : list) {
|
||||
if (fragment instanceof OnTitleClickListener) {
|
||||
((OnTitleClickListener) fragment).onTitleClick();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 为 fragment 附加 bundle (setArgument())
|
||||
public BaseFragment with(Bundle bundle) {
|
||||
this.setArguments(bundle);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,118 @@
|
||||
package com.gh.base.fragment;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import android.view.View;
|
||||
|
||||
import com.gh.base.adapter.FragmentAdapter;
|
||||
import com.gh.common.view.TabIndicatorView;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.normal.NormalFragment;
|
||||
import com.lightgame.view.NoScrollableViewPager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.BindView;
|
||||
|
||||
/**
|
||||
* Created by khy on 15/03/18.
|
||||
*/
|
||||
|
||||
public abstract class BaseFragment_TabLayout extends NormalFragment implements ViewPager.OnPageChangeListener {
|
||||
|
||||
public static final String PAGE_INDEX = "PAGE_INDEX";
|
||||
|
||||
@BindView(R.id.fragment_tab_layout)
|
||||
protected TabLayout mTabLayout;
|
||||
@BindView(R.id.fragment_view_pager)
|
||||
protected NoScrollableViewPager mViewPager;
|
||||
@BindView(R.id.fragment_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 65;
|
||||
}
|
||||
|
||||
protected View provideTabView(int position, String tabTitle) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getLayoutId() {
|
||||
return R.layout.fragment_tablayout_viewpager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
List<Fragment> fragments = getChildFragmentManager().getFragments();
|
||||
if (fragments != null) {
|
||||
for (Fragment fragment : fragments) {
|
||||
fragment.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (getArguments() != null) mCheckedIndex = getArguments().getInt(PAGE_INDEX, 0);
|
||||
mFragmentsList = new ArrayList<>();
|
||||
initFragmentList(mFragmentsList);
|
||||
mTabTitleList = new ArrayList<>();
|
||||
initTabTitleList(mTabTitleList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
mViewPager.setOffscreenPageLimit(mFragmentsList.size());
|
||||
mViewPager.addOnPageChangeListener(this);
|
||||
mViewPager.setAdapter(new FragmentAdapter(getChildFragmentManager(), 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;
|
||||
View tabView = provideTabView(i, tab.getText() != null ? tab.getText().toString() : "");
|
||||
if (tabView == null) continue;
|
||||
tab.setCustomView(tabView);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
|
||||
}
|
||||
}
|
||||
@ -11,14 +11,15 @@ package com.gh.base.fragment;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.support.annotation.LayoutRes;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.view.PagerAdapter;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import androidx.annotation.IdRes;
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import android.view.View;
|
||||
|
||||
import com.gh.gamecenter.normal.NormalFragment;
|
||||
import com.lightgame.adapter.BaseFragmentPagerAdapter;
|
||||
import com.lightgame.config.CommonDebug;
|
||||
import com.lightgame.view.DoubleTapTextView;
|
||||
@ -33,9 +34,9 @@ import java.util.List;
|
||||
* @author CsHeng
|
||||
* @date 2013-3-6
|
||||
*/
|
||||
public abstract class BaseFragment_ViewPager extends BaseFragment implements DoubleTapTextView.OnDoubleTapListener {
|
||||
public abstract class BaseFragment_ViewPager extends NormalFragment implements DoubleTapTextView.OnDoubleTapListener {
|
||||
|
||||
protected static final String ARGS_INDEX = "index";
|
||||
public static final String ARGS_INDEX = "index";
|
||||
protected int mCheckedIndex = 0;
|
||||
protected PagerAdapter mAdapter;
|
||||
protected List<Fragment> mFragmentsList;
|
||||
@ -67,11 +68,6 @@ public abstract class BaseFragment_ViewPager extends BaseFragment implements Dou
|
||||
mViewPager = (ViewPager) view.findViewById(getViewPagerId());
|
||||
mViewPager.setOffscreenPageLimit(mFragmentsList.size());
|
||||
mViewPager.setAdapter(mAdapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
if (mCheckedIndex < mFragmentsList.size()) {
|
||||
mViewPager.setCurrentItem(mCheckedIndex, false);
|
||||
}
|
||||
@ -116,10 +112,15 @@ public abstract class BaseFragment_ViewPager extends BaseFragment implements Dou
|
||||
}
|
||||
List<Fragment> fragments = getChildFragmentManager().getFragments();
|
||||
if (fragments != null) {
|
||||
Fragment curFragment = fragments.get(mViewPager.getCurrentItem());
|
||||
curFragment.onActivityResult(requestCode, resultCode, data);
|
||||
for (Fragment fragment : fragments) {
|
||||
fragment.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int getCurrentItem() {
|
||||
return mViewPager != null ? mViewPager.getCurrentItem() : 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -10,13 +10,20 @@
|
||||
package com.gh.base.fragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Checkable;
|
||||
|
||||
import com.gh.gamecenter.fragment.MainWrapperFragment;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.IdRes;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
|
||||
/**
|
||||
* ViewPager 配合ViewGroup Checkable实现双切换<br/>
|
||||
@ -31,6 +38,8 @@ public abstract class BaseFragment_ViewPager_Checkable extends BaseFragment_View
|
||||
|
||||
protected ViewGroup mCheckableGroup;
|
||||
|
||||
private int mLastPosition = MainWrapperFragment.INDEX_HOME;
|
||||
|
||||
@IdRes
|
||||
protected abstract int getCheckableGroupId();
|
||||
|
||||
@ -68,6 +77,33 @@ public abstract class BaseFragment_ViewPager_Checkable extends BaseFragment_View
|
||||
@Override
|
||||
public void onPageSelected(int index) {
|
||||
onPageChanged(index);
|
||||
try {
|
||||
// 补充Viewpager Fragment的生命周期, 先调用旧选中 fragment 的 onPause 再当前的 onResume
|
||||
if (mFragmentsList.size() > mLastPosition) {
|
||||
Fragment fragment = mFragmentsList.get(mLastPosition);
|
||||
fragment.onPause();
|
||||
|
||||
FragmentManager childFragmentManager = fragment.getChildFragmentManager();
|
||||
List<Fragment> fragments = childFragmentManager.getFragments();
|
||||
for (Fragment childFragment : fragments) {
|
||||
childFragment.onPause();
|
||||
}
|
||||
}
|
||||
|
||||
if (mFragmentsList.size() > index) {
|
||||
Fragment fragment = mFragmentsList.get(index);
|
||||
fragment.onResume();
|
||||
|
||||
FragmentManager childFragmentManager = fragment.getChildFragmentManager();
|
||||
List<Fragment> fragments = childFragmentManager.getFragments();
|
||||
for (Fragment childFragment : fragments) {
|
||||
childFragment.onResume();
|
||||
}
|
||||
}
|
||||
mLastPosition = index;
|
||||
} catch (Exception ignore) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
163
app/src/main/java/com/gh/base/fragment/BaseLazyFragment.kt
Normal file
163
app/src/main/java/com/gh/base/fragment/BaseLazyFragment.kt
Normal file
@ -0,0 +1,163 @@
|
||||
package com.gh.base.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import com.gh.gamecenter.normal.NormalFragment
|
||||
|
||||
/**
|
||||
* 懒加载(支持多层嵌套)
|
||||
*/
|
||||
abstract class BaseLazyFragment : NormalFragment() {
|
||||
|
||||
private var mIsFirstVisible = true
|
||||
|
||||
private var isViewCreated = false
|
||||
|
||||
private var isSupportVisible = false
|
||||
|
||||
/**
|
||||
* 用于分发可见时间的时候父获取 fragment 是否隐藏
|
||||
*
|
||||
* @return true fragment 不可见, false 父 fragment 可见
|
||||
*/
|
||||
private val isParentInvisible: Boolean
|
||||
get() {
|
||||
val parentFragment = parentFragment
|
||||
return if (parentFragment is BaseLazyFragment) {
|
||||
val fragment = parentFragment as BaseLazyFragment?
|
||||
!fragment!!.isSupportVisible
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
|
||||
super.setUserVisibleHint(isVisibleToUser)
|
||||
// 对于默认 tab 和 间隔 checked tab 需要等到 isViewCreated = true 后才可以通过此通知用户可见
|
||||
// 这种情况下第一次可见不是在这里通知 因为 isViewCreated = false 成立,等从别的界面回到这里后会使用 onFragmentResume 通知可见
|
||||
// 对于非默认 tab mIsFirstVisible = true 会一直保持到选择则这个 tab 的时候,因为在 onActivityCreated 会返回 false
|
||||
if (isViewCreated) {
|
||||
if (isVisibleToUser && !isSupportVisible) {
|
||||
dispatchUserVisibleHint(true)
|
||||
} else if (!isVisibleToUser && isSupportVisible) {
|
||||
dispatchUserVisibleHint(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
|
||||
isViewCreated = true
|
||||
// !isHidden() 默认为 true 在调用 hide show 的时候可以使用
|
||||
if (!isHidden && userVisibleHint) {
|
||||
dispatchUserVisibleHint(true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onHiddenChanged(hidden: Boolean) {
|
||||
super.onHiddenChanged(hidden)
|
||||
|
||||
if (hidden) {
|
||||
dispatchUserVisibleHint(false)
|
||||
} else {
|
||||
dispatchUserVisibleHint(true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if (!mIsFirstVisible) {
|
||||
if (!isHidden && !isSupportVisible && userVisibleHint) {
|
||||
dispatchUserVisibleHint(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
// 当前 Fragment 包含子 Fragment 的时候 dispatchUserVisibleHint 内部本身就会通知子 Fragment 不可见
|
||||
// 子 fragment 走到这里的时候自身又会调用一遍 ?
|
||||
if (isSupportVisible && userVisibleHint) {
|
||||
dispatchUserVisibleHint(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 统一处理 显示隐藏
|
||||
*
|
||||
* @param visible
|
||||
*/
|
||||
private fun dispatchUserVisibleHint(visible: Boolean) {
|
||||
//当前 Fragment 是 child 时候 作为缓存 Fragment 的子 fragment getUserVisibleHint = true
|
||||
//但当父 fragment 不可见所以 currentVisibleState = false 直接 return 掉
|
||||
// 这里限制则可以限制多层嵌套的时候子 Fragment 的分发
|
||||
if (visible && isParentInvisible) return
|
||||
|
||||
//此处是对子 Fragment 不可见的限制,因为 子 Fragment 先于父 Fragment回调本方法 currentVisibleState 置位 false
|
||||
// 当父 dispatchChildVisibleState 的时候第二次回调本方法 visible = false 所以此处 visible 将直接返回
|
||||
if (isSupportVisible == visible) {
|
||||
return
|
||||
}
|
||||
|
||||
isSupportVisible = visible
|
||||
|
||||
if (visible) {
|
||||
if (mIsFirstVisible) {
|
||||
mIsFirstVisible = false
|
||||
onFragmentFirstVisible()
|
||||
}
|
||||
onFragmentResume()
|
||||
dispatchChildVisibleState(true)
|
||||
} else {
|
||||
dispatchChildVisibleState(false)
|
||||
onFragmentPause()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前 Fragment 是 child 时候 作为缓存 Fragment 的子 fragment 的唯一或者嵌套 VP 的第一 fragment 时 getUserVisibleHint = true
|
||||
* 但是由于父 Fragment 还未进入可见状态所以自身也是不可见的, 这个方法可以存在是因为庆幸的是 父 fragment 的生命周期回调总是先于子 Fragment
|
||||
* 所以在父 fragment 设置完成当前不可见状态后,需要通知子 Fragment 我不可见,你也不可见,
|
||||
*
|
||||
*
|
||||
* 因为 dispatchUserVisibleHint 中判断了 isParentInvisible 所以当 子 fragment 走到了 onActivityCreated 的时候直接 return 掉了
|
||||
*
|
||||
*
|
||||
* 当真正的外部 Fragment 可见的时候,走 setVisibleHint (VP 中)或者 onActivityCreated (hide show) 的时候
|
||||
* 从对应的生命周期入口调用 dispatchChildVisibleState 通知子 Fragment 可见状态
|
||||
*
|
||||
* @param visible
|
||||
*/
|
||||
private fun dispatchChildVisibleState(visible: Boolean) {
|
||||
val childFragmentManager = childFragmentManager
|
||||
val fragments = childFragmentManager.fragments
|
||||
if (!fragments.isEmpty()) {
|
||||
for (child in fragments) {
|
||||
if (child is BaseLazyFragment && !child.isHidden() && child.getUserVisibleHint()) {
|
||||
child.dispatchUserVisibleHint(visible)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open fun onFragmentFirstVisible() {
|
||||
//ULog.e("对用户第一次可见")
|
||||
}
|
||||
|
||||
open fun onFragmentResume() {
|
||||
//ULog.e("对用户可见")
|
||||
}
|
||||
|
||||
open fun onFragmentPause() {
|
||||
//ULog.e("对用户不可见")
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
isViewCreated = false
|
||||
mIsFirstVisible = true
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
package com.gh.base.fragment;
|
||||
|
||||
public interface OnDialogBackListener {
|
||||
void onBack();
|
||||
}
|
||||
@ -0,0 +1,114 @@
|
||||
package com.gh.base.fragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.gh.gamecenter.R;
|
||||
|
||||
/**
|
||||
* @author CsHeng
|
||||
* @Date 17/05/2017
|
||||
* @Time 4:27 PM
|
||||
*/
|
||||
public class WaitingDialogFragment extends BaseDialogFragment {
|
||||
|
||||
public static final String KEY_MSG = "msg";
|
||||
|
||||
private OnDialogBackListener mBackListener;
|
||||
|
||||
private TextView message;
|
||||
|
||||
public static WaitingDialogFragment newInstance(String message) {
|
||||
Bundle args = new Bundle();
|
||||
args.putString(KEY_MSG, message);
|
||||
WaitingDialogFragment fragment = new WaitingDialogFragment();
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
public static WaitingDialogFragment newInstance(String message, boolean isCancelable) {
|
||||
Bundle args = new Bundle();
|
||||
args.putString(KEY_MSG, message);
|
||||
WaitingDialogFragment fragment = new WaitingDialogFragment();
|
||||
fragment.setArguments(args);
|
||||
fragment.setCancelable(isCancelable);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
final View view = inflater.inflate(R.layout.set_wait_dialog, null);
|
||||
message = view.findViewById(R.id.set_wait_message);
|
||||
message.setText(getArguments().getString(KEY_MSG));
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show(FragmentManager manager, String tag) {
|
||||
try {
|
||||
super.show(manager, tag);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void show(FragmentManager manager, String tag, OnDialogBackListener backListener) {
|
||||
show(manager, tag);
|
||||
this.mBackListener = backListener;
|
||||
}
|
||||
|
||||
public void uploadWaitingHint(String hint) {
|
||||
if (message != null) message.setText(hint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBack() {
|
||||
if (mBackListener != null) {
|
||||
mBackListener.onBack();
|
||||
return true;
|
||||
}
|
||||
return super.onBack();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismiss() {
|
||||
mBackListener = null;
|
||||
super.dismiss();
|
||||
}
|
||||
|
||||
public static class WaitingDialogData {
|
||||
private String msg;
|
||||
|
||||
private boolean isShow;
|
||||
|
||||
public WaitingDialogData(String msg, boolean isShow) {
|
||||
this.msg = msg;
|
||||
this.isShow = isShow;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public boolean isShow() {
|
||||
return isShow;
|
||||
}
|
||||
|
||||
public void setShow(boolean show) {
|
||||
isShow = show;
|
||||
}
|
||||
}
|
||||
}
|
||||
33
app/src/main/java/com/gh/common/AppExecutor.kt
Normal file
33
app/src/main/java/com/gh/common/AppExecutor.kt
Normal file
@ -0,0 +1,33 @@
|
||||
package com.gh.common
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import java.util.concurrent.Executor
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
object AppExecutor {
|
||||
@JvmStatic
|
||||
var ioExecutor = Executors.newSingleThreadExecutor()
|
||||
@JvmStatic
|
||||
var uiExecutor = MainThreadExecutor()
|
||||
|
||||
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(f: () -> Unit) {
|
||||
AppExecutor.ioExecutor.execute(f)
|
||||
}
|
||||
|
||||
fun runOnUiThread(f: () -> Unit) {
|
||||
AppExecutor.uiExecutor.execute(f)
|
||||
}
|
||||
5
app/src/main/java/com/gh/common/Base64ImageHolder.kt
Normal file
5
app/src/main/java/com/gh/common/Base64ImageHolder.kt
Normal file
@ -0,0 +1,5 @@
|
||||
package com.gh.common
|
||||
|
||||
object Base64ImageHolder {
|
||||
var image: String = ""
|
||||
}
|
||||
153
app/src/main/java/com/gh/common/DefaultJsApi.kt
Normal file
153
app/src/main/java/com/gh/common/DefaultJsApi.kt
Normal file
@ -0,0 +1,153 @@
|
||||
package com.gh.common
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.webkit.JavascriptInterface
|
||||
import androidx.annotation.Keep
|
||||
import com.gh.base.CurrentActivityHolder
|
||||
import com.gh.common.util.*
|
||||
import com.gh.gamecenter.LoginActivity
|
||||
import com.gh.gamecenter.ViewImageActivity
|
||||
import com.gh.gamecenter.entity.Badge
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.gh.gamecenter.room.AppDatabase
|
||||
import com.gh.gamecenter.user.LoginTag
|
||||
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 wendu.dsbridge.CompletionHandler
|
||||
|
||||
class DefaultJsApi(var context: Context) {
|
||||
|
||||
@JavascriptInterface
|
||||
fun isGhzs(msg: Any): String {
|
||||
return "true"
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun toast(msg: Any) {
|
||||
Utils.toast(HaloApp.getInstance().application, msg.toString())
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun logMtaEvent(event: Any) {
|
||||
val mtaEvent = event.toString().toObject() ?: MtaEvent()
|
||||
|
||||
MtaHelper.onEvent(mtaEvent.name, mtaEvent.key, mtaEvent.value)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun getUserInfo(msg: Any): String {
|
||||
return UserManager.getInstance().userInfoEntity.toJson()
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun getUserToken(msg: Any): String {
|
||||
return if (UserManager.getInstance().isLoggedIn) UserManager.getInstance().loginTokenEntity.accessToken.value else ""
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun login(msg: Any) {
|
||||
val intent = LoginActivity.getIntent(context, "浏览器")
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun refreshUserInfoBadge(msg: Any) {
|
||||
val userInfoEntity = UserManager.getInstance().userInfoEntity
|
||||
if (msg.toString().isNotEmpty()) {
|
||||
val badge = msg.toString().toObject() ?: Badge()
|
||||
userInfoEntity.badge = badge
|
||||
} else {
|
||||
userInfoEntity.badge = null
|
||||
}
|
||||
UserManager.getInstance().userInfoEntity = userInfoEntity
|
||||
AppDatabase.getInstance(context).userInfoDao().updateUserInfo(userInfoEntity)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun getChannel(msg: Any): String {
|
||||
return HaloApp.getInstance().channel
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun bindWechat(msg: Any, handler: CompletionHandler<Any>) {
|
||||
context.ifLogin("浏览器") {
|
||||
LoginHelper.loginWithWechat(object : LoginHelper.LoginCallback {
|
||||
@SuppressLint("CheckResult")
|
||||
override fun onLoginSuccess(loginType: LoginTag, jsonContent: JSONObject) {
|
||||
|
||||
val wechatLoginInfoMap = hashMapOf<String, String>()
|
||||
wechatLoginInfoMap["openid"] = jsonContent.getString("openid")
|
||||
wechatLoginInfoMap["unionid"] = jsonContent.getString("unionid")
|
||||
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) {
|
||||
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 onLoginFailure(loginType: LoginTag, error: String) {
|
||||
handler.complete(false)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun copyText(msg: Any) {
|
||||
msg.toString().copyTextAndToast()
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun startApp(msg: Any) {
|
||||
val packageName = msg.toString()
|
||||
PackageUtils.launchApplicationByPackageName(HaloApp.getInstance().application, packageName)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun openImage(event: Any) {
|
||||
val imageEvent = event.toString().toObject() ?: ImageEvent()
|
||||
|
||||
val context = CurrentActivityHolder.getCurrentActivity()
|
||||
|
||||
context?.startActivity(ViewImageActivity.getViewImageIntent(context, imageEvent.imageList, imageEvent.position, "浏览器"))
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun openBase64Image(event: Any) {
|
||||
val context = CurrentActivityHolder.getCurrentActivity()
|
||||
|
||||
Base64ImageHolder.image = event.toString()
|
||||
|
||||
context?.startActivity(ViewImageActivity.getBase64ViewImageIntent(context, true))
|
||||
}
|
||||
|
||||
@Keep
|
||||
internal data class MtaEvent(var name: String = "", var key: String = "", var value: String = "")
|
||||
|
||||
@Keep
|
||||
internal data class ImageEvent(var imageList: ArrayList<String> = arrayListOf(), var position: Int = 0)
|
||||
|
||||
}
|
||||
133
app/src/main/java/com/gh/common/DefaultWebViewUrlHandler.kt
Normal file
133
app/src/main/java/com/gh/common/DefaultWebViewUrlHandler.kt
Normal file
@ -0,0 +1,133 @@
|
||||
package com.gh.common
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.text.TextUtils
|
||||
import com.gh.common.util.CheckLoginUtils
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.EntranceUtils
|
||||
import com.gh.gamecenter.GameDetailActivity
|
||||
import com.gh.gamecenter.LibaoDetailActivity
|
||||
import com.gh.gamecenter.NewsDetailActivity
|
||||
import com.gh.gamecenter.WebActivity
|
||||
import com.gh.gamecenter.entity.CommunityEntity
|
||||
import com.gh.gamecenter.entity.VideoLinkEntity
|
||||
import com.gh.gamecenter.subject.SubjectActivity
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
|
||||
object DefaultWebViewUrlHandler {
|
||||
|
||||
@JvmStatic
|
||||
fun interceptUrl(context: Context, url: String, entrance: String): Boolean {
|
||||
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)
|
||||
}
|
||||
val intent: Intent
|
||||
when (host) {
|
||||
"article" -> context.startActivity(NewsDetailActivity.getIntentById(context, id, entrance))
|
||||
|
||||
"game" -> GameDetailActivity.startGameDetailActivity(context, id, entrance)
|
||||
|
||||
"column" -> SubjectActivity.startSubjectActivity(context, id, uri.getQueryParameter("name"), false, entrance)
|
||||
|
||||
"libao" -> context.startActivity(LibaoDetailActivity.getIntentById(context, id, entrance))
|
||||
|
||||
"qq" -> try {
|
||||
DirectUtils.directToQqConversation(context, id)
|
||||
} catch (e: Exception) {
|
||||
Utils.toast(context, "请检查是否已经安装手机QQ")
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
"qqqun" -> {
|
||||
val key = uri.getQueryParameter("key")
|
||||
if (!DirectUtils.directToQqGroup(context, key)) {
|
||||
Utils.toast(context, "请检查是否已经安装手机QQ")
|
||||
}
|
||||
}
|
||||
|
||||
"inurl" -> {
|
||||
intent = Intent(context, WebActivity::class.java)
|
||||
intent.putExtra(EntranceUtils.KEY_URL, uri.getQueryParameter("url"))
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
"outurl" -> {
|
||||
intent = Intent()
|
||||
intent.action = Intent.ACTION_VIEW
|
||||
intent.data = Uri.parse(uri.getQueryParameter("url"))
|
||||
try {
|
||||
context.startActivity(intent)
|
||||
} catch (e: Exception) {
|
||||
Utils.toast(context, "请检查是否已经安装手机浏览器")
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
}
|
||||
"question" -> DirectUtils.directToQuestionDetail(context, id, entrance, "文章链接")
|
||||
|
||||
"community" -> {
|
||||
val community = CommunityEntity()
|
||||
community.id = id
|
||||
community.name = uri.getQueryParameter("name")
|
||||
DirectUtils.directToCommunity(context, community)
|
||||
}
|
||||
|
||||
"answer" -> DirectUtils.directToAnswerDetail(context, id, entrance, "文章链接")
|
||||
|
||||
"communities" -> {
|
||||
// ghzhushou://communities/5a32405b2397ab000f688de3/articles/5c99d262c140b321564f04e3
|
||||
var communityId = ""
|
||||
var type = ""
|
||||
var typeId = ""
|
||||
val split = id.split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
for (text in split) {
|
||||
if (TextUtils.isEmpty(communityId)) {
|
||||
communityId = text
|
||||
continue
|
||||
}
|
||||
if (TextUtils.isEmpty(type)) {
|
||||
type = text
|
||||
continue
|
||||
}
|
||||
if (TextUtils.isEmpty(typeId)) {
|
||||
typeId = text
|
||||
}
|
||||
}
|
||||
if ("articles" == type) {
|
||||
DirectUtils.directToCommunityArticle(
|
||||
context, typeId, communityId,
|
||||
entrance, "文章链接")
|
||||
}
|
||||
}
|
||||
EntranceUtils.HOST_UPLOAD_VIDEO -> {
|
||||
val titleParameter = uri.getQueryParameter("title")
|
||||
val title = if (titleParameter.isNullOrEmpty()) "" else "#$titleParameter#"
|
||||
val categoryId = uri.getQueryParameter("category_id") ?: ""
|
||||
val link = uri.getQueryParameter("link") ?: ""
|
||||
val linkEntity = VideoLinkEntity(title, categoryId, link)
|
||||
if (!CheckLoginUtils.isLogin()) {
|
||||
HaloApp.put(EntranceUtils.HOST_UPLOAD_VIDEO, linkEntity)
|
||||
}
|
||||
CheckLoginUtils.checkLogin(context, EntranceUtils.ENTRANCE_BROWSER) {
|
||||
DirectUtils.directToVideoManager(context, linkEntity, EntranceUtils.ENTRANCE_BROWSER, "")
|
||||
}
|
||||
}
|
||||
else -> DialogUtils.showLowVersionDialog(context)
|
||||
}
|
||||
return true
|
||||
}
|
||||
if ("http" != uri.scheme && "https" != uri.scheme) return true
|
||||
return false
|
||||
}
|
||||
}
|
||||
39
app/src/main/java/com/gh/common/LocalBroadcastReceiver.kt
Normal file
39
app/src/main/java/com/gh/common/LocalBroadcastReceiver.kt
Normal file
@ -0,0 +1,39 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
140
app/src/main/java/com/gh/common/PushManager.kt
Normal file
140
app/src/main/java/com/gh/common/PushManager.kt
Normal file
@ -0,0 +1,140 @@
|
||||
package com.gh.common
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.preference.PreferenceManager
|
||||
import com.gh.base.GHUmengNotificationService
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.exposure.meta.MetaUtil
|
||||
import com.gh.common.util.edit
|
||||
import com.gh.common.util.toJson
|
||||
import com.gh.common.util.toObject
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.entity.AliasEntity
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import com.umeng.commonsdk.UMConfigure
|
||||
import com.umeng.message.IUmengRegisterCallback
|
||||
import com.umeng.message.PushAgent
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.RequestBody
|
||||
import org.android.agoo.huawei.HuaWeiRegister
|
||||
import org.android.agoo.mezu.MeizuRegister
|
||||
import org.android.agoo.xiaomi.MiPushRegistar
|
||||
import org.json.JSONObject
|
||||
|
||||
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) {
|
||||
//初始化友盟推送
|
||||
UMConfigure.init(mApplication,
|
||||
Config.UMENG_APPKEY, channel,
|
||||
UMConfigure.DEVICE_TYPE_PHONE,
|
||||
Config.UMENG_MESSAGE_SECRET)
|
||||
|
||||
// 注册小米、华为和魅族通道
|
||||
MiPushRegistar.register(mApplication, Config.MIPUSH_APPID, Config.MIPUSH_APPKEY)
|
||||
HuaWeiRegister.register(mApplication)
|
||||
MeizuRegister.register(mApplication, BuildConfig.MEIZUPUSH_APPID, BuildConfig.MEIZUPUSH_APPKEY)
|
||||
|
||||
//友盟推送
|
||||
val pushAgent = PushAgent.getInstance(mApplication)
|
||||
pushAgent.onAppStart() // 开启App统计
|
||||
|
||||
//注册推送服务,每次调用register方法都会回调该接口
|
||||
registerDevice()
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
121
app/src/main/java/com/gh/common/TimeElapsedHelper.kt
Normal file
121
app/src/main/java/com/gh/common/TimeElapsedHelper.kt
Normal file
@ -0,0 +1,121 @@
|
||||
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.halo.assistant.HaloApp
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
/**
|
||||
* 统计用户在当前 Fragment 的停留时间,在 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 = Executors.newSingleThreadExecutor()
|
||||
}
|
||||
|
||||
interface TimeoutCallback {
|
||||
fun onTimeout()
|
||||
}
|
||||
11
app/src/main/java/com/gh/common/annotation/Synchronize.java
Normal file
11
app/src/main/java/com/gh/common/annotation/Synchronize.java
Normal file
@ -0,0 +1,11 @@
|
||||
package com.gh.common.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Synchronize {
|
||||
}
|
||||
@ -1,26 +1,42 @@
|
||||
package com.gh.common.constant;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.gh.common.util.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.entity.NewsEntity;
|
||||
import com.gh.gamecenter.entity.SettingsEntity;
|
||||
import com.gh.gamecenter.eventbus.EBReuse;
|
||||
import com.gh.gamecenter.retrofit.Response;
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
public class Config {
|
||||
|
||||
public static final String HOST = BuildConfig.HOST;
|
||||
public static final String USER_HOST = BuildConfig.USER_HOST;
|
||||
public static final String API_HOST = BuildConfig.API_HOST;
|
||||
public static final String COMMENT_HOST = BuildConfig.COMMENT_HOST;
|
||||
public static final String DATA_HOST = BuildConfig.DATA_HOST;
|
||||
public static final String LIBAO_HOST = BuildConfig.LIBAO_HOST;
|
||||
public static final String MESSAGE_HOST = BuildConfig.MESSAGE_HOST;
|
||||
|
||||
/**
|
||||
* 需要配置的请使用{@link PreferenceManager#getDefaultSharedPreferences(Context)}
|
||||
*/
|
||||
// @Deprecated
|
||||
// public static final String PREFERENCE = "ghzhushou";
|
||||
|
||||
// Third-Party confs
|
||||
public static final String WECHAT_APPID = BuildConfig.WECHAT_APPID;
|
||||
@ -30,13 +46,228 @@ public class Config {
|
||||
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 TD_APPID = BuildConfig.TD_APPID;// TalkingData
|
||||
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;
|
||||
// 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 boolean isShow(Context context) {
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
return sp.getBoolean("isShow", true);
|
||||
public static final String DEFAULT_CHANNEL = "GH_TEST";
|
||||
|
||||
private static String SETTINGS_KEY = "settingsKey";
|
||||
|
||||
private static SettingsEntity mSettingsEntity;
|
||||
|
||||
public static final String FIX_DOWNLOAD_KEY = "isFixDownload";
|
||||
public static final String FIX_PLUGIN_KEY = "isFixPlugin";
|
||||
public static final String FIX_ARTICLE_KEY = "isFixArticle";
|
||||
public static final String FIX_COMMUNITY_KEY = "isFixCommunity";
|
||||
|
||||
public static final int VIDEO_PAGE_SIZE = 21; // 视频列表大多都是一行3个
|
||||
|
||||
public static boolean isShow() {
|
||||
if (getPreferences().getBoolean(FIX_DOWNLOAD_KEY, false)) return true;
|
||||
|
||||
if (!isExistDownloadFilter()) return false;
|
||||
|
||||
for (SettingsEntity.Download entity : getSettings().getDownload()) {
|
||||
if ("all".equals(entity.getGame())) {
|
||||
if (entity.getPluginfy() && "normal".equals(entity.getPolicy()) && filterTime(entity.getTime())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
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) {
|
||||
|
||||
if (getPreferences().getBoolean(FIX_DOWNLOAD_KEY, false)) return true;
|
||||
|
||||
if (TextUtils.isEmpty(gameId) || !isExistDownloadFilter())
|
||||
return false;
|
||||
|
||||
for (SettingsEntity.Download entity : getSettings().getDownload()) {
|
||||
if (gameId.equals(entity.getGame())) {
|
||||
if ("normal".equals(entity.getPolicy()) && filterTime(entity.getTime())) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if ("all".equals(entity.getGame())) {
|
||||
if ("normal".equals(entity.getPolicy()) && filterTime(entity.getTime())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public static boolean isShowPlugin(String gameId) {
|
||||
SharedPreferences preferences = getPreferences();
|
||||
boolean isFixPlugin = preferences.getBoolean(FIX_PLUGIN_KEY, false);
|
||||
if (isFixPlugin) return true;
|
||||
|
||||
if (TextUtils.isEmpty(gameId) || !isExistDownloadFilter())
|
||||
return false;
|
||||
|
||||
for (SettingsEntity.Download entity : getSettings().getDownload()) {
|
||||
if (gameId.equals(entity.getGame())) {
|
||||
if (entity.getPluginfy() && filterTime(entity.getTime())) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ("all".equals(entity.getGame())) {
|
||||
if (entity.getPluginfy() && filterTime(entity.getTime())) {
|
||||
preferences.edit().putBoolean(FIX_PLUGIN_KEY, true).apply();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isShowPlugin() {
|
||||
SharedPreferences preferences = getPreferences();
|
||||
boolean isFixPlugin = preferences.getBoolean(FIX_PLUGIN_KEY, false);
|
||||
if (isFixPlugin) return true;
|
||||
|
||||
if (!isExistDownloadFilter())
|
||||
return false;
|
||||
|
||||
for (SettingsEntity.Download entity : getSettings().getDownload()) {
|
||||
if ("all".equals(entity.getGame())) {
|
||||
if (entity.getPluginfy() && filterTime(entity.getTime())) {
|
||||
preferences.edit().putBoolean(FIX_PLUGIN_KEY, true).apply();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean filterTime(SettingsEntity.Download.TimeEntity timeEntity) {
|
||||
long end = timeEntity.getEnd();
|
||||
long start = timeEntity.getStart();
|
||||
long curTime = Utils.getTime(HaloApp.getInstance().getApplication());
|
||||
|
||||
if ((start == 0 || curTime >= start) && (end == 0 || curTime <= end)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void setSettings(SettingsEntity settingsEntity) {
|
||||
getPreferences().edit().putString(SETTINGS_KEY, GsonUtils.toJson(settingsEntity)).apply();
|
||||
mSettingsEntity = settingsEntity;
|
||||
|
||||
// 更新 FIX_ARTICLE_KEY 状态
|
||||
mSettingsEntity.showArticleEntrance();
|
||||
|
||||
// 加载完设置后刷新下
|
||||
PackageHelper.initList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static SettingsEntity getSettings() {
|
||||
if (mSettingsEntity == null) {
|
||||
try {
|
||||
String json = getPreferences().getString(SETTINGS_KEY, null);
|
||||
if (!TextUtils.isEmpty(json)) {
|
||||
mSettingsEntity = GsonUtils.fromJson(json, SettingsEntity.class);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return mSettingsEntity;
|
||||
}
|
||||
|
||||
private static boolean isExistDownloadFilter() {
|
||||
if (getSettings() == null || getSettings().getDownload() == null || getSettings().getDownload().size() == 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void filterPluginArticle(List<NewsEntity> list) {
|
||||
if (isShowPlugin() || list == null) return;
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
NewsEntity newsEntity = list.get(i);
|
||||
String title = newsEntity.getTitle();
|
||||
if (!TextUtils.isEmpty(title) && title.contains("插件")) {
|
||||
list.remove(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static SharedPreferences getPreferences() {
|
||||
return PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().getApplication());
|
||||
}
|
||||
|
||||
public static boolean isExistHideFunction() {
|
||||
SharedPreferences preferences = getPreferences();
|
||||
if (!preferences.getBoolean(FIX_DOWNLOAD_KEY, false)) return true;
|
||||
if (!preferences.getBoolean(FIX_PLUGIN_KEY, false)) return true;
|
||||
if (!preferences.getBoolean(FIX_COMMUNITY_KEY, false)) return true;
|
||||
if (!preferences.getBoolean(FIX_ARTICLE_KEY, false)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void fixHideFunction() {
|
||||
SharedPreferences preferences = PreferenceManager.
|
||||
getDefaultSharedPreferences(HaloApp.getInstance().getApplication());
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean(Config.FIX_DOWNLOAD_KEY, true);
|
||||
editor.putBoolean(Config.FIX_ARTICLE_KEY, true);
|
||||
editor.putBoolean(Config.FIX_COMMUNITY_KEY, true);
|
||||
editor.putBoolean(Config.FIX_PLUGIN_KEY, true);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void getGhzsSettings() {
|
||||
String channel = HaloApp.getInstance().getChannel();
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().getApplication())
|
||||
.getApi().getSettings(PackageUtils.getVersionName(), channel)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Response<SettingsEntity>() {
|
||||
@Override
|
||||
public void onResponse(SettingsEntity response) {
|
||||
Config.setSettings(response);
|
||||
|
||||
// 意见反馈
|
||||
SharedPreferences.Editor edit = getPreferences().edit();
|
||||
edit.putString(SuggestionActivity.SUGGESTION_HINT_TYPE,
|
||||
GsonUtils.toJson(response.getSuggestion()));
|
||||
edit.apply();
|
||||
|
||||
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"));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,56 @@
|
||||
package com.gh.common.constant;
|
||||
|
||||
import com.gh.common.util.PackageUtils;
|
||||
|
||||
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 LOGIN_TOKEN_ID = "userToken_id"; // 用户ID 与服务器无关
|
||||
|
||||
public static final String USER_TOKEN_KEY = "userTokenKey";
|
||||
public static final String USER_INFO_KEY = "userInfoKey";
|
||||
|
||||
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 XPOSED_INSTALLER_PACKAGE_NAME = "de.robv.android.xposed.installer";
|
||||
|
||||
public static final String EB_QUIT_LOGIN = "quit_login";
|
||||
|
||||
// 最近显示的弹窗信息
|
||||
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 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_NEW_VERSION = "show_notification_new_version";
|
||||
// 今天是否已经触发了 “通知管理” 引导弹窗
|
||||
public static final String SP_IS_SHOWED_NOTIFICATION_TODAY = "show_is_notification_today";
|
||||
// 标记安装的游戏为已玩过弹窗,最多取消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_SHOW_SLIDE_GUIDE = "show_slide_guide";
|
||||
//视频详情点击引导
|
||||
public static final String SP_SHOW_CLICK_GUIDE = "show_click_guide";
|
||||
|
||||
//手机号码匹配规则
|
||||
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}$";
|
||||
@ -13,6 +59,14 @@ public class Constants {
|
||||
//输入规则
|
||||
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 BADGE_ADDRESS_DEV = "http://resource.ghzs.com/page/badge_dev/index.html#/";
|
||||
public static final String BADGE_ADDRESS = "http://resource.ghzs.com/page/badge_pro/index.html#/";
|
||||
|
||||
//最少需要多少数据才能上传
|
||||
public static final int DATA_AMOUNT = 20;
|
||||
|
||||
@ -28,5 +82,15 @@ public class Constants {
|
||||
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;
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
@ -8,6 +8,8 @@ public class ItemViewType {
|
||||
public static final int COLUMN_HEADER = 0; // 专题头部布局
|
||||
public static final int GAME_SLIDE = 1; // 滚动图布局
|
||||
public static final int GAME_NORMAL = 2; // 正常游戏布局
|
||||
public static final int GAME_SUBJECT = 19;
|
||||
public static final int GAME_SUBJECT_SLIDE = 26;
|
||||
public static final int GAME_TEST = 3; // 测试游戏布局
|
||||
public static final int GAME_IMAGE = 4; // 游戏大图布局
|
||||
public static final int NEWS_HEADER = 5; // 新闻头部布局
|
||||
@ -21,6 +23,21 @@ public class ItemViewType {
|
||||
public static final int LOADING = 14; // 加载布局
|
||||
public static final int LIBAO_NORMAL = 15; // 礼包正常布局
|
||||
public static final int LIBAO_SKIP_CONCERN = 16; // 跳转关注管理页面布局
|
||||
public static final int KC_HINT = 16;
|
||||
public static final int KC_HINT = 17;
|
||||
public static final int GAME_PLUGIN = 18; // 游戏插件模块
|
||||
public static final int ASK_REFRESH = 19; // 问答精选 刷新
|
||||
public static final int ITEM_EMPTY = 20;
|
||||
public static final int ASK_CONCERN = 21; // 问答精选 关注
|
||||
public static final int RATING_ITEM = 22; // 问答精选 关注
|
||||
public static final int IMAGE_SLIDE_ITEM = 23;
|
||||
public static final int VERTICAL_SLIDE_ITEM = 24;
|
||||
public static final int COLUMN_COLLECTION = 25;
|
||||
|
||||
/**
|
||||
* 普通列表
|
||||
*/
|
||||
public static final int ITEM_BODY = 100;
|
||||
public static final int ITEM_FOOTER = 101;
|
||||
public static final int ITEM_HEADER = 102;
|
||||
|
||||
}
|
||||
|
||||
666
app/src/main/java/com/gh/common/databind/BindingAdapters.java
Normal file
666
app/src/main/java/com/gh/common/databind/BindingAdapters.java
Normal file
@ -0,0 +1,666 @@
|
||||
package com.gh.common.databind;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.TextUtils;
|
||||
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 com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.gh.base.OnViewClickListener;
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.common.dialog.ReserveDialogFragment;
|
||||
import com.gh.common.exposure.ExposureEvent;
|
||||
import com.gh.common.exposure.ExposureUtils;
|
||||
import com.gh.common.repository.ReservationRepository;
|
||||
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.PackageUtils;
|
||||
import com.gh.common.util.PermissionHelper;
|
||||
import com.gh.common.util.PlatformUtils;
|
||||
import com.gh.common.util.ReservationHelper;
|
||||
import com.gh.common.view.DownloadDialog;
|
||||
import com.gh.common.view.DownloadProgressBar;
|
||||
import com.gh.common.view.DrawableView;
|
||||
import com.gh.download.DownloadManager;
|
||||
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.databinding.KaifuDetailItemRowBinding;
|
||||
import com.gh.gamecenter.entity.ApkEntity;
|
||||
import com.gh.gamecenter.entity.GameEntity;
|
||||
import com.gh.gamecenter.entity.LinkEntity;
|
||||
import com.gh.gamecenter.entity.PluginLocation;
|
||||
import com.gh.gamecenter.entity.ServerCalendarEntity;
|
||||
import com.gh.gamecenter.entity.TagStyleEntity;
|
||||
import com.gh.gamecenter.eventbus.EBReuse;
|
||||
import com.gh.gamecenter.manager.PackagesManager;
|
||||
import com.gh.gamecenter.qa.entity.CommunityVideoEntity;
|
||||
import com.lightgame.download.DownloadEntity;
|
||||
import com.lightgame.download.FileUtils;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.databinding.BindingAdapter;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
/**
|
||||
* Created by khy on 12/02/18.
|
||||
*/
|
||||
|
||||
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({"addDetailKaiFuView", "addDetailKaiFuViewListener", "isReadyPatch"})
|
||||
public static void addDetailKaiFuView(LinearLayout view, List<ServerCalendarEntity> list
|
||||
, OnViewClickListener listener, Boolean isReadyPatch) {
|
||||
if (list == null) return;
|
||||
view.removeAllViews();
|
||||
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().setOnClickListener(v -> {
|
||||
listener.onClick(v, isReadyPatch != null && isReadyPatch ? serverEntity : null);
|
||||
});
|
||||
|
||||
// 滑动冲突处理
|
||||
binding.getRoot().setOnTouchListener((v, event) -> {
|
||||
if (list.size() > 5) {
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
EventBus.getDefault().post(new EBReuse("CalenderDown"));
|
||||
} else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
|
||||
EventBus.getDefault().post(new EBReuse("CalenderCancel"));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
view.addView(inflate);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果超过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("visibleGone")
|
||||
public static void showHide(View view, Boolean show) {
|
||||
if (show != null && show) {
|
||||
view.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
view.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("messageUnread")
|
||||
public static void setMessageUnread(TextView view, int unreadCount) {
|
||||
if (unreadCount < 100) {
|
||||
view.setText(String.valueOf(unreadCount));
|
||||
} else {
|
||||
view.setText("99+");
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("serverTypePadding")
|
||||
public static void setServerTypePadding(TextView view, String serverType) {
|
||||
int paddRight = 0;
|
||||
if (TextUtils.isEmpty(serverType)) {
|
||||
} else {
|
||||
if ("删档内测".equals(serverType) || "不删档内测".equals(serverType)) {
|
||||
if ("删档内测".equals(serverType)) {
|
||||
paddRight = DisplayUtils.dip2px(view.getContext(), 50);
|
||||
} else {
|
||||
paddRight = DisplayUtils.dip2px(view.getContext(), 60);
|
||||
}
|
||||
} else {
|
||||
paddRight = DisplayUtils.dip2px(view.getContext(), 30);
|
||||
}
|
||||
}
|
||||
view.setPadding(0, 0, paddRight, 0);
|
||||
}
|
||||
|
||||
@BindingAdapter("serverType")
|
||||
public static void setServerType(TextView view, String serverType) {
|
||||
view.setText(serverType);
|
||||
if ("删档内测".equals(serverType) || "不删档内测".equals(serverType)) {
|
||||
view.setBackgroundResource(R.drawable.textview_server_tag);
|
||||
} else {
|
||||
view.setBackgroundResource(R.drawable.textview_orange_up);
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("articleType")
|
||||
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);
|
||||
view.setTextColor(0xFF999999);
|
||||
view.setClickable(false);
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("liBaoBtn")
|
||||
public static void setLiBaoBtn(TextView view, String status) {
|
||||
if (TextUtils.isEmpty(status)) return;
|
||||
switch (status) {
|
||||
case "coming":
|
||||
view.setText(R.string.libao_coming);
|
||||
view.setBackgroundResource(R.drawable.textview_blue_style);
|
||||
break;
|
||||
case "ling":
|
||||
view.setText(R.string.libao_ling);
|
||||
view.setBackgroundResource(R.drawable.textview_green_style);
|
||||
break;
|
||||
case "tao":
|
||||
view.setText(R.string.libao_tao);
|
||||
view.setBackgroundResource(R.drawable.textview_orange_style);
|
||||
break;
|
||||
case "used_up":
|
||||
view.setText(R.string.libao_used_up);
|
||||
view.setBackgroundResource(R.drawable.textview_cancel_up);
|
||||
break;
|
||||
case "finish":
|
||||
view.setText(R.string.libao_finish);
|
||||
view.setBackgroundResource(R.drawable.textview_cancel_up);
|
||||
break;
|
||||
case "linged":
|
||||
view.setText(R.string.libao_linged);
|
||||
view.setBackgroundResource(R.drawable.libao_linged_style);
|
||||
view.setTextColor(ContextCompat.getColorStateList(view.getContext(), R.color.libao_linged_selector));
|
||||
break;
|
||||
case "taoed":
|
||||
view.setText(R.string.libao_taoed);
|
||||
view.setBackgroundResource(R.drawable.libao_taoed_style);
|
||||
view.setTextColor(ContextCompat.getColorStateList(view.getContext(), R.color.libao_taoed_selector));
|
||||
break;
|
||||
case "copy":
|
||||
view.setText(R.string.libao_copy);
|
||||
view.setBackgroundResource(R.drawable.textview_blue_style);
|
||||
break;
|
||||
case "repeatLing":
|
||||
view.setText(R.string.libao_repeat_ling);
|
||||
view.setBackgroundResource(R.drawable.textview_cancel_up);
|
||||
break;
|
||||
case "repeatLinged":
|
||||
view.setText(R.string.libao_repeat_ling);
|
||||
view.setBackgroundResource(R.drawable.textview_green_style);
|
||||
break;
|
||||
case "repeatTao":
|
||||
view.setText(R.string.libao_repeat_tao);
|
||||
view.setBackgroundResource(R.drawable.textview_cancel_up);
|
||||
break;
|
||||
case "repeatTaoed":
|
||||
view.setText(R.string.libao_repeat_tao);
|
||||
view.setBackgroundResource(R.drawable.textview_orange_style);
|
||||
break;
|
||||
case "unshelve":
|
||||
view.setBackgroundResource(R.drawable.textview_cancel_style);
|
||||
view.setText(R.string.libao_unshelve);
|
||||
break;
|
||||
default:
|
||||
view.setBackgroundResource(R.drawable.textview_cancel_style);
|
||||
view.setText("异常");
|
||||
}
|
||||
}
|
||||
|
||||
// 大图下的进度条
|
||||
@BindingAdapter({"downloadButton", "traceEvent", "clickCallBack", "entrance", "location"})
|
||||
public static void setDownloadButton(DownloadProgressBar progressBar,
|
||||
GameEntity gameEntity,
|
||||
ExposureEvent traceEvent,
|
||||
@Nullable View.OnClickListener clickCallBack,
|
||||
@Nullable String entrance,
|
||||
@Nullable String location) {
|
||||
|
||||
// 判断是否显示按钮
|
||||
if (gameEntity != null
|
||||
&& Config.isShowDownload(gameEntity.getId())
|
||||
&& !"光环助手".equals(gameEntity.getName())) {
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
|
||||
// 点击事件
|
||||
progressBar.setOnClickListener(v -> {
|
||||
if (clickCallBack != null) clickCallBack.onClick(v);
|
||||
switch (progressBar.getDownloadType()) {
|
||||
case DOWNLOADING_PLUGIN:
|
||||
case DOWNLOADING_NORMAL:
|
||||
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);
|
||||
DownloadDialogHelper.findAvailableDialogAndShow(
|
||||
v.getContext(),
|
||||
gameEntity,
|
||||
apk,
|
||||
() -> {
|
||||
DialogUtils.checkDownload(v.getContext(), apk.getSize(),
|
||||
isSubscribe -> download(progressBar, gameEntity, traceEvent, isSubscribe, entrance, location));
|
||||
});
|
||||
} else {
|
||||
DownloadDialog.getInstance(v.getContext()).showPopupWindow(v, gameEntity,
|
||||
entrance, location + gameEntity.getName(), traceEvent);
|
||||
}
|
||||
break;
|
||||
case LAUNCH_OR_OPEN:
|
||||
if (gameEntity.getApk().size() == 1) {
|
||||
DataUtils.onGameLaunchEvent(v.getContext(), gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), location);
|
||||
PackageUtils.launchApplicationByPackageName(v.getContext(), gameEntity.getApk().get(0).getPackageName());
|
||||
} else {
|
||||
DownloadDialog.getInstance(v.getContext()).showPopupWindow(v, gameEntity,
|
||||
entrance, location + gameEntity.getName(), traceEvent);
|
||||
}
|
||||
break;
|
||||
case INSTALL_PLUGIN:
|
||||
case INSTALL_NORMAL:
|
||||
if (gameEntity.getApk().size() == 1) {
|
||||
DownloadEntity downloadEntity = DownloadManager.getInstance(progressBar.getContext()).getDownloadEntityByUrl(gameEntity.getApk().get(0).getUrl());
|
||||
if (downloadEntity != null) {
|
||||
PackageUtils.launchSetup(v.getContext(), downloadEntity);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case RESERVABLE:
|
||||
CheckLoginUtils.checkLogin(progressBar.getContext(), "", () -> {
|
||||
PermissionHelper.checkReadPhoneStatePermissionBeforeAction(progressBar.getContext(), () -> {
|
||||
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(gameEntity, () -> {
|
||||
LogUtils.logReservation(gameEntity, traceEvent);
|
||||
updateReservation(progressBar, gameEntity);
|
||||
});
|
||||
dialogFragment.show(((AppCompatActivity) progressBar.getContext()).getSupportFragmentManager(), "reserve");
|
||||
});
|
||||
});
|
||||
break;
|
||||
case RESERVED:
|
||||
if ("download".equals(gameEntity.getReserveStatus())) {
|
||||
ReservationHelper.showDeleteReservationDialog(progressBar.getContext(), () -> {
|
||||
ReservationHelper.deleteReservation(gameEntity, () -> {
|
||||
updateReservation(progressBar, gameEntity);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
ReservationHelper.showCancelReservationDialog(progressBar.getContext(), () -> {
|
||||
ReservationHelper.cancelReservation(gameEntity, () -> {
|
||||
updateReservation(progressBar, gameEntity);
|
||||
});
|
||||
});
|
||||
}
|
||||
break;
|
||||
case H5_GAME:
|
||||
MtaHelper.onEvent("H5页面", "入口", "列表页_" + gameEntity.getName());
|
||||
LinkEntity linkEntity = gameEntity.getH5Link();
|
||||
Intent i = new Intent(WebActivity.getIntentForWebGame(progressBar.getContext(), linkEntity.getLink(), gameEntity.getName(), "play".equals(linkEntity.getType())));
|
||||
progressBar.getContext().startActivity(i);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// 显示预约
|
||||
if (gameEntity.isReservable()) {
|
||||
if (!ReservationRepository.thisGameHasBeenReserved(gameEntity.getId())) {
|
||||
progressBar.setText("预约");
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.RESERVABLE);
|
||||
} else {
|
||||
progressBar.setText("已预约");
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.RESERVED);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 显示下载按钮状态
|
||||
if (gameEntity.getApk().isEmpty() || gameEntity.getDownloadOffStatus() != null) {
|
||||
LinkEntity h5LinkEntity = gameEntity.getH5Link();
|
||||
String offStatus = gameEntity.getDownloadOffStatus();
|
||||
if (h5LinkEntity != null) {
|
||||
if ("play".equals(h5LinkEntity.getType())) {
|
||||
progressBar.setText("开始玩");
|
||||
} else {
|
||||
progressBar.setText("查看");
|
||||
}
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.H5_GAME);
|
||||
} else {
|
||||
if (offStatus != null && "dialog".equals(offStatus)) {
|
||||
progressBar.setText("查看");
|
||||
} else {
|
||||
progressBar.setText("暂无");
|
||||
}
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.NONE);
|
||||
}
|
||||
|
||||
} else {
|
||||
String status = GameUtils.getDownloadBtnText(progressBar.getContext(), gameEntity, PluginLocation.only_game);
|
||||
switch (status) {
|
||||
case "插件化":
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.PLUGIN);
|
||||
break;
|
||||
case "打开":
|
||||
case "启动":
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.LAUNCH_OR_OPEN);
|
||||
break;
|
||||
default:
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.NORMAL);
|
||||
break;
|
||||
}
|
||||
progressBar.setText(status);
|
||||
}
|
||||
|
||||
// 显示下载过程状态
|
||||
if (gameEntity.getApk().size() == 1) {
|
||||
DownloadEntity downloadEntity = DownloadManager.getInstance(progressBar.getContext()).getDownloadEntityByUrl(gameEntity.getApk().get(0).getUrl());
|
||||
if (downloadEntity != null) {
|
||||
progressBar.setProgress((int) (downloadEntity.getPercent() * 10));
|
||||
switch (downloadEntity.getStatus()) {
|
||||
case downloading:
|
||||
case pause:
|
||||
case timeout:
|
||||
case neterror:
|
||||
case waiting:
|
||||
progressBar.setText(R.string.downloading);
|
||||
if (downloadEntity.isPluggable() && PackagesManager.INSTANCE.isInstalled(downloadEntity.getPackageName())) {
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.DOWNLOADING_PLUGIN);
|
||||
} else {
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.DOWNLOADING_NORMAL);
|
||||
}
|
||||
break;
|
||||
case done:
|
||||
progressBar.setText(R.string.install);
|
||||
if (downloadEntity.isPluggable()
|
||||
&& PackagesManager.INSTANCE.isInstalled(downloadEntity.getPackageName())) {
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.INSTALL_PLUGIN);
|
||||
} else {
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.INSTALL_NORMAL);
|
||||
}
|
||||
break;
|
||||
case cancel:
|
||||
case hijack:
|
||||
case notfound:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void updateReservation(DownloadProgressBar progressBar, GameEntity gameEntity) {
|
||||
// 显示预约
|
||||
if (gameEntity.isReservable()) {
|
||||
if (!ReservationRepository.thisGameHasBeenReserved(gameEntity.getId())) {
|
||||
progressBar.setText("预约");
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.RESERVABLE);
|
||||
} else {
|
||||
progressBar.setText("已预约");
|
||||
progressBar.setDownloadType(DownloadProgressBar.DownloadType.RESERVED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 开始下载
|
||||
private static void download(DownloadProgressBar progressBar,
|
||||
GameEntity gameEntity,
|
||||
ExposureEvent traceEvent,
|
||||
boolean isSubscribe,
|
||||
String entrance,
|
||||
String location) {
|
||||
String str = progressBar.getText();
|
||||
String method;
|
||||
if (str.contains("更新")) {
|
||||
method = "更新";
|
||||
} else if (str.contains("插件化")) {
|
||||
method = "插件化";
|
||||
} else {
|
||||
method = progressBar.getContext().getString(R.string.download);
|
||||
}
|
||||
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);
|
||||
|
||||
ExposureUtils.DownloadType downloadType = ExposureUtils.getDownloadType(apkEntity, method);
|
||||
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, apkEntity.getPlatform(), traceEvent, downloadType);
|
||||
|
||||
DownloadManager.createDownload(progressBar.getContext(),
|
||||
apkEntity,
|
||||
gameEntity,
|
||||
method,
|
||||
entrance,
|
||||
location + gameEntity.getName(),
|
||||
isSubscribe,
|
||||
downloadExposureEvent);
|
||||
|
||||
progressBar.setProgress(0);
|
||||
progressBar.setDownloadType("插件化".equals(method) ?
|
||||
DownloadProgressBar.DownloadType.DOWNLOADING_PLUGIN : DownloadProgressBar.DownloadType.DOWNLOADING_NORMAL);
|
||||
} else {
|
||||
Utils.toast(progressBar.getContext(), msg);
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter({"gameLabelList", "subjectTag"})
|
||||
public static void setGameLabelList(LinearLayout layout, GameEntity gameEntity, String subjectTag) {
|
||||
if (gameEntity == null) return;
|
||||
if (gameEntity.getTest() != null) {
|
||||
layout.removeAllViews();
|
||||
View testView = LayoutInflater.from(layout.getContext()).inflate(R.layout.game_test_label, null);
|
||||
TextView testType = testView.findViewById(R.id.test_type);
|
||||
TextView testTime = testView.findViewById(R.id.test_time);
|
||||
testType.setText(gameEntity.getTest().getType());
|
||||
testType.setBackgroundColor(ContextCompat.getColor(layout.getContext(), R.color.tag_yellow));
|
||||
|
||||
if (gameEntity.getTest().getStart() == 0) {
|
||||
testTime.setVisibility(View.GONE);
|
||||
} else {
|
||||
testTime.setText(GameViewUtils.getGameTestDate(gameEntity.getTest().getStart()));
|
||||
}
|
||||
layout.addView(testView);
|
||||
} else {
|
||||
GameViewUtils.setLabelList(layout.getContext(), layout, gameEntity.getTag(), subjectTag, gameEntity.getTagStyle());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@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"})
|
||||
public static void setGameName(TextView view, GameEntity game, boolean isShowPlatform) {
|
||||
if (isShowPlatform && game.getApk().size() > 0) {
|
||||
view.setText(String.format("%s - %s", game.getName(),
|
||||
PlatformUtils.getInstance(view.getContext()).getPlatformName(
|
||||
game.getApk().get(0).getPlatform())));
|
||||
} else {
|
||||
view.setText(game.getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@BindingAdapter({"setCommunityImage", "setCommunityVideoImage"})
|
||||
public static void setCommunityImage(SimpleDraweeView imageView, List<String> images, List<CommunityVideoEntity> videos) {
|
||||
if (videos.size() > 0) {
|
||||
CommunityVideoEntity videoEntity = videos.get(0);
|
||||
ImageUtils.display(imageView, videoEntity.getPoster());
|
||||
imageView.setVisibility(View.VISIBLE);
|
||||
} else if (images.size() > 0) {
|
||||
imageView.setVisibility(View.VISIBLE);
|
||||
ImageUtils.display(imageView, images.get(0));
|
||||
} else {
|
||||
imageView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@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.setText(videoEntity.getDuration());
|
||||
mVideoDuration.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mVideoDuration.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter({"setGameTags", "setMaxGameTags"})
|
||||
public static void setGameTags(TextView view, List<TagStyleEntity> tags, int maxTags) {
|
||||
if (tags == null) {
|
||||
view.setText("");
|
||||
return;
|
||||
}
|
||||
|
||||
int showCount = tags.size() > maxTags ? maxTags : tags.size(); // 最多显示3个
|
||||
|
||||
StringBuilder content = new StringBuilder();
|
||||
for (int i = 0; i < showCount; i++) {
|
||||
TagStyleEntity tag = tags.get(i);
|
||||
content.append(tag.getName());
|
||||
if (i != showCount - 1) content.append("/");
|
||||
}
|
||||
|
||||
Spannable span = new SpannableString(content);
|
||||
int index = 0;
|
||||
for (int i = 0; i < showCount; i++) {
|
||||
TagStyleEntity tag = tags.get(i);
|
||||
int start = index;
|
||||
int end = start + tag.getName().length() + ((i != showCount - 1) ? 1 : 0);
|
||||
index = end;
|
||||
span.setSpan(new ForegroundColorSpan(Color.parseColor("#" + tag.getColor())),
|
||||
start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
view.setText(span);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
package com.gh.common.dialog
|
||||
|
||||
import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.view.KeyEvent
|
||||
import android.view.View
|
||||
import com.gh.common.util.MtaHelper
|
||||
import com.lightgame.dialog.BaseDialogFragment
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
/**
|
||||
* 对 dialog 操作进行 MTA 事件记录的 dialog fragment
|
||||
*/
|
||||
abstract class BaseTrackableDialogFragment : BaseDialogFragment() {
|
||||
|
||||
abstract fun getEvent(): String
|
||||
abstract fun getKey(): String
|
||||
|
||||
// 区分此 dialog 是点击 dialog 外部取消的还是点击返回取消的
|
||||
private val mIsCanceledByClickOutsideOfDialog = AtomicBoolean(true)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
if (getEvent().isEmpty()) {
|
||||
throw IllegalStateException("需要提供非空的 Event 来供 MTA 进行事件记录")
|
||||
}
|
||||
|
||||
if (getKey().isEmpty()) {
|
||||
throw IllegalStateException("需要提供非空的 Key 来供 MTA 进行事件记录")
|
||||
}
|
||||
|
||||
onEvent("出现弹窗")
|
||||
|
||||
dialog?.setCanceledOnTouchOutside(true)
|
||||
dialog?.setOnKeyListener { _, keyCode, event ->
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP) {
|
||||
mIsCanceledByClickOutsideOfDialog.set(false)
|
||||
onEvent("点击返回")
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun onEvent(value: String) {
|
||||
if (trackWithBasicDeviceInfo()) {
|
||||
MtaHelper.onEventWithBasicDeviceInfo(getEvent(), getKey(), value)
|
||||
} else {
|
||||
MtaHelper.onEvent(getEvent(), getKey(), value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCancel(dialog: DialogInterface) {
|
||||
super.onCancel(dialog)
|
||||
if (mIsCanceledByClickOutsideOfDialog.get()) {
|
||||
onEvent("点击空白")
|
||||
}
|
||||
}
|
||||
|
||||
open fun trackWithBasicDeviceInfo() = false
|
||||
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
package com.gh.common.dialog
|
||||
|
||||
import android.graphics.Paint
|
||||
import android.os.Bundle
|
||||
import android.util.TypedValue
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.text.HtmlCompat
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.DisplayUtils
|
||||
import com.gh.common.util.MtaHelper
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import kotlinx.android.synthetic.main.dialog_game_off_service.*
|
||||
|
||||
// 游戏关闭下载弹窗
|
||||
class GameOffServiceDialogFragment : BaseTrackableDialogFragment() {
|
||||
private var mDialog: GameEntity.Dialog? = null
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.dialog_game_off_service, null)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
mDialog?.run {
|
||||
titleTv.text = title
|
||||
contentTv.text = HtmlCompat.fromHtml(content, HtmlCompat.FROM_HTML_MODE_LEGACY)
|
||||
|
||||
for (site in sites) {
|
||||
val siteTv = TextView(context)
|
||||
siteTv.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply {
|
||||
topMargin = DisplayUtils.dip2px(12f)
|
||||
}
|
||||
siteTv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14f)
|
||||
siteTv.setTextColor(ContextCompat.getColor(requireContext(), R.color.theme))
|
||||
siteTv.text = site.text
|
||||
siteTv.paintFlags = siteTv.paintFlags or Paint.UNDERLINE_TEXT_FLAG
|
||||
siteTv.setOnClickListener {
|
||||
MtaHelper.onEvent("游戏下载状态按钮", getKey(), site.text)
|
||||
DirectUtils.directToWebView(requireContext(), site.url, "(关闭下载弹窗)")
|
||||
dismiss()
|
||||
}
|
||||
|
||||
container.addView(siteTv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getEvent(): String {
|
||||
return "游戏下载状态按钮"
|
||||
}
|
||||
|
||||
override fun getKey(): String {
|
||||
return "查看详情弹窗"
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(dialog: GameEntity.Dialog) = GameOffServiceDialogFragment().apply {
|
||||
mDialog = dialog
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,90 @@
|
||||
package com.gh.common.dialog
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import android.util.TypedValue
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import com.gh.common.util.DisplayUtils
|
||||
import com.gh.common.util.MtaHelper
|
||||
import com.gh.common.util.PermissionHelper
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.NotificationHint
|
||||
import kotlinx.android.synthetic.main.dialog_notification_hint.*
|
||||
|
||||
// 通知权限弹窗
|
||||
class NotificationHintDialogFragment : BaseTrackableDialogFragment() {
|
||||
|
||||
private var mNotificationHint: NotificationHint? = 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)
|
||||
|
||||
titleTv.text = mNotificationHint?.title
|
||||
|
||||
contentContainer.removeAllViews()
|
||||
for (item in mNotificationHint?.content!!) {
|
||||
val tv = TextView(context)
|
||||
|
||||
tv.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT).apply {
|
||||
topMargin = if (contentContainer.childCount == 0) 0 else DisplayUtils.dip2px(12f)
|
||||
}
|
||||
tv.text = item
|
||||
tv.setTextColor(Color.parseColor("#1383EB"))
|
||||
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14f)
|
||||
contentContainer.addView(tv)
|
||||
}
|
||||
|
||||
activateTv.setOnClickListener {
|
||||
MtaHelper.onEventWithBasicDeviceInfo(getEvent(), getKey(), "点击立即开启")
|
||||
dismiss()
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
laterTv.setOnClickListener {
|
||||
dismiss()
|
||||
MtaHelper.onEventWithBasicDeviceInfo(getEvent(), getKey(), "点击以后再说")
|
||||
}
|
||||
|
||||
dialog?.setCanceledOnTouchOutside(true)
|
||||
}
|
||||
|
||||
override fun getEvent(): String {
|
||||
return "推送引导弹窗"
|
||||
}
|
||||
|
||||
override fun getKey(): String {
|
||||
return "引导弹窗"
|
||||
}
|
||||
|
||||
override fun trackWithBasicDeviceInfo() = true
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(hint: NotificationHint) = NotificationHintDialogFragment().apply {
|
||||
mNotificationHint = hint
|
||||
}
|
||||
}
|
||||
}
|
||||
198
app/src/main/java/com/gh/common/dialog/ReserveDialogFragment.kt
Normal file
198
app/src/main/java/com/gh/common/dialog/ReserveDialogFragment.kt
Normal file
@ -0,0 +1,198 @@
|
||||
package com.gh.common.dialog
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import android.os.Bundle
|
||||
import android.text.Html
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import android.widget.TextView
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import butterknife.OnClick
|
||||
import com.gh.common.constant.Config
|
||||
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.manager.UserManager
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.lightgame.utils.Utils
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.ResponseBody
|
||||
import org.json.JSONObject
|
||||
|
||||
// 预约弹窗
|
||||
class ReserveDialogFragment : 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
|
||||
|
||||
private lateinit var mViewModel: ReserveViewModel
|
||||
|
||||
private var mSuccessCallback: SuccessCallback? = null
|
||||
|
||||
private var mGameId: String = ""
|
||||
private var mGameName: String = ""
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
mViewModel = viewModelProvider()
|
||||
}
|
||||
|
||||
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='#ff4147'>免费</font>收到短信提醒"
|
||||
|
||||
reserveContentTv.text = Html.fromHtml(reserveContent)
|
||||
mobileEt.setText(UserManager.getInstance().userInfoEntity.mobile)
|
||||
mobileEt.setSelection(mobileEt.text.length)
|
||||
|
||||
mViewModel.reservation.observeNonNull(this) {
|
||||
if (it.success) {
|
||||
showSuccessDialog(it.withMobile, it.boundWechat)
|
||||
mSuccessCallback?.onSuccess()
|
||||
}
|
||||
}
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.reserve_with_mobile_btn,
|
||||
R.id.reserve_without_mobile_btn,
|
||||
R.id.close_btn,
|
||||
R.id.customizable_btn)
|
||||
fun onClick(view: View) {
|
||||
when (view.id) {
|
||||
R.id.reserve_without_mobile_btn -> {
|
||||
MtaHelper.onEvent("预约游戏", "预约功能操作", "点击无手机号预约")
|
||||
mViewModel.reserve(gameId = mGameId, gameName = mGameName)
|
||||
}
|
||||
|
||||
R.id.reserve_with_mobile_btn -> {
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(gameEntity: GameEntity, successCallback: SuccessCallback) = ReserveDialogFragment().apply {
|
||||
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>()
|
||||
|
||||
@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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
class Reservation(var success: Boolean = false, var withMobile: Boolean = false, var boundWechat: Boolean = false)
|
||||
}
|
||||
47
app/src/main/java/com/gh/common/dialog/TrackableDialog.kt
Normal file
47
app/src/main/java/com/gh/common/dialog/TrackableDialog.kt
Normal file
@ -0,0 +1,47 @@
|
||||
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 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 ?: "点击空白")
|
||||
}
|
||||
}
|
||||
|
||||
setOnKeyListener { _, keyCode, event ->
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP) {
|
||||
mIsCanceledByClickOutsideOfDialog.set(false)
|
||||
MtaHelper.onEvent(mEvent, mKey, mKeyBackValue ?: "点击返回")
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun show() {
|
||||
super.show()
|
||||
if (mLogShowEvent) {
|
||||
MtaHelper.onEvent(mEvent, mKey, "出现弹窗")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
23
app/src/main/java/com/gh/common/exposure/ExposureDatabase.kt
Normal file
23
app/src/main/java/com/gh/common/exposure/ExposureDatabase.kt
Normal file
@ -0,0 +1,23 @@
|
||||
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
|
||||
}
|
||||
18
app/src/main/java/com/gh/common/exposure/ExposureEntity.kt
Normal file
18
app/src/main/java/com/gh/common/exposure/ExposureEntity.kt
Normal file
@ -0,0 +1,18 @@
|
||||
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 sequence: Int? = 0,
|
||||
val platform: String? = "",
|
||||
val downloadType: String? = "",
|
||||
val downloadCompleteType: String? = ""
|
||||
) : Parcelable
|
||||
41
app/src/main/java/com/gh/common/exposure/ExposureEvent.kt
Normal file
41
app/src/main/java/com/gh/common/exposure/ExposureEvent.kt
Normal file
@ -0,0 +1,41 @@
|
||||
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.exposure.meta.Meta
|
||||
import com.gh.common.exposure.meta.MetaUtil
|
||||
import com.gh.common.exposure.time.TimeUtil
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import java.util.*
|
||||
|
||||
@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 {
|
||||
@JvmStatic
|
||||
fun createEvent(gameEntity: GameEntity?, source: List<ExposureSource>, eTrace: List<ExposureEvent>? = null, event: ExposureType = ExposureType.EXPOSURE): ExposureEvent {
|
||||
return ExposureEvent(
|
||||
payload = ExposureEntity(gameId = gameEntity?.id,
|
||||
gameName = gameEntity?.name,
|
||||
sequence = gameEntity?.sequence,
|
||||
platform = gameEntity?.platform,
|
||||
downloadType = gameEntity?.downloadType,
|
||||
downloadCompleteType = gameEntity?.downloadCompleteType),
|
||||
source = source,
|
||||
eTrace = eTrace,
|
||||
event = event).apply { gameEntity?.exposureEvent = this }
|
||||
}
|
||||
}
|
||||
}
|
||||
18
app/src/main/java/com/gh/common/exposure/ExposureEventDao.kt
Normal file
18
app/src/main/java/com/gh/common/exposure/ExposureEventDao.kt
Normal file
@ -0,0 +1,18 @@
|
||||
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>)
|
||||
}
|
||||
66
app/src/main/java/com/gh/common/exposure/ExposureListener.kt
Normal file
66
app/src/main/java/com/gh/common/exposure/ExposureListener.kt
Normal file
@ -0,0 +1,66 @@
|
||||
package com.gh.common.exposure
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.reactivex.functions.Consumer
|
||||
|
||||
/**
|
||||
* Exposure Event Listener for RecyclerView
|
||||
*/
|
||||
class ExposureListener(var fragment: Fragment, var exposable: IExposable) : RecyclerView.OnScrollListener() {
|
||||
|
||||
var throttleBus: ExposureThrottleBus? = null
|
||||
var layoutManager: LinearLayoutManager? = null
|
||||
var visibleState: ExposureThrottleBus.VisibleState? = null
|
||||
|
||||
init {
|
||||
fragment.fragmentManager?.registerFragmentLifecycleCallbacks(
|
||||
object : FragmentManager.FragmentLifecycleCallbacks() {
|
||||
override fun onFragmentResumed(fm: FragmentManager, f: Fragment) {
|
||||
throttleBus = ExposureThrottleBus(Consumer { commitExposure(it) }, Consumer(Throwable::printStackTrace))
|
||||
}
|
||||
|
||||
override fun onFragmentPaused(fm: FragmentManager, f: Fragment) {
|
||||
visibleState?.let { commitExposure(it) }
|
||||
throttleBus?.clear()
|
||||
}
|
||||
}, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Monitor items in display when scrolling, record those newly displayed as well as
|
||||
* those newly disappeared. And finally trigger commitExposure().
|
||||
*/
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
|
||||
if (layoutManager == null) layoutManager = recyclerView.layoutManager as LinearLayoutManager
|
||||
|
||||
layoutManager?.run {
|
||||
visibleState = ExposureThrottleBus.VisibleState(findFirstCompletelyVisibleItemPosition(), findLastCompletelyVisibleItemPosition())
|
||||
throttleBus?.postVisibleState(visibleState!!)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Just commit the exposureEvent that is stored in listItem.
|
||||
*/
|
||||
private fun commitExposure(visibleState: ExposureThrottleBus.VisibleState) {
|
||||
|
||||
val eventList = arrayListOf<ExposureEvent>()
|
||||
|
||||
for (pos in visibleState.firstCompletelyVisible..visibleState.lastCompletelyVisible) {
|
||||
try {
|
||||
exposable.getEventByPosition(pos)?.let { eventList.add(it) }
|
||||
exposable.getEventListByPosition(pos)?.let { eventList.addAll(it) }
|
||||
} catch (ignore: Exception) {
|
||||
// Just ignore the error.
|
||||
}
|
||||
}
|
||||
|
||||
ExposureManager.log(eventList)
|
||||
}
|
||||
|
||||
}
|
||||
160
app/src/main/java/com/gh/common/exposure/ExposureManager.kt
Normal file
160
app/src/main/java/com/gh/common/exposure/ExposureManager.kt
Normal file
@ -0,0 +1,160 @@
|
||||
package com.gh.common.exposure
|
||||
|
||||
import com.aliyun.sls.android.sdk.model.LogGroup
|
||||
import com.gh.common.exposure.time.TimeUtil
|
||||
import com.gh.common.util.toJson
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.loghub.LgLOG
|
||||
import com.gh.loghub.LoghubHelper
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.concurrent.fixedRateTimer
|
||||
|
||||
/**
|
||||
* A handful tool for committing logs to aliyun loghub.
|
||||
*
|
||||
* 如何简单地统计列表中每个 item 的曝光事件?
|
||||
*
|
||||
* 1. Adapter 实现 IExposable 接口,在 BindView 阶段更新 ExposureEvent,ExposureEvent 供 getEventByPosition(pos) 方法获取用
|
||||
* 2. 构建一个 ExposureListener 并作为入参添加至 recyclerview 的 Scroll 回调中
|
||||
* 3. 没了
|
||||
*/
|
||||
object ExposureManager {
|
||||
|
||||
private const val ENDPOINT = "cn-qingdao.log.aliyuncs.com"
|
||||
private const val PROJECT = "ghzs"
|
||||
private const val STORE_SIZE = 100
|
||||
private const val STORE_FORCE_UPLOAD_PERIOD = 300 * 1000L
|
||||
private const val LOG_STORE = BuildConfig.EXPOSURE_REPO
|
||||
|
||||
private val loghubHelper = LoghubHelper.getInstance()
|
||||
|
||||
// exposureCache 用来过滤掉具有相同 id 的曝光事件,避免重复发送事件
|
||||
private val exposureSet = hashSetOf<ExposureEvent>()
|
||||
private val exposureExecutor = Executors.newSingleThreadExecutor()
|
||||
private val exposureCache = FixedSizeLinkedHashSet<String>(300)
|
||||
private val exposureDao by lazy { ExposureDatabase.buildDatabase(HaloApp.getInstance().application).logHubEventDao() }
|
||||
|
||||
@JvmStatic
|
||||
fun init() {
|
||||
TimeUtil.init()
|
||||
|
||||
loghubHelper.init(HaloApp.getInstance().application, ENDPOINT, PROJECT, LOG_STORE) { TimeUtil.currentTimeMillis() }
|
||||
|
||||
exposureExecutor.execute {
|
||||
val eventList = exposureDao.getAll()
|
||||
exposureSet.addAll(eventList)
|
||||
}
|
||||
|
||||
fixedRateTimer(name = "ExposureManager-Store-Checker", initialDelay = 500, period = STORE_FORCE_UPLOAD_PERIOD) {
|
||||
commitSavedExposureEvents(true)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
}
|
||||
}
|
||||
commitSavedExposureEvents()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param forced Ignore all restrictions.
|
||||
*/
|
||||
fun commitSavedExposureEvents(forced: Boolean = false) {
|
||||
exposureExecutor.execute {
|
||||
if (exposureSet.size < STORE_SIZE && !forced || exposureSet.size == 0) return@execute
|
||||
|
||||
val exposureList = exposureSet.toList()
|
||||
// uploadLogGroup 是一个异步方法,LoghubHelper 里面实现了重传功能,所以这里交给它就好了
|
||||
loghubHelper.uploadLogGroup(buildLogGroup(exposureList))
|
||||
|
||||
Utils.log("Exposure", "提交了${exposureList.size}条曝光记录")
|
||||
exposureSet.removeAll(exposureList)
|
||||
exposureDao.deleteMany(exposureList)
|
||||
}
|
||||
}
|
||||
|
||||
private fun eliminateMultipleBrackets(jsonWithMultipleBracket: String): String {
|
||||
return jsonWithMultipleBracket.replace("[[", "[").replace("]]", "]")
|
||||
}
|
||||
|
||||
private fun buildLogGroup(eventList: List<ExposureEvent>): LogGroup {
|
||||
val logGroup = LogGroup("sls android", "no ip")
|
||||
|
||||
eventList.forEach { logGroup.PutLog(buildLog(it)) }
|
||||
|
||||
return logGroup
|
||||
}
|
||||
|
||||
private fun buildLog(event: ExposureEvent): LgLOG {
|
||||
val log = LgLOG(TimeUtil.currentTime())
|
||||
|
||||
log.PutContent("id", event.id)
|
||||
log.PutContent("payload", event.payload.toJson())
|
||||
log.PutContent("event", event.event.toString())
|
||||
log.PutContent("source", eliminateMultipleBrackets(event.source.toJson()))
|
||||
log.PutContent("meta", event.meta.toJson())
|
||||
log.PutContent("e-traces", if (event.eTrace != null) {
|
||||
eliminateMultipleBrackets(event.eTrace?.toJson() ?: "")
|
||||
} else "")
|
||||
log.PutTime(event.time)
|
||||
|
||||
return log
|
||||
}
|
||||
|
||||
internal 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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package com.gh.common.exposure
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.annotation.Keep
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
|
||||
@Keep
|
||||
@Parcelize
|
||||
data class ExposureSource(var k: String, var v: String = ""): Parcelable
|
||||
@ -0,0 +1,59 @@
|
||||
package com.gh.common.exposure
|
||||
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.functions.Consumer
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import io.reactivex.subjects.PublishSubject
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class ExposureThrottleBus(var onSuccess: Consumer<VisibleState>, var onError: Consumer<Throwable>) {
|
||||
|
||||
companion object {
|
||||
private const val THRESHOLD_TIME = 300L
|
||||
}
|
||||
|
||||
private val mPublishSubject: PublishSubject<VisibleState> = PublishSubject.create()
|
||||
private val mCompositeDisposable: CompositeDisposable = CompositeDisposable()
|
||||
|
||||
init {
|
||||
|
||||
/**
|
||||
* Since onScroll() callback will be triggered multiple times for every swipe, we use
|
||||
* distinctUntilChanged() to prevent committing the same visibleState event and
|
||||
* 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)
|
||||
mCompositeDisposable.add(disposable)
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
mCompositeDisposable.clear()
|
||||
}
|
||||
|
||||
fun postVisibleState(visibleState: VisibleState) {
|
||||
mPublishSubject.onNext(visibleState)
|
||||
}
|
||||
|
||||
class VisibleState(val firstCompletelyVisible: Int, val lastCompletelyVisible: Int) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || javaClass != other.javaClass) return false
|
||||
|
||||
val that = other as VisibleState
|
||||
|
||||
if (firstCompletelyVisible != that.firstCompletelyVisible) return false
|
||||
|
||||
return lastCompletelyVisible == that.lastCompletelyVisible
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = firstCompletelyVisible
|
||||
result = 31 * result + lastCompletelyVisible
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package com.gh.common.exposure
|
||||
|
||||
object ExposureTraceUtils {
|
||||
|
||||
fun appendTrace(event: ExposureEvent?): List<ExposureEvent> {
|
||||
val traceList = arrayListOf<ExposureEvent>()
|
||||
|
||||
event?.let {
|
||||
if (event.eTrace == null) {
|
||||
traceList.add(event)
|
||||
} else {
|
||||
traceList.addAll(event.eTrace!!)
|
||||
traceList.add(flattenTrace(event))
|
||||
}
|
||||
}
|
||||
|
||||
return traceList
|
||||
}
|
||||
|
||||
private fun flattenTrace(event: ExposureEvent): ExposureEvent {
|
||||
event.eTrace = arrayListOf()
|
||||
return event
|
||||
}
|
||||
|
||||
}
|
||||
11
app/src/main/java/com/gh/common/exposure/ExposureType.kt
Normal file
11
app/src/main/java/com/gh/common/exposure/ExposureType.kt
Normal file
@ -0,0 +1,11 @@
|
||||
package com.gh.common.exposure
|
||||
|
||||
enum class ExposureType {
|
||||
EXPOSURE,
|
||||
|
||||
CLICK,
|
||||
|
||||
DOWNLOAD,
|
||||
|
||||
DOWNLOAD_COMPLETE
|
||||
}
|
||||
78
app/src/main/java/com/gh/common/exposure/ExposureUtils.kt
Normal file
78
app/src/main/java/com/gh/common/exposure/ExposureUtils.kt
Normal file
@ -0,0 +1,78 @@
|
||||
package com.gh.common.exposure
|
||||
|
||||
import com.gh.common.util.PackageUtils
|
||||
import com.gh.common.util.toObject
|
||||
import com.gh.gamecenter.entity.ApkEntity
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.halo.assistant.HaloApp
|
||||
import java.util.*
|
||||
|
||||
object ExposureUtils {
|
||||
|
||||
@JvmStatic
|
||||
fun logADownloadExposureEvent(entity: GameEntity,
|
||||
platform: String?,
|
||||
traceEvent: ExposureEvent?,
|
||||
downloadType: DownloadType): ExposureEvent {
|
||||
val gameEntity = entity.clone()
|
||||
gameEntity.platform = platform
|
||||
gameEntity.downloadType = downloadType.toString()
|
||||
val exposureEvent = ExposureEvent.createEvent(gameEntity = gameEntity,
|
||||
source = traceEvent?.source ?: ArrayList(),
|
||||
eTrace = ExposureTraceUtils.appendTrace(traceEvent),
|
||||
event = ExposureType.DOWNLOAD)
|
||||
ExposureManager.log(exposureEvent)
|
||||
return exposureEvent
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun logADownloadCompleteExposureEvent(entity: GameEntity,
|
||||
platform: String?,
|
||||
trace: String?,
|
||||
downloadType: DownloadType) {
|
||||
val gameEntity = entity.clone()
|
||||
gameEntity.platform = platform
|
||||
gameEntity.downloadCompleteType = downloadType.toString()
|
||||
val traceEvent = trace?.toObject<ExposureEvent>()
|
||||
val exposureEvent = ExposureEvent.createEvent(gameEntity = gameEntity,
|
||||
source = traceEvent?.source ?: ArrayList(),
|
||||
eTrace = ExposureTraceUtils.appendTrace(traceEvent),
|
||||
event = ExposureType.DOWNLOAD_COMPLETE)
|
||||
ExposureManager.log(exposureEvent)
|
||||
ExposureManager.commitSavedExposureEvents(forced = true)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getDownloadType(apkEntity: ApkEntity, method: String) : DownloadType {
|
||||
return if ("更新" == method) {
|
||||
if (PackageUtils.isSignature(HaloApp.getInstance().application, apkEntity.packageName)) {
|
||||
DownloadType.PLUGIN_UPDATE
|
||||
} else {
|
||||
DownloadType.UPDATE
|
||||
}
|
||||
} else if ("插件化" == method) {
|
||||
DownloadType.PLUGIN_DOWNLOAD
|
||||
} else {
|
||||
DownloadType.DOWNLOAD
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getUpdateType(apkEntity: ApkEntity) : DownloadType {
|
||||
return if (PackageUtils.isSignature(HaloApp.getInstance().application, apkEntity.packageName)) {
|
||||
DownloadType.PLUGIN_UPDATE
|
||||
} else {
|
||||
DownloadType.UPDATE
|
||||
}
|
||||
}
|
||||
|
||||
enum class DownloadType {
|
||||
DOWNLOAD,
|
||||
|
||||
UPDATE,
|
||||
|
||||
PLUGIN_UPDATE,
|
||||
|
||||
PLUGIN_DOWNLOAD
|
||||
}
|
||||
}
|
||||
11
app/src/main/java/com/gh/common/exposure/IExposable.kt
Normal file
11
app/src/main/java/com/gh/common/exposure/IExposable.kt
Normal file
@ -0,0 +1,11 @@
|
||||
package com.gh.common.exposure
|
||||
|
||||
/**
|
||||
* 统计曝光的列表的 adapter 需要实现这个接口
|
||||
*/
|
||||
interface IExposable {
|
||||
fun getEventByPosition(pos: Int): ExposureEvent?
|
||||
|
||||
// 部分列表的 item 内嵌套了 recyclerview 这里获取这个 item 所携带的所有事件
|
||||
fun getEventListByPosition(pos: Int): List<ExposureEvent>?
|
||||
}
|
||||
26
app/src/main/java/com/gh/common/exposure/meta/Meta.kt
Normal file
26
app/src/main/java/com/gh/common/exposure/meta/Meta.kt
Normal file
@ -0,0 +1,26 @@
|
||||
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 imei: String? = "",
|
||||
val model: String? = "",
|
||||
val manufacturer: String? = "",
|
||||
val android_id: 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
|
||||
178
app/src/main/java/com/gh/common/exposure/meta/MetaUtil.kt
Normal file
178
app/src/main/java/com/gh/common/exposure/meta/MetaUtil.kt
Normal file
@ -0,0 +1,178 @@
|
||||
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.net.wifi.WifiManager
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import android.telephony.TelephonyManager
|
||||
import android.text.TextUtils
|
||||
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
|
||||
import java.io.File
|
||||
|
||||
object MetaUtil {
|
||||
|
||||
private val application: Application = HaloApp.getInstance().application
|
||||
private var channel = ""
|
||||
|
||||
private var m: Meta? = null
|
||||
|
||||
fun refreshMeta() {
|
||||
m = Meta(mac = getMac(),
|
||||
imei = getIMEI(),
|
||||
model = getModel(),
|
||||
manufacturer = getManufacturer(),
|
||||
android_id = getAndroidId(),
|
||||
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 = RomIdentifier.getRom().name + "" + RomIdentifier.getRom().versionName)
|
||||
}
|
||||
|
||||
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 MAC address
|
||||
* TODO check > 6.0 results
|
||||
*/
|
||||
fun getMac(): String? {
|
||||
|
||||
var mac: String = ""
|
||||
|
||||
//Plan A
|
||||
try {
|
||||
mac = File("/sys/class/net/wlan0/address").inputStream().bufferedReader().use { it.readText() }
|
||||
if (!TextUtils.isEmpty(mac)) return mac.trim()
|
||||
} catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
}
|
||||
|
||||
// Plan B
|
||||
try {
|
||||
mac = File("/sys/class/net/eth0/address").inputStream().bufferedReader().use { it.readText() }
|
||||
if (!TextUtils.isEmpty(mac)) return mac.trim()
|
||||
} catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
}
|
||||
|
||||
// Plan C
|
||||
val wifiManager = application.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
||||
try {
|
||||
mac = wifiManager.connectionInfo.macAddress
|
||||
} catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
}
|
||||
|
||||
return mac.trim()
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get IMEI
|
||||
*/
|
||||
fun getIMEI(): String? {
|
||||
|
||||
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 >= 26) {
|
||||
return telephonyManager.imei
|
||||
}
|
||||
|
||||
return telephonyManager.getDeviceId()
|
||||
|
||||
}
|
||||
|
||||
fun getModel(): String? {
|
||||
return Build.MODEL
|
||||
}
|
||||
|
||||
fun getManufacturer(): String? {
|
||||
return Build.MANUFACTURER
|
||||
}
|
||||
|
||||
fun getAndroidId(): String? {
|
||||
var android_id: String = ""
|
||||
try {
|
||||
android_id = Settings.Secure.getString(application.contentResolver, Settings.Secure.ANDROID_ID)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return 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"
|
||||
}
|
||||
}
|
||||
30
app/src/main/java/com/gh/common/exposure/time/Corrector.kt
Normal file
30
app/src/main/java/com/gh/common/exposure/time/Corrector.kt
Normal file
@ -0,0 +1,30 @@
|
||||
package com.gh.common.exposure.time
|
||||
|
||||
import com.gh.gamecenter.entity.TimeEntity
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlin.concurrent.fixedRateTimer
|
||||
|
||||
class Corrector {
|
||||
|
||||
companion object {
|
||||
const val TIME_CORRECTOR_ADJUST_PERIOD: Long = 600000
|
||||
}
|
||||
|
||||
var delta: Long = 0
|
||||
|
||||
init {
|
||||
fixedRateTimer("TimeUtil-Corrector-Checker", initialDelay = 0, period = TIME_CORRECTOR_ADJUST_PERIOD) {
|
||||
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 { delta = it * 1000 - System.currentTimeMillis() }
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
23
app/src/main/java/com/gh/common/exposure/time/TimeUtil.kt
Normal file
23
app/src/main/java/com/gh/common/exposure/time/TimeUtil.kt
Normal file
@ -0,0 +1,23 @@
|
||||
package com.gh.common.exposure.time
|
||||
|
||||
object TimeUtil {
|
||||
|
||||
private lateinit var corrector: Corrector
|
||||
|
||||
fun init() {
|
||||
corrector = Corrector()
|
||||
}
|
||||
|
||||
fun currentTimeMillis(): Long {
|
||||
return corrector.delta + System.currentTimeMillis()
|
||||
}
|
||||
|
||||
fun currentTime(): Int {
|
||||
return if (::corrector.isInitialized) {
|
||||
((corrector.delta + System.currentTimeMillis()) / 1000).toInt()
|
||||
} else {
|
||||
(System.currentTimeMillis() / 1000).toInt()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
66
app/src/main/java/com/gh/common/history/HistoryDatabase.kt
Normal file
66
app/src/main/java/com/gh/common/history/HistoryDatabase.kt
Normal file
@ -0,0 +1,66 @@
|
||||
package com.gh.common.history
|
||||
|
||||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.TypeConverters
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import com.gh.gamecenter.entity.HistoryGameEntity
|
||||
import com.gh.gamecenter.entity.MyVideoEntity
|
||||
import com.gh.gamecenter.entity.NewsEntity
|
||||
import com.gh.gamecenter.qa.entity.AnswerEntity
|
||||
import com.gh.gamecenter.qa.entity.ArticleEntity
|
||||
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 = 5, exportSchema = false)
|
||||
@TypeConverters(CountConverter::class,
|
||||
CommunityConverter::class,
|
||||
TimeConverter::class,
|
||||
AnswerUserConverter::class,
|
||||
ThumbnailConverter::class,
|
||||
TagStyleListConverter::class,
|
||||
StringArrayListConverter::class,
|
||||
CommunityVideoConverter::class)
|
||||
|
||||
abstract class HistoryDatabase : RoomDatabase() {
|
||||
|
||||
abstract fun answerDao(): AnswerHistoryDao
|
||||
abstract fun articleDao(): ArticleHistoryDao
|
||||
abstract fun newsDao(): NewsHistoryDao
|
||||
abstract fun gameDao(): GameDao
|
||||
abstract fun videoHistoryDao(): VideoHistoryDao
|
||||
|
||||
companion object {
|
||||
|
||||
val MIGRATION_2_3: Migration = object : Migration(2, 3) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("Alter TABLE HistoryGameEntity add isLibaoExist INTEGER NOT NULL DEFAULT 0")
|
||||
}
|
||||
}
|
||||
|
||||
val MIGRATION_3_4: Migration = object : Migration(3, 4) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("Alter TABLE AnswerEntity add videos TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE ArticleEntity add videos TEXT NOT NULL DEFAULT ''")
|
||||
}
|
||||
}
|
||||
|
||||
val MIGRATION_4_5: Migration = object : Migration(4, 5) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("CREATE TABLE MyVideoEntity(id TEXT NOT NULL PRIMARY KEY,poster TEXT NOT NULL DEFAULT '',url TEXT NOT NULL DEFAULT '',vote INTEGER NOT NULL DEFAULT 0,length INTEGER NOT NULL DEFAULT 0,time INTEGER NOT NULL DEFAULT 0,videoStreamRecord INTEGER NOT NULL DEFAULT 0,status TEXT NOT NULL 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)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user