Compare commits
603 Commits
Author | SHA1 | Date |
---|---|---|
Thomas | e19526dbf6 | |
Thomas | f6192881d3 | |
Thomas | 309c6aa890 | |
Thomas | 9f6ac90074 | |
Thomas | 8d4418bf2b | |
Thomas | 3d85e74957 | |
Thomas | fda17ee8fe | |
Thomas | 5696809c1d | |
Thomas | e03147c6da | |
Thomas | 7c695f5f82 | |
Thomas | 1c6f7858ca | |
Thomas | 1ef0389997 | |
Thomas | 1c54d44a22 | |
Thomas | 724b43ca4d | |
Thomas | ed3d978b03 | |
Thomas | af53071b08 | |
Thomas | bd8e2a50d9 | |
Thomas | e5c918af51 | |
Thomas | 4077c5bc55 | |
Thomas | 2b43f32772 | |
Thomas | 1e0eafef9b | |
Thomas | 45b35d0718 | |
Thomas | a9286ab150 | |
Thomas | fcb1974e78 | |
Thomas | 2456e8f782 | |
Thomas | ce4913452b | |
Thomas | e605dd8417 | |
Thomas | 8434f9ee00 | |
Thomas | 61bb7d962d | |
Thomas | 35aec32070 | |
Thomas | 274bcc8be7 | |
Thomas | ce70df5137 | |
Thomas | d9dca3ef23 | |
Thomas | e3635c3f01 | |
Thomas | 2cdabbcb70 | |
Thomas | d5ad9b181b | |
Thomas | 540fb3e2dc | |
Thomas | edbe65593b | |
Thomas | d5f394dfea | |
Thomas | d5a5fdf52e | |
Thomas | a7f9256947 | |
Thomas | d769729901 | |
Thomas | b2026c8784 | |
Thomas | b29de141ef | |
Thomas | 6d4772da75 | |
Thomas | 2344fe0942 | |
Thomas | 7c309b68b8 | |
Thomas | c8c5e56a17 | |
Thomas | cef227ba42 | |
Thomas | 02296b038a | |
Thomas | b76a4cfcf5 | |
Thomas | f168f101bc | |
Thomas | 2e8a86fe20 | |
Thomas | fe0d2fe726 | |
Thomas | 9b322cc922 | |
Thomas | 346656e53d | |
Thomas | 6e6187175a | |
Thomas | 5e832fa046 | |
Thomas | 34007d4507 | |
Thomas | fd400f025e | |
Thomas | f3f474ee13 | |
Thomas | d971032d52 | |
Thomas | 961c77103e | |
Thomas | b22b21c47a | |
Thomas | 6d70bd758a | |
Thomas | 087ac92f15 | |
Thomas | 99fe789f30 | |
Thomas | 10892f92f1 | |
Thomas | 0a919c85ab | |
Thomas | 761abc013f | |
Thomas | 327f6f0e8d | |
Thomas | d6f1a360d2 | |
Thomas | 24ec69d7f7 | |
Thomas | c80692bd34 | |
Thomas | b5e9f70be6 | |
Thomas | d446081331 | |
Thomas | 8178cff72c | |
Thomas | 950d99b5de | |
Thomas | b7855cb1a2 | |
Thomas | b298fbfa3e | |
Thomas | d83929f80a | |
Thomas | b932ed2c13 | |
Thomas | 36073d340d | |
Thomas | 0e14540b69 | |
Thomas | 57327a8ad0 | |
Thomas | bbfa278d6b | |
Thomas | 439decf6a9 | |
Thomas | 2277cc5f05 | |
Thomas | 4204ffccee | |
Thomas | 31407e709d | |
Thomas | 44d26bb1cf | |
Thomas | 8a8a433023 | |
Thomas | 5c27292543 | |
Thomas | e475348d39 | |
Thomas | 9f8358e471 | |
Thomas | 4fd8d42d85 | |
Thomas | 498990c48a | |
Thomas | 1cddf26c9a | |
Thomas | 325a239b86 | |
Thomas | 2c4ef9c3ce | |
Thomas | 4dbd191c4f | |
Thomas | 01e489da10 | |
Thomas | 53a7062c6d | |
Thomas | 3425e1e593 | |
Thomas | 9970635ff8 | |
Thomas | c1f174a5b8 | |
Thomas | 3587e7c524 | |
Thomas | 3911ad15a6 | |
Thomas | d40b35da59 | |
Thomas | ccb6e184cc | |
Thomas | 74e45b1820 | |
Thomas | 0a1336f0e0 | |
Thomas | d5a0dcb980 | |
Thomas | 83e7c41ca0 | |
Thomas | 1d1b0c11a9 | |
Thomas | 3b2c4e2ac6 | |
Thomas | 2d77fe580f | |
Thomas | 7ae20f43f8 | |
Thomas | f03c1b206b | |
Thomas | d99a58f2cf | |
Thomas | 5aeaf7f34b | |
Thomas | af0b484d16 | |
Thomas | 0a6791b752 | |
Thomas | e73e306d05 | |
Thomas | 52189abbff | |
Thomas | d721f12d74 | |
Thomas | 69f28bb647 | |
Thomas | 2b2295d831 | |
Thomas | 179586b8c4 | |
Thomas | 1afad9e06a | |
Thomas | 59c73fd864 | |
Thomas | 6820344750 | |
Thomas | 680504791c | |
Thomas | 41e500a8f8 | |
Thomas | 448af1ef9a | |
Thomas | 041e8c0bd6 | |
Thomas | 0b7300e93a | |
Thomas | 94c5f5a705 | |
Thomas | fa2f8a7b05 | |
Thomas | aeb288142e | |
Thomas | 635c43f458 | |
Thomas | d36138431b | |
Thomas | 9cdf857730 | |
Thomas | 52a6152af6 | |
Thomas | 9d3312c081 | |
Thomas | 1146236f46 | |
Thomas | ec19ee1e55 | |
Thomas | cc37e40158 | |
Thomas | bdd12de34d | |
Thomas | e64692d0d3 | |
Thomas | 7da8c0f664 | |
Thomas | fc41c077dc | |
Thomas | 50800da4b9 | |
Thomas | a9219e8a91 | |
Thomas | 5eedadef47 | |
Thomas | 14cde8e625 | |
Thomas | 1f2ecd591d | |
Thomas | 9a2eb6cd49 | |
Thomas | aa38514bcb | |
Thomas | f2fddfb16c | |
Thomas | 05300682c1 | |
Thomas | a3714a4ecf | |
Thomas | 500584b9ef | |
Thomas | 33ac822957 | |
Thomas | 1f6107e238 | |
Thomas | 2b7639599c | |
Thomas | dedf7b0163 | |
Thomas | 88b5a83fb1 | |
Thomas | efd6b0088f | |
Thomas | ccb5cd20b1 | |
Thomas | 668e41bc9b | |
Thomas | 46123fa7d6 | |
Thomas | b079965de8 | |
Thomas | 842ab914a4 | |
Thomas | fcb93b7dc6 | |
Thomas | f1420fe29e | |
Thomas | 23f8674adc | |
Thomas | 76a4aa5ae6 | |
Thomas | 85ffb4064b | |
Thomas | 73c9e639b6 | |
Thomas | 5172695784 | |
Thomas | fcc10f97b5 | |
Thomas | 0a12020fd8 | |
Thomas | e9c10b17e0 | |
Thomas | f4698f1312 | |
Thomas | 1690507a18 | |
Thomas | fbeb87e29e | |
Thomas | de14e95e90 | |
Thomas | 35c5713b0a | |
Thomas | 413792087e | |
Thomas | 21c53d2b4d | |
Thomas | 5757a8b1d8 | |
Thomas | 680bdf7bd2 | |
Thomas | 6911fbd124 | |
Thomas | 9fdffc9709 | |
Thomas | 0b722a5ecc | |
Thomas | 6ae42ffefe | |
Thomas | 3a8c82ce63 | |
Thomas | 04c2b277ce | |
Thomas | 962462ff84 | |
Thomas | 964b0f2690 | |
Thomas | 4b25b61680 | |
Thomas | 61c3735e57 | |
Thomas | b0e29c0ba4 | |
Thomas | e7f55aace9 | |
Thomas | 2955206b07 | |
Thomas | b59d97279d | |
Thomas | 7d9e299940 | |
Thomas | e15252a0f8 | |
Thomas | e0907f1dc8 | |
Thomas | 1107391c43 | |
Thomas | 2500035c33 | |
Thomas | 24ad4dbc0f | |
Thomas | 550394a5e4 | |
Thomas | 720c13fa2d | |
Thomas | a02b8b79c1 | |
Thomas | c2f99e130d | |
Thomas | 250aa03e9a | |
Thomas | dd7d253a1b | |
Thomas | f2b46fffe0 | |
Thomas | 60630cc4ea | |
Thomas | 85164c18e9 | |
Thomas | 3634e5e232 | |
Thomas | f7d44cb547 | |
Thomas | 85b89507db | |
Thomas | 7415b752cc | |
Thomas | 0a52060223 | |
Thomas | 1024b1e6f9 | |
Thomas | 23fc061711 | |
Thomas | bfa3ede06b | |
Thomas | c7f6cdc8c6 | |
Thomas | 58f280d347 | |
Thomas | 0715824ae1 | |
Thomas | 5540c8cacc | |
Thomas | 14efbdd08f | |
Thomas | 7ceb04d548 | |
Thomas | e9608f63db | |
Thomas | 64e1c7ca81 | |
Thomas | 7823b30900 | |
Thomas | 1e45e4454c | |
Thomas | 1dd3a193c5 | |
Thomas | 30416837a9 | |
Thomas | 363132d331 | |
Thomas | ebc0d744ed | |
Thomas | d685031ee8 | |
Thomas | 3ea012f62e | |
Thomas | 9a06f5660b | |
Thomas | dff76aada1 | |
Thomas | 50a9f8a1b0 | |
Thomas | 8ff3b81112 | |
Thomas | 38f73a5d60 | |
Thomas | 15f6835a0c | |
Thomas | 84e3264726 | |
Thomas | dbd068d95f | |
Thomas | acba219e44 | |
Thomas | c8e7c23855 | |
Thomas | f0ff8a6feb | |
Thomas | 91a1380fef | |
Thomas | 3351ef7d91 | |
Thomas | 564cda58a5 | |
Thomas | 3233fe673d | |
Thomas | 8cc8b284ce | |
Thomas | 3ecdedc17c | |
Thomas | 8f361c605a | |
Thomas | 9d599e8b57 | |
Thomas | 9c676d8002 | |
Thomas | d3ffc32d9b | |
Thomas | 8c95554d8e | |
Thomas | 3ed5248c2a | |
Thomas | 32990932ad | |
Thomas | 6d0a47903c | |
Thomas | 05eaa196b4 | |
Thomas | 2cd076bfb8 | |
Thomas | 02cd267cae | |
Thomas | 21394cb585 | |
Thomas | 73cd48b94a | |
Thomas | ea2cf58e5f | |
Thomas | 2f3e29b037 | |
Thomas | 33d597c2c0 | |
Thomas | 66afb3f4ee | |
Thomas | dad94d753d | |
Thomas | 1727bebf58 | |
Thomas | 37576c69ce | |
Thomas | b8f83a7227 | |
Thomas | 3a14abaf2e | |
Thomas | 0e03a55aef | |
Thomas | 931fb30330 | |
Thomas | b893dc9c4f | |
Thomas | f6ddd99449 | |
Thomas | ddcbbfe670 | |
Thomas | 0f7438fa54 | |
Thomas | fbbab1db68 | |
Thomas | 15725dceb0 | |
Thomas | 1bcbcec8b8 | |
Thomas | c3e475be6f | |
Thomas | 150a81adc6 | |
Thomas | a984607ee8 | |
Thomas | 2bf929986e | |
Thomas | 860edec2e6 | |
Thomas | 90cfcbb7ae | |
Thomas | c63048730f | |
Thomas | 55bbafdbb5 | |
Thomas | 0923a07e42 | |
Thomas | 431c21e066 | |
Thomas | 17c84f6c37 | |
Thomas | 58f10d9372 | |
Thomas | a6dfd842e3 | |
Thomas | dfdda7627f | |
Thomas | 1711826c43 | |
Thomas | 4627de23b4 | |
Thomas | 023ab2d4b2 | |
Thomas | 2a375318ea | |
Thomas | fee593d059 | |
Thomas | fe3546e282 | |
Thomas | b61b6868a6 | |
Thomas | 2f8ecd1f3e | |
Thomas | 8a9ead3f0d | |
Thomas | 43e2762d4d | |
Thomas | 8ab237a957 | |
Thomas | ffa5d0883a | |
Thomas | 14f0a47f52 | |
Thomas | 4c1e466866 | |
Thomas | 24c6f79b51 | |
Thomas | 8c958a2563 | |
Thomas | 02cc00780d | |
Thomas | d13cce3997 | |
Thomas | 985835429b | |
Thomas | 00751cedab | |
Thomas | c4e85a7161 | |
Thomas | 253b61fb11 | |
Thomas | 54ffbe2e15 | |
Thomas | 86d9ba930c | |
Thomas | fb96efc8cf | |
Thomas | aaac1652e9 | |
Thomas | c8fc98ee71 | |
Thomas | 4457259dfd | |
Thomas | 6dbb11f6e9 | |
Thomas | 08a4b4b49a | |
Thomas | 4afd2ca341 | |
Thomas | 0c048877e0 | |
Thomas | 825a74de4a | |
Thomas | 79ca0ceb88 | |
Thomas | a5ccc9bf6f | |
Thomas | 685467266a | |
Thomas | 599e53b10c | |
Thomas | 029b8b57ae | |
Thomas | 631264eb57 | |
Thomas | e7eef5b760 | |
Thomas | 59741e5979 | |
Thomas | 0f38ad180a | |
Thomas | fdc6e6e325 | |
Thomas | ed9e79496a | |
Thomas | 4f909417f1 | |
Thomas | aecb4034ad | |
Thomas | f0335d96d2 | |
Thomas | 65f3886355 | |
Thomas | 8e2f1fb8fe | |
Thomas | 852cfee310 | |
Thomas | 6620a12957 | |
Thomas | 11e8135cbd | |
Thomas | 824c4e0cbb | |
Thomas | 9af7934448 | |
Thomas | 4ffa027e8d | |
Thomas | 7e8ab3359a | |
Thomas | 8e72655731 | |
Thomas | 5c098857bd | |
Thomas | 7fece740af | |
Thomas | 857ab65f93 | |
Thomas | 807655da5b | |
Thomas | a77f37e564 | |
Thomas | 1194209c82 | |
Thomas | f31b6e9ac8 | |
Thomas | 3353b7205b | |
Thomas | 0f995cc615 | |
Thomas | 7be0f72292 | |
Thomas | ffbe8877a8 | |
Thomas | 74feb7e8f0 | |
Thomas | cbaef4bcfe | |
Thomas | 38a387a423 | |
Thomas | 1092eefc76 | |
Thomas | 3615b43b97 | |
Thomas | e17c7fb01d | |
Thomas | f3d69e19a0 | |
Thomas | ea102eb485 | |
Thomas | 2e4c01ed62 | |
Thomas | ed22892d10 | |
Thomas | 017bd5a6a2 | |
Thomas | 967f11ddb4 | |
Thomas | 6b4abd019e | |
Thomas | 8b66c4030f | |
Thomas | 34f058358e | |
Thomas | 2bab907777 | |
Thomas | 52e64b6d85 | |
Thomas | 9510678a9f | |
Thomas | b4e7c3f8e2 | |
Thomas | d800d2b10c | |
Thomas | 785b4949e6 | |
Thomas | b79e17cb60 | |
Thomas | 19fcbeb4b9 | |
Thomas | ffb355d1a2 | |
Thomas | 43fd2945cc | |
Thomas | d93c74a449 | |
Thomas | 7a197993c9 | |
Thomas | dc2a252dd5 | |
Thomas | 2c33f7a7f8 | |
Thomas | 24a8a0dc00 | |
Thomas | b78894b33c | |
Thomas | 2d33d7f970 | |
Thomas | 8823eb74ba | |
Thomas | 7f77b86272 | |
Thomas | 2f773b2f0f | |
Thomas | ca69a6e86d | |
Thomas | 3e5cefbf24 | |
Thomas | 245ef64ebe | |
Thomas | a0ff454dd9 | |
Thomas | fa6b1560f8 | |
Thomas | 518b5f617b | |
Thomas | 7c4ce7701c | |
Thomas | 0b6557f9c5 | |
Thomas | a8e00d137a | |
Thomas | 75d3f74e48 | |
Thomas | 3866317597 | |
Thomas | 10e904fe4a | |
Thomas | be655f6c2b | |
Thomas | 676e540059 | |
Thomas | 87763a050c | |
Thomas | ab45c1f80c | |
Thomas | ec5f2c7c45 | |
Thomas | c4448f22b9 | |
Thomas | 62af5c54aa | |
Thomas | 5872f5c99f | |
Thomas | 2b1a63e08b | |
Thomas | 7b96cf32b3 | |
Thomas | 6108bd143c | |
Thomas | 0127b9bffa | |
Thomas | 8dddfc5497 | |
Thomas | bf119a5808 | |
Thomas | 89ade69c5f | |
Thomas | 93eaec8544 | |
Thomas | ce984de339 | |
Thomas | b089ae93e1 | |
Thomas | fc95708a84 | |
Thomas | 7262690999 | |
Thomas | f818c74943 | |
Thomas | d7c5a04965 | |
Thomas | 257a00fa1e | |
Thomas | 23875a2ceb | |
Thomas | 3f1883fbbc | |
Thomas | c5269a3129 | |
Thomas | 056092ac71 | |
Thomas | fd7632f001 | |
Thomas | fb83a1927d | |
Thomas | 641a616c96 | |
Thomas | fc051d8d1d | |
Thomas | b8bec4f357 | |
Thomas | fe78c8bf7e | |
Thomas | 42caaa9dc9 | |
Thomas | 74d6cb8041 | |
Thomas | 7678da2bb6 | |
Thomas | e771153f35 | |
Thomas | e96b9f7f02 | |
Thomas | 0604ac9ba8 | |
Thomas | bd0c59a69e | |
Thomas | 0a84b75518 | |
Thomas | c4b49b58cf | |
Thomas | afbb27896e | |
Thomas | e0ff6c0ac3 | |
Thomas | 4d7c7e88bb | |
Thomas | 7eef023277 | |
Thomas | 6a762a8fd6 | |
Thomas | 752e3d50c1 | |
Thomas | 8377f9bb8a | |
Thomas | 5ff06a29d2 | |
Thomas | 50aeb075b1 | |
Thomas | 79ff617d67 | |
Thomas | 5de8524f2a | |
Thomas | 6164ff9163 | |
Thomas | 6e8b304b63 | |
Thomas | 3be0cd727f | |
Thomas | 451dd53230 | |
Thomas | 34c1222fbc | |
Thomas | ccf2fc877b | |
Thomas | 10a496c299 | |
Thomas | ba1bfd1f9c | |
Thomas | b9622da6c6 | |
Thomas | b3e9100c2f | |
Thomas | fb0e87397d | |
Thomas | bed1bb634b | |
Thomas | 4db288743e | |
Thomas | ba569b2d40 | |
Thomas | c774dcee96 | |
Thomas | 48fe22c8db | |
Thomas | 3f282c8116 | |
Thomas | 4f4cdd68b5 | |
Thomas | 9c350c922b | |
Thomas | 8548777c50 | |
Thomas | 30d344987c | |
Thomas | 80c8e1a356 | |
Thomas | 8ce7eb386f | |
Thomas | c50a587250 | |
Thomas | a8b17ce0b2 | |
Thomas | 731863ef6c | |
Thomas | 04b8294022 | |
Thomas | 4937ff43e5 | |
Thomas | 1670867a1d | |
Thomas | 5e947cd221 | |
Thomas | 1f8c5cbc05 | |
Thomas | c2ab7a3608 | |
Thomas | d62ff6d18f | |
Thomas | 92a0af8b36 | |
Thomas | 34ed36f9ae | |
Thomas | 7777317eb8 | |
Thomas | 4d53612adc | |
Thomas | e08d9805f1 | |
Thomas | cb5b7274fe | |
Thomas | db84cac8f0 | |
Thomas | b6769ca25f | |
Thomas | 70903578d1 | |
Thomas | 07d8a39681 | |
Thomas | 7410467cd6 | |
Thomas | f21732f753 | |
Thomas | 9dca5fcd3b | |
Thomas | 1bc99b3c46 | |
Thomas | a8a5028852 | |
Thomas | f5fa9944ad | |
Thomas | 3697917d2b | |
Thomas | 9f25405983 | |
Thomas | 9c476037ef | |
Thomas | 2044a85b58 | |
Thomas | d878ac780c | |
Thomas | 55179c6955 | |
Thomas | 618384cccb | |
Thomas | 0b84823f64 | |
Thomas | 9361f6ca64 | |
Thomas | b81257c77c | |
Thomas | 75e919adbc | |
Thomas | d946451b27 | |
Thomas | 2d960d4c55 | |
Thomas | 6f24030b86 | |
Thomas | ce7b0d4d7d | |
Thomas | ed34917550 | |
Thomas | 18bd328814 | |
Thomas | cf35a65edd | |
Thomas | fe04f32aa1 | |
Thomas | 36f5f73a47 | |
Thomas | cd5e23364d | |
Thomas | 8bd4a3f5d1 | |
Thomas | 4114e4c349 | |
Thomas | 3993e4a67e | |
Thomas | c78af3ea1a | |
Thomas | 132687366c | |
Thomas | 667469c773 | |
Thomas | e78e7a6f97 | |
Thomas | a1790bf32d | |
Thomas | 7a8e2f32b4 | |
Thomas | 1932913793 | |
Thomas | 7c40060438 | |
Thomas | 0c6c5c813f | |
Thomas | 786b80e25e | |
Thomas | 4cc0729d77 | |
Thomas | 9f444d6d88 | |
Thomas | 700fe6c9e8 | |
Thomas | 3c2b8cc699 | |
Thomas | eef6b3d76c | |
Thomas | 0a7fab6883 | |
Thomas | 1f7fe1fc6f | |
Thomas | 5bb395f2d3 | |
Thomas | 4d6cb47e6c | |
Thomas | f7f85a9dbb | |
Thomas | 118c2175f5 | |
Thomas | 645c9fa240 | |
Thomas | 13baaccd81 | |
Thomas | aaa8281da8 | |
Thomas | 8bcc7e8f58 | |
Thomas | 8085ed6a95 | |
Thomas | 12d24f4a56 | |
Thomas | fcf2fbdd86 | |
Thomas | 81a711ee4c | |
Thomas | b68cb689ca | |
Thomas | b2f1bf2817 | |
Thomas | 7aab6fbba9 | |
Thomas | 015a2f3289 | |
Thomas | 647c827ee4 | |
Thomas | e503a5ec95 | |
Thomas | 11209a5334 | |
Thomas | b23686ab64 | |
Thomas | 7f4c6faa1d | |
Thomas | 33c7f12180 | |
Thomas | 106bacb4b1 | |
Thomas | d6c662434d | |
Thomas | 3705657aec | |
Thomas | ea810fd61b | |
Thomas | 2d32aa9a9b | |
Thomas | e672b207b6 | |
Thomas | 68dfb1b980 | |
Thomas | 6feedf5c24 | |
Thomas | c196d3aebe | |
Thomas | a87ec4ffa5 | |
Thomas | 3e694b8ac2 | |
Thomas | 26af939014 | |
Thomas | f0eaceb8a4 | |
Thomas | 7827c97bf9 | |
Thomas | 88514c0669 |
|
@ -0,0 +1,10 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: tom79
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: tom79
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
|
@ -0,0 +1,17 @@
|
|||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 60
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 7
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- pinned
|
||||
- security
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: inactive
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
|
@ -8,3 +8,5 @@
|
|||
.externalNativeBuild
|
||||
.cxx
|
||||
/app/release/
|
||||
/app/fdroid_full/release/
|
||||
/frostwire-jlibtorrent/
|
||||
|
|
|
@ -51,23 +51,83 @@ before_script:
|
|||
- sdkmanager --sdk_root=${ANDROID_HOME} "build-tools;${ANDROID_BUILD_TOOLS}"
|
||||
|
||||
# Not necessary, but just for surity
|
||||
- chmod +x ./gradlew
|
||||
- chmod +x ./gradle
|
||||
|
||||
# Basic android and gradle stuff
|
||||
# Check linting
|
||||
lintDebug:
|
||||
interruptible: true
|
||||
stage: build
|
||||
script:
|
||||
- ./gradlew -Pci --console=plain :app:lintDebug -PbuildDir=lint
|
||||
stages:
|
||||
- build
|
||||
- build-and-test
|
||||
- tag
|
||||
|
||||
.no-upload: &no-upload
|
||||
stage: build-and-test
|
||||
retry: 2
|
||||
|
||||
# Make Project
|
||||
assembleDebug:
|
||||
<<: *no-upload
|
||||
cache:
|
||||
key: "${CI_COMMIT_TAG}"
|
||||
paths:
|
||||
- app/build/outputs/apk/fdroid_acad/debug/app-fdroid_acad-debug.apk
|
||||
- app/build/outputs/apk/fdroid_full/debug/app-fdroid_full-debug.apk
|
||||
policy: push
|
||||
script:
|
||||
- ./gradlew assembleDebug
|
||||
|
||||
# Basic android and gradle stuff
|
||||
# Check linting
|
||||
lintfdroid_acadDebug:
|
||||
interruptible: true
|
||||
stage: build
|
||||
script:
|
||||
- ./gradlew assembleDebug
|
||||
artifacts:
|
||||
paths:
|
||||
- app/build/outputs/
|
||||
- ./gradlew -Pci --console=plain :app:lintfdroid_acadDebug -PbuildDir=lint
|
||||
except:
|
||||
- tags
|
||||
|
||||
lintFdroid_fullDebug:
|
||||
interruptible: true
|
||||
stage: build
|
||||
script:
|
||||
- ./gradlew -Pci --console=plain :app:lintFdroid_fullDebug -PbuildDir=lint
|
||||
except:
|
||||
- tags
|
||||
|
||||
|
||||
## PROTECTED VARIABLES TO SET IN GITLAB:
|
||||
# - GITLAB_API_TOKEN: token you create on Gitlab
|
||||
# - NC_REMOTE_DIR: like https://YOUR_NEXTCLOUD/remote.php/dav/files/YOUR_USER/mastalab (no trailing slash)
|
||||
# - NC_SHARE_URL: share the folder in Nextcloud with public link and put your public link here (no trailing slash)
|
||||
# - NC_USER: nextcloud user
|
||||
# - NC_PASSWORD: nextcloud password
|
||||
## Protect all tags in Gitlab repo settings (do a wildcard, ie '*')
|
||||
# For now, it uses the assembleDebug builds, you'll need to create a job in build-and-test to create the apks, with only: - tags and add except: - tags to assembleDebug (like in debugTests)
|
||||
# In it, put something like this to get your signature key file:
|
||||
# - curl -s --output signature.jsk -u "${NC_USER}:${NC_PASSWORD}" "https://YOUR_NEXTCLOUD/remote.php/dav/files/YOUR_USER/signature.jsk"
|
||||
putApkOnTags:
|
||||
image: hatsoftwares/curl-jq:latest
|
||||
stage: tag
|
||||
retry: 2
|
||||
cache:
|
||||
key: "${CI_COMMIT_TAG}"
|
||||
paths:
|
||||
- app/build/outputs/apk/fdroid_acad/debug/app-fdroid_acad-debug.apk
|
||||
- app/build/outputs/apk/fdroid_full/debug/app-fdroid_full-debug.apk
|
||||
policy: pull
|
||||
script:
|
||||
- export PROJECT_API_URL="https://framagit.org/api/v4/projects/${CI_PROJECT_ID}"
|
||||
- export DESCRIPTION_URL="${PROJECT_API_URL}/repository/tags/${CI_COMMIT_TAG}"
|
||||
- export RELEASE_URL="${DESCRIPTION_URL}/release"
|
||||
- export NC_UPLOAD_URL="${NC_REMOTE_DIR}/${CI_COMMIT_TAG}"
|
||||
- export NC_DOWNLOAD_URL="${NC_SHARE_URL}/download?path=%2F${CI_COMMIT_TAG}%2F&files="
|
||||
- 'export HEADER="Private-Token: ${GITLAB_API_TOKEN}"'
|
||||
- export acadUrl="${NC_DOWNLOAD_URL}app-fdroid_acad-debug.apk"
|
||||
- export fullUrl="${NC_DOWNLOAD_URL}app-fdroid_full-debug.apk"
|
||||
- 'curl -s -u "${NC_USER}:${NC_PASSWORD}" -X MKCOL "${NC_UPLOAD_URL}"'
|
||||
- 'curl -s -u "${NC_USER}:${NC_PASSWORD}" -T app/build/outputs/apk/fdroid_full/debug/app-fdroid_full-debug.apk "${NC_UPLOAD_URL}/app-fdroid_full-debug.apk"'
|
||||
- 'curl -s -u "${NC_USER}:${NC_PASSWORD}" -T app/build/outputs/apk/fdroid_acad/debug/app-fdroid_acad-debug.apk "${NC_UPLOAD_URL}/app-fdroid_acad-debug.apk"'
|
||||
- export description=$(curl -s --header "${HEADER}" "${DESCRIPTION_URL}" | jq .release.description | sed -e 's@"@@g')
|
||||
- if [[ $description == 'null' ]]; then export METHOD="POST"; echo -e "[Get the acad version](${acadUrl})\n\n[Get the full version](${fullUrl})" > /tmp/text; fi
|
||||
- if [[ $description != 'null' ]]; then export METHOD="PUT"; echo -e "${description}\n\n[Get the acad version](${acadUrl})\n\n[Get the full version](${fullUrl})" > /tmp/text; fi
|
||||
- curl -s --request $METHOD --data-urlencode "description@/tmp/text" --header "${HEADER}" "${RELEASE_URL}"
|
||||
only:
|
||||
- tags
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
# 1.5.2
|
||||
|
||||
### Added:
|
||||
- Enable/disable auto playback
|
||||
- Enter in full-screen automatically (default disabled)
|
||||
- Back press pauses the video in full-screen
|
||||
|
||||
### Fixed:
|
||||
- Public timelines don't honor muted accounts
|
||||
- Comments are not removed when switching to a video without comments
|
||||
- Some other fixes
|
||||
|
||||
--------
|
||||
|
||||
# 1.5.1
|
||||
|
||||
- Fix some issues
|
||||
- New translations
|
||||
|
||||
--------
|
||||
|
||||
# 1.5.0
|
||||
|
||||
- Custom default instance depending of the country
|
||||
- Full managements of comments and their replies (read/post/delete)
|
||||
- Profile for accounts (displays their channels & videos)
|
||||
- Fix some issues when posting a comment
|
||||
- Fix videos not paused after screen lock
|
|
@ -0,0 +1,17 @@
|
|||
CONTRIBUTING
|
||||
============
|
||||
|
||||
### Localizations:
|
||||
|
||||
TubeLab works only with [Crowdin](https://crowdin.com/project/tubelab), which offers nice tools for helping in translations.
|
||||
New translations will be automatically merged in a branch.
|
||||
If your language is not listed, please ask me to add it. If you prefer to work on an XML file, you should be able [to upload it with Crowdin](https://support.crowdin.com/xml-configuration/).
|
||||
Crowdin will not pick up changes in develop branch, that's why all translations should be done with this tool.
|
||||
|
||||
### Issues:
|
||||
|
||||
Issues are handled on Framagit at: https://framagit.org/imattau/fedilab-tube/-/issues, before opening an issue, please check it has not yet been submitted by someone else
|
||||
|
||||
### Contribution to code:
|
||||
|
||||
Your contributions are welcomed, but please, use this repo https://framagit.org/tom79/fedilab-tube. You can create PR to the dev branch.
|
50
README.md
|
@ -1,6 +1,46 @@
|
|||
## TubeLab [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
|
||||
## TubeLab/TubeAcad [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
|
||||
|
||||
This project groups two different apps. **[TubeAcad](#TubeAcad)**, a Peertube Android app for French academic authorities. All is in French. Its use is limited to some instances.
|
||||
The other app is **[TubeLab](#TubeLab)** a Peertube Android app working for all instances.
|
||||
|
||||
|
||||
## <a name="TubeLab">TubeLab</a>
|
||||
|
||||
Tubelab is an Android app for Peertube (GNU GPLv3). <img src='https://img.shields.io/f-droid/v/app.fedilab.tubelab?include_prereleases' />
|
||||
|
||||
[<img alt='Get it on Google Play' src='./images/get-it-on-play.png' height="80"/>](https://play.google.com/store/apps/details?id=app.fedilab.tubelab)
|
||||
[<img alt='Get it on F-Droid' src='./images/get-it-on-fdroid.png' height="80"/>](https://f-droid.org/packages/app.fedilab.tubelab/)
|
||||
|
||||
### Not authenticated mode
|
||||
|
||||
It's a limited mode where you can do some actions:
|
||||
|
||||
- Switch instance
|
||||
- Share videos
|
||||
- Download videos
|
||||
|
||||
### Authenticated mode
|
||||
|
||||
Many features are available with this mode:
|
||||
|
||||
- Write/delete comments
|
||||
- Upload/remove/edit videos
|
||||
- Manage (create/edit/remove) channels and playlists
|
||||
- Follow/unfollow channels
|
||||
- Thumbs-up/down
|
||||
- Check notifications
|
||||
- Mute/unmute channels
|
||||
- Report videos/accounts
|
||||
- Check your history
|
||||
|
||||
## <a name="TubeAcad">TubeAcad</a>
|
||||
|
||||
TubeAcad est une application Android open source (GNU GPLv3) pour les instances Peertube académiques. L’authentification se fait par adresse mail, l’instance est automatiquement détectée. Il est également possible sur certaines instances de créer son compte depuis l’application.
|
||||
|
||||
|
||||
[<img alt='Get it on Google Play' src='./images/get-it-on-play.png' height="80"/>](https://play.google.com/store/apps/details?id=app.fedilab.fedilabtube)
|
||||
[<img alt='Get it on F-Droid' src='./images/get-it-on-fdroid.png' height="80"/>](https://f-droid.org/packages/app.fedilab.fedilabtube/)
|
||||
|
||||
TubeLab est une application Android open source (GNU GPLv3) pour les instances Peertube académiques. L’authentification se fait par adresse mail, l’instance est automatiquement détectée. Il est également possible sur certaines instances de créer son compte depuis l’application.
|
||||
|
||||
### Mode non authentifié
|
||||
|
||||
|
@ -28,9 +68,3 @@ Si vous connectez votre compte, vous pourrez interagir avec les vidéos :
|
|||
- Signaler des vidéos ou des comptes
|
||||
- Voir l'historique
|
||||
|
||||
|
||||
### Télécharger
|
||||
|
||||
[Fdroid](https://f-droid.org/packages/app.fedilab.fedilabtube/)
|
||||
|
||||
[GooglePlay](https://play.google.com/store/apps/details?id=app.fedilab.fedilabtube)
|
||||
|
|
193
app/build.gradle
|
@ -1,23 +1,24 @@
|
|||
apply plugin: 'com.android.application'
|
||||
|
||||
apply plugin: "androidx.navigation.safeargs"
|
||||
|
||||
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion "30.0.2"
|
||||
compileSdkVersion 31
|
||||
|
||||
defaultConfig {
|
||||
applicationId "app.fedilab.fedilabtube"
|
||||
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 30
|
||||
versionCode 7
|
||||
versionName "1.0.5"
|
||||
targetSdkVersion 31
|
||||
versionCode 45
|
||||
versionName "1.15.0"
|
||||
multiDexEnabled true
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
dexOptions {
|
||||
javaMaxHeapSize "4g"
|
||||
}
|
||||
flavorDimensions "default"
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
|
@ -28,6 +29,100 @@ android {
|
|||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
viewBinding true
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
disable 'MissingTranslation'
|
||||
checkReleaseBuilds false
|
||||
abortOnError false
|
||||
}
|
||||
//boolean full_instances if set to false means TubeAcad
|
||||
productFlavors {
|
||||
fdroid_acad {
|
||||
applicationId "app.fedilab.fedilabtube"
|
||||
resValue "string", "app_name", "TubeAcad"
|
||||
resValue "string", "app_id", "app.fedilab.fedilabtube"
|
||||
buildConfigField "String", "version", "\"fdroid_acad\""
|
||||
buildConfigField "boolean", "full_instances", "false"
|
||||
buildConfigField "boolean", "google_restriction", "false"
|
||||
buildConfigField "boolean", "surfing_mode", "false"
|
||||
buildConfigField "boolean", "sepia_search", "false"
|
||||
buildConfigField "boolean", "instance_switcher", "true"
|
||||
buildConfigField "boolean", "allow_remote_connections", "false"
|
||||
buildConfigField "boolean", "google_cast_lib", "false"
|
||||
buildConfigField "int", "cast_enabled", "0"
|
||||
buildConfigField "int", "default_theme", "2"
|
||||
}
|
||||
google_acad {
|
||||
applicationId "app.fedilab.fedilabtube"
|
||||
resValue "string", "app_name", "TubeAcad"
|
||||
resValue "string", "app_id", "app.fedilab.fedilabtube"
|
||||
buildConfigField "String", "version", "\"google_acad\""
|
||||
buildConfigField "boolean", "full_instances", "false"
|
||||
buildConfigField "boolean", "google_restriction", "true"
|
||||
buildConfigField "boolean", "surfing_mode", "false"
|
||||
buildConfigField "boolean", "sepia_search", "false"
|
||||
buildConfigField "boolean", "instance_switcher", "true"
|
||||
buildConfigField "boolean", "allow_remote_connections", "false"
|
||||
buildConfigField "boolean", "google_cast_lib", "true"
|
||||
buildConfigField "int", "cast_enabled", "1"
|
||||
buildConfigField "int", "default_theme", "2"
|
||||
}
|
||||
fdroid_full {
|
||||
applicationId "app.fedilab.tubelab"
|
||||
resValue "string", "app_name", "TubeLab"
|
||||
resValue "string", "app_id", "app.fedilab.tubelab"
|
||||
buildConfigField "String", "version", "\"fdroid_full\""
|
||||
buildConfigField "boolean", "full_instances", "true"
|
||||
buildConfigField "boolean", "google_restriction", "false"
|
||||
buildConfigField "boolean", "surfing_mode", "true"
|
||||
buildConfigField "boolean", "sepia_search", "true"
|
||||
buildConfigField "boolean", "instance_switcher", "true"
|
||||
buildConfigField "boolean", "allow_remote_connections", "true"
|
||||
buildConfigField "boolean", "google_cast_lib", "false"
|
||||
buildConfigField "int", "cast_enabled", "0"
|
||||
buildConfigField "int", "default_theme", "2"
|
||||
}
|
||||
google_full {
|
||||
applicationId "app.fedilab.tubelab"
|
||||
resValue "string", "app_name", "TubeLab"
|
||||
resValue "string", "app_id", "app.fedilab.tubelab"
|
||||
buildConfigField "String", "version", "\"google_full\""
|
||||
buildConfigField "boolean", "full_instances", "true"
|
||||
buildConfigField "boolean", "google_restriction", "true"
|
||||
buildConfigField "boolean", "surfing_mode", "true"
|
||||
buildConfigField "boolean", "sepia_search", "true"
|
||||
buildConfigField "boolean", "instance_switcher", "true"
|
||||
buildConfigField "boolean", "allow_remote_connections", "true"
|
||||
buildConfigField "boolean", "google_cast_lib", "true"
|
||||
buildConfigField "int", "cast_enabled", "1"
|
||||
buildConfigField "int", "default_theme", "2"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
|
||||
fdroid_acad {
|
||||
res.srcDirs = ['src/main/res', 'src/no_google_cast_lib/res', 'src/acad/res']
|
||||
java.srcDirs = ['src/main/java', 'src/acad/java', 'src/no_google_donation/java', 'src/no_google_cast_lib/java']
|
||||
}
|
||||
google_acad {
|
||||
res.srcDirs = ['src/main/res', 'src/google_cast_lib/res', 'src/acad/res']
|
||||
java.srcDirs = ['src/main/java', 'src/acad/java', 'src/no_google_donation/java', 'src/google_cast_lib/java']
|
||||
}
|
||||
fdroid_full {
|
||||
res.srcDirs = ['src/main/res', 'src/no_google_cast_lib/res', 'src/full/res']
|
||||
java.srcDirs = ['src/main/java', 'src/full/java', 'src/no_google_donation/java', 'src/no_google_cast_lib/java']
|
||||
}
|
||||
google_full {
|
||||
res.srcDirs = ['src/main/res', 'src/google_donation/res', 'src/google_cast_lib/res', 'src/full/res']
|
||||
java.srcDirs = ['src/main/java', 'src/full/java', 'src/google_donation/java', 'src/google_cast_lib/java']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
|
@ -37,33 +132,81 @@ allprojects {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
implementation "androidx.multidex:multidex:2.0.1"
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'androidx.preference:preference:1.1.1'
|
||||
implementation 'com.google.android.material:material:1.2.1'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
|
||||
implementation 'androidx.appcompat:appcompat:1.4.1'
|
||||
implementation 'androidx.preference:preference:1.2.0'
|
||||
implementation 'com.google.android.material:material:1.5.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
|
||||
implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
|
||||
implementation 'androidx.navigation:navigation-fragment:2.3.0'
|
||||
implementation "androidx.fragment:fragment:1.2.5"
|
||||
implementation 'androidx.navigation:navigation-ui:2.3.0'
|
||||
implementation ("androidx.navigation:navigation-dynamic-features-fragment:2.3.0")
|
||||
implementation 'androidx.navigation:navigation-fragment:2.4.2'
|
||||
implementation "androidx.fragment:fragment:1.4.1"
|
||||
implementation 'androidx.navigation:navigation-ui:2.4.2'
|
||||
implementation ("androidx.navigation:navigation-dynamic-features-fragment:2.4.2")
|
||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
||||
implementation 'androidx.browser:browser:1.2.0'
|
||||
testImplementation 'junit:junit:4.13'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
||||
implementation 'androidx.browser:browser:1.4.0'
|
||||
implementation 'androidx.documentfile:documentfile:1.0.1'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||
|
||||
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
|
||||
implementation 'com.github.GrenderG:Toasty:1.4.2'
|
||||
implementation 'com.google.android.exoplayer:exoplayer:2.10.6'
|
||||
implementation 'com.github.amoskorir:avatarimagegenerator:1.5.0'
|
||||
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0'
|
||||
implementation 'com.github.GrenderG:Toasty:1.5.2'
|
||||
implementation 'com.google.android.exoplayer:exoplayer:2.12.2'
|
||||
implementation 'com.google.android.exoplayer:extension-mediasession:2.12.2'
|
||||
implementation "com.github.mabbas007:TagsEditText:1.0.5"
|
||||
implementation "com.github.bumptech.glide:glide:4.11.0"
|
||||
annotationProcessor "com.github.bumptech.glide:compiler:4.11.0"
|
||||
implementation 'jp.wasabeef:glide-transformations:4.0.0'
|
||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
||||
implementation 'org.apache.poi:poi:3.16'
|
||||
implementation "net.gotev:uploadservice:3.5.2"
|
||||
implementation "net.gotev:uploadservice-okhttp:3.5.2"
|
||||
implementation "net.gotev:uploadservice:4.5.1"
|
||||
implementation "net.gotev:uploadservice-okhttp:4.5.1"
|
||||
implementation "com.google.code.gson:gson:2.8.6"
|
||||
implementation 'androidx.media:media:1.6.0'
|
||||
implementation 'com.github.ybq:Android-SpinKit:1.4.0'
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
||||
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
|
||||
implementation 'com.github.mancj:MaterialSearchBar:0.8.5'
|
||||
|
||||
|
||||
implementation "io.github.kobakei:ratethisapp:1.2.0"
|
||||
implementation 'com.github.vkay94:DoubleTapPlayerView:1.0.0'
|
||||
|
||||
implementation "androidx.work:work-runtime:2.7.1"
|
||||
|
||||
|
||||
//************ DONATION GOOGLE ONLY **************//
|
||||
google_fullImplementation "com.android.billingclient:billing:4.1.0"
|
||||
|
||||
//************ MATOMO --> acad instances only **************//
|
||||
|
||||
fdroid_acadImplementation 'org.matomo.sdk:tracker:4.1.2'
|
||||
google_acadImplementation 'org.matomo.sdk:tracker:4.1.2'
|
||||
|
||||
//************ CAST **************///
|
||||
|
||||
//---> Google libs (google_full)
|
||||
google_acadImplementation "com.google.android.gms:play-services-cast-tv:19.0.1"
|
||||
google_acadImplementation "com.google.android.gms:play-services-cast:21.0.1"
|
||||
google_acadImplementation "androidx.mediarouter:mediarouter:1.3.0"
|
||||
google_acadImplementation 'com.google.android.gms:play-services-cast-framework:21.0.1'
|
||||
|
||||
google_fullImplementation "com.google.android.gms:play-services-cast-tv:19.0.1"
|
||||
google_fullImplementation "com.google.android.gms:play-services-cast:21.0.1"
|
||||
google_fullImplementation "androidx.mediarouter:mediarouter:1.3.0"
|
||||
google_fullImplementation 'com.google.android.gms:play-services-cast-framework:21.0.1'
|
||||
|
||||
//----> Other flavors
|
||||
fdroid_acadImplementation 'su.litvak.chromecast:api-v2:0.11.3'
|
||||
fdroid_acadImplementation 'com.fasterxml.jackson.core:jackson-core:2.12.0'
|
||||
fdroid_acadImplementation 'org.slf4j:slf4j-simple:1.7.30'
|
||||
fdroid_acadImplementation 'com.github.evozi:Cyanea:1.0.7'
|
||||
|
||||
fdroid_fullImplementation 'su.litvak.chromecast:api-v2:0.11.3'
|
||||
fdroid_fullImplementation 'com.fasterxml.jackson.core:jackson-core:2.12.0'
|
||||
fdroid_fullImplementation 'org.slf4j:slf4j-simple:1.7.30'
|
||||
|
||||
}
|
After Width: | Height: | Size: 16 KiB |
|
@ -0,0 +1,39 @@
|
|||
package app.fedilab.fedilabtube;
|
||||
/* Copyright 2020 Thomas Schneider
|
||||
*
|
||||
* This file is a part of TubeLab
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
|
||||
|
||||
import org.matomo.sdk.Matomo;
|
||||
import org.matomo.sdk.Tracker;
|
||||
import org.matomo.sdk.TrackerBuilder;
|
||||
|
||||
|
||||
|
||||
public class FedilabTube extends BaseFedilabTube {
|
||||
|
||||
private Tracker mMatomoTracker;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
}
|
||||
|
||||
public synchronized Tracker getTracker() {
|
||||
if (mMatomoTracker != null) return mMatomoTracker;
|
||||
mMatomoTracker = TrackerBuilder.createDefault("https://wa.phm.education.gouv.fr/snp/matomo.php", 11).build(Matomo.getInstance(this));
|
||||
return mMatomoTracker;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package app.fedilab.fedilabtube;
|
||||
/* Copyright 2020 Thomas Schneider
|
||||
*
|
||||
* This file is a part of TubeLab
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
|
||||
import org.matomo.sdk.Tracker;
|
||||
import org.matomo.sdk.extra.TrackHelper;
|
||||
|
||||
public class Matomo {
|
||||
|
||||
public static void sendScreen(Context _mcontext, String path, String title) {
|
||||
Tracker tracker = ((FedilabTube) ((Activity) _mcontext).getApplication()).getTracker();
|
||||
TrackHelper.track().screen(path).title(title).with(tracker);
|
||||
}
|
||||
|
||||
public static void sendEvent(Context _mcontext, String category, String action, String label, float value) {
|
||||
Tracker tracker = ((FedilabTube) ((Activity) _mcontext).getApplication()).getTracker();
|
||||
TrackHelper.track().event(category, action).name(label).value(value).with(tracker);
|
||||
}
|
||||
|
||||
|
||||
public static void sendValue(Context _mcontext, String path, int index, String dimensionValue) {
|
||||
Tracker tracker = ((FedilabTube) ((Activity) _mcontext).getApplication()).getTracker();
|
||||
TrackHelper.track().screen(path).dimension(index, dimensionValue).with(tracker);
|
||||
}
|
||||
|
||||
|
||||
public static void trackInstall(Context _mcontext) {
|
||||
Tracker tracker = ((FedilabTube) ((Activity) _mcontext).getApplication()).getTracker();
|
||||
TrackHelper.track().download().with(tracker);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package app.fedilab.fedilabtube.activities;
|
||||
/* Copyright 2022 Thomas Schneider
|
||||
*
|
||||
* This file is a part of TubeLab
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
|
||||
public class BaseActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package app.fedilab.fedilabtube.helper;
|
||||
/* Copyright 2022 Thomas Schneider
|
||||
*
|
||||
* This file is a part of TubeLab
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import app.fedilab.fedilabtube.R;
|
||||
|
||||
public class Theme {
|
||||
|
||||
public static void setTheme(AppCompatActivity activity, String instance, boolean noActionBar) {
|
||||
|
||||
switch (instance) {
|
||||
case "tube-institutionnel.apps.education.fr":
|
||||
activity.setTheme(noActionBar? R.style.InstitutionnelNoActionBar:R.style.Institutionnel);
|
||||
break;
|
||||
case "tube-maternelle.apps.education.fr":
|
||||
activity.setTheme(noActionBar?R.style.MaternelleNoActionBar:R.style.Maternelle);
|
||||
break;
|
||||
case "tube-arts-lettres-sciences-humaines.apps.education.fr":
|
||||
activity.setTheme(noActionBar?R.style.ArtNoActionBar:R.style.Art);
|
||||
break;
|
||||
case "tube-sciences-technologies.apps.education.fr":
|
||||
activity.setTheme(noActionBar?R.style.SciencesNoActionBar:R.style.Sciences);
|
||||
break;
|
||||
case "tube-education-physique-et-sportive.apps.education.fr":
|
||||
activity.setTheme(noActionBar?R.style.EducationNoActionBar:R.style.Education);
|
||||
break;
|
||||
case "tube-enseignement-professionnel.apps.education.fr":
|
||||
activity.setTheme(noActionBar?R.style.EnseignementProNoActionBar:R.style.EnseignementPro);
|
||||
break;
|
||||
case "tube-langues-vivantes.apps.education.fr":
|
||||
activity.setTheme(noActionBar?R.style.LanguesNoActionBar:R.style.Langues);
|
||||
break;
|
||||
case "tube-action-educative.apps.education.fr":
|
||||
activity.setTheme(noActionBar?R.style.ActionEducativeNoActionBar:R.style.ActionEducative);
|
||||
break;
|
||||
case "tube-cycle-2.apps.education.fr":
|
||||
activity.setTheme(noActionBar?R.style.Cycle2NoActionBar:R.style.Cycle2);
|
||||
break;
|
||||
case "tube-cycle-3.apps.education.fr":
|
||||
activity.setTheme(noActionBar?R.style.Cycle3NoActionBar:R.style.Cycle3);
|
||||
break;
|
||||
default:
|
||||
activity.setTheme(noActionBar?R.style.AppThemeNoActionBar:R.style.AppTheme);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:color="@color/colorAccent"
|
||||
android:state_checked="true" />
|
||||
<item android:color="@android:color/tab_indicator_text" />
|
||||
</selector>
|
|
@ -1,14 +1,14 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:tint="#9C27B0"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<group
|
||||
android:scaleX="2.61"
|
||||
android:scaleY="2.61"
|
||||
android:translateX="22.68"
|
||||
android:translateY="22.68">
|
||||
android:scaleX="1.104"
|
||||
android:scaleY="1.104"
|
||||
android:translateX="-1.248"
|
||||
android:translateY="-1.248">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M10,16.5l6,-4.5 -6,-4.5v9zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z" />
|
After Width: | Height: | Size: 720 B |
After Width: | Height: | Size: 491 B |
After Width: | Height: | Size: 937 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.6 KiB |
|
@ -0,0 +1,21 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<group
|
||||
android:scaleX="2.0409248"
|
||||
android:scaleY="2.0409248"
|
||||
android:translateX="19.44"
|
||||
android:translateY="19.44">
|
||||
<path
|
||||
android:fillColor="#502ca7"
|
||||
android:pathData="m0,0h33.867v33.867h-33.867z" />
|
||||
<path
|
||||
android:fillColor="#9a26ae"
|
||||
android:pathData="m15.544,29.459c-0.5613,-0.052 -1.8193,-0.2922 -2.5659,-0.49 -1.4544,-0.3854 -2.6614,-0.9423 -3.8833,-1.7918 -2.3102,-1.606 -3.8461,-3.928 -4.3943,-6.6437 -0.4789,-2.3721 -0.2362,-5.3562 0.6533,-8.0312 0.376,-1.131 0.7053,-1.8387 1.2806,-2.7519 0.9004,-1.4293 1.5877,-2.1804 2.8991,-3.1683 1.3049,-0.983 2.9258,-1.6476 4.88,-2.0009 0.8669,-0.1568 1.1303,-0.1748 2.5858,-0.1775 1.5249,-0.0027 1.6704,0.0078 2.465,0.1789 1.9969,0.43 3.3805,1.0324 4.9616,2.1602 1.8104,1.2913 3.1669,2.8519 4.0578,4.6681 0.896,1.8267 1.3075,3.6274 1.3075,5.7214 0,1.5759 -0.2607,3.1575 -0.7605,4.613 -0.8579,2.4986 -2.193,4.235 -4.4452,5.7811 -1.2142,0.8336 -2.9496,1.4792 -4.8751,1.8136 -0.6105,0.106 -3.4333,0.1862 -4.1663,0.1183zM19.42,26.9851c1.5946,-0.1757 3.0062,-0.5799 4.293,-1.2293 1.048,-0.5289 1.5517,-0.8781 2.271,-1.5743 0.9003,-0.8714 1.3979,-1.6179 1.8328,-2.7494 0.3399,-0.8845 0.4151,-1.1551 0.5267,-1.8953 0.3809,-2.5269 -0.4498,-6.1791 -1.8859,-8.291 -0.9544,-1.4038 -2.0586,-2.3755 -3.7036,-3.2592 -2.538,-1.3635 -6.6246,-1.6184 -9.6573,-0.6023 -1.2489,0.4185 -2.8043,1.4067 -3.6027,2.289 -0.7826,0.8649 -1.5925,2.2749 -1.9531,3.4007 -0.3872,1.2088 -0.4937,2.0043 -0.4947,3.695 -0.0008,1.3192 0.0189,1.6195 0.1484,2.2599 0.2029,1.0037 0.4086,1.6055 0.8491,2.4837 0.9265,1.8474 2.0961,3.1054 3.8624,4.1541 1.3723,0.8148 2.6611,1.2289 4.3987,1.4136 0.4192,0.0446 2.3964,-0.0157 3.1154,-0.0949z" />
|
||||
<path
|
||||
android:fillColor="#9a26ae"
|
||||
android:pathData="m14.648,11.972 l7.4433,4.9609 -7.4433,4.9609z" />
|
||||
</group>
|
||||
</vector>
|
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 8.1 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,145 @@
|
|||
<resources>
|
||||
|
||||
<attr name="backgroundView" format="color" />
|
||||
|
||||
<style name="BaseTheme" parent="Theme.AppCompat.DayNight.DarkActionBar">
|
||||
<item name="backgroundView">@color/backgroundDark</item>
|
||||
</style>
|
||||
<style name="BaseThemeNoAction" parent="Theme.AppCompat.DayNight.NoActionBar">
|
||||
<item name="backgroundView">@color/backgroundDark</item>
|
||||
</style>
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="BaseTheme">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
</style>
|
||||
|
||||
<style name="AppThemeNoActionBar" parent="BaseThemeNoAction">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
</style>
|
||||
|
||||
<!-- Institutionnel theme. -->
|
||||
<style name="Institutionnel" parent="BaseTheme">
|
||||
<item name="colorPrimary">@color/colorPrimary_institutionnel</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_institutionnel</item>
|
||||
<item name="colorAccent">@color/colorAccent_institutionnel</item>
|
||||
</style>
|
||||
<style name="InstitutionnelNoActionBar" parent="BaseThemeNoAction">
|
||||
<item name="colorPrimary">@color/colorPrimary_institutionnel</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_institutionnel</item>
|
||||
<item name="colorAccent">@color/colorAccent_institutionnel</item>
|
||||
</style>
|
||||
<!-- Maternelle theme. -->
|
||||
<style name="Maternelle" parent="BaseTheme">
|
||||
<item name="colorPrimary">@color/colorPrimary_maternelle</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_maternelle</item>
|
||||
<item name="colorAccent">@color/colorAccent_maternelle</item>
|
||||
</style>
|
||||
<style name="MaternelleNoActionBar" parent="BaseThemeNoAction">
|
||||
<item name="colorPrimary">@color/colorPrimary_maternelle</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_maternelle</item>
|
||||
<item name="colorAccent">@color/colorAccent_maternelle</item>
|
||||
</style>
|
||||
<!-- Art theme. -->
|
||||
<style name="Art" parent="BaseTheme">
|
||||
<item name="colorPrimary">@color/colorPrimary_art</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_art</item>
|
||||
<item name="colorAccent">@color/colorAccent_art</item>
|
||||
</style>
|
||||
<style name="ArtNoActionBar" parent="BaseThemeNoAction">
|
||||
<item name="colorPrimary">@color/colorPrimary_art</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_art</item>
|
||||
<item name="colorAccent">@color/colorAccent_art</item>
|
||||
</style>
|
||||
<!-- Sciences theme. -->
|
||||
<style name="Sciences" parent="BaseTheme">
|
||||
<item name="colorPrimary">@color/colorPrimary_sciences</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_sciences</item>
|
||||
<item name="colorAccent">@color/colorAccent_sciences</item>
|
||||
</style>
|
||||
<style name="SciencesNoActionBar" parent="BaseThemeNoAction">
|
||||
<item name="colorPrimary">@color/colorPrimary_sciences</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_sciences</item>
|
||||
<item name="colorAccent">@color/colorAccent_sciences</item>
|
||||
</style>
|
||||
<!-- Education theme. -->
|
||||
<style name="Education" parent="BaseTheme">
|
||||
<item name="colorPrimary">@color/colorPrimary_education</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_education</item>
|
||||
<item name="colorAccent">@color/colorAccent_education</item>
|
||||
</style>
|
||||
<style name="EducationNoActionBar" parent="BaseThemeNoAction">
|
||||
<item name="colorPrimary">@color/colorPrimary_education</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_education</item>
|
||||
<item name="colorAccent">@color/colorAccent_education</item>
|
||||
</style>
|
||||
<!-- Enseignement Pro theme. -->
|
||||
<style name="EnseignementPro" parent="BaseTheme">
|
||||
<item name="colorPrimary">@color/colorPrimary_enseignement_pro</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_enseignement_pro</item>
|
||||
<item name="colorAccent">@color/colorAccent_enseignement_pro</item>
|
||||
</style>
|
||||
<style name="EnseignementProNoActionBar" parent="BaseThemeNoAction">
|
||||
<item name="colorPrimary">@color/colorPrimary_enseignement_pro</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_enseignement_pro</item>
|
||||
<item name="colorAccent">@color/colorAccent_enseignement_pro</item>
|
||||
</style>
|
||||
<!-- Langues theme. -->
|
||||
<style name="Langues" parent="BaseTheme">
|
||||
<item name="colorPrimary">@color/colorPrimary_langues</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_langues</item>
|
||||
<item name="colorAccent">@color/colorAccent_langues</item>
|
||||
</style>
|
||||
<style name="LanguesNoActionBar" parent="BaseThemeNoAction">
|
||||
<item name="colorPrimary">@color/colorPrimary_langues</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_langues</item>
|
||||
<item name="colorAccent">@color/colorAccent_langues</item>
|
||||
</style>
|
||||
<!-- ActionEducative theme. -->
|
||||
<style name="ActionEducative" parent="BaseTheme">
|
||||
<item name="colorPrimary">@color/colorPrimary_action_educative</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_action_educative</item>
|
||||
<item name="colorAccent">@color/colorAccent_action_educative</item>
|
||||
</style>
|
||||
<style name="ActionEducativeNoActionBar" parent="BaseThemeNoAction">
|
||||
<item name="colorPrimary">@color/colorPrimary_action_educative</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_action_educative</item>
|
||||
<item name="colorAccent">@color/colorAccent_action_educative</item>
|
||||
</style>
|
||||
<!-- Cycle 2 theme. -->
|
||||
<style name="Cycle2" parent="BaseTheme">
|
||||
<item name="colorPrimary">@color/colorPrimary_cycle2</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_cycle2</item>
|
||||
<item name="colorAccent">@color/colorAccent_cycle2</item>
|
||||
</style>
|
||||
<style name="Cycle2NoActionBar" parent="BaseThemeNoAction">
|
||||
<item name="colorPrimary">@color/colorPrimary_cycle2</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_cycle2</item>
|
||||
<item name="colorAccent">@color/colorAccent_cycle2</item>
|
||||
</style>
|
||||
<!-- Cycle 3 theme. -->
|
||||
<style name="Cycle3" parent="BaseTheme">
|
||||
<item name="colorPrimary">@color/colorPrimary_cycle3</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_cycle3</item>
|
||||
<item name="colorAccent">@color/colorAccent_cycle3</item>
|
||||
</style>
|
||||
<style name="Cycle3NoActionBar" parent="BaseThemeNoAction">
|
||||
<item name="colorPrimary">@color/colorPrimary_cycle3</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_cycle3</item>
|
||||
<item name="colorAccent">@color/colorAccent_cycle3</item>
|
||||
</style>
|
||||
<style name="theme" parent="@style/ThemeOverlay.AppCompat.Dark" />
|
||||
|
||||
<style name="popupTheme" parent="@style/ThemeOverlay.AppCompat.DayNight" />
|
||||
|
||||
<style name="progress" parent="SpinKitView.Circle" />
|
||||
|
||||
<style name="progressBottom" parent="SpinKitView.ThreeBounce" />
|
||||
|
||||
<style name="searchBarSepia" parent="MaterialSearchBarDark" />
|
||||
</resources>
|
|
@ -0,0 +1,61 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<color name="colorPrimary">#512DA8</color>
|
||||
<color name="colorPrimaryDark">#4527A0</color>
|
||||
<color name="colorAccent">#9C27B0</color>
|
||||
|
||||
<!-- Institutionnel -->
|
||||
<color name="colorPrimary_institutionnel">#1B2E35</color>
|
||||
<color name="colorPrimaryDark_institutionnel">#1B2E35</color>
|
||||
<color name="colorAccent_institutionnel">#35A8E0</color>
|
||||
<!-- maternelle -->
|
||||
<color name="colorPrimary_maternelle">#341047</color>
|
||||
<color name="colorPrimaryDark_maternelle">#341047</color>
|
||||
<color name="colorAccent_maternelle">#D3135D</color>
|
||||
<!-- art -->
|
||||
<color name="colorPrimary_art">#0d3b5f</color>
|
||||
<color name="colorPrimaryDark_art">#0d3b5f</color>
|
||||
<color name="colorAccent_art">#E61B72</color>
|
||||
<!-- sciences -->
|
||||
<color name="colorPrimary_sciences">#0d3b5f</color>
|
||||
<color name="colorPrimaryDark_sciences">#0d3b5f</color>
|
||||
<color name="colorAccent_sciences">#59b700</color>
|
||||
<!-- education -->
|
||||
<color name="colorPrimary_education">#0d3b5f</color>
|
||||
<color name="colorPrimaryDark_education">#0d3b5f</color>
|
||||
<color name="colorAccent_education">#EA3700</color>
|
||||
<!-- enseignement pro -->
|
||||
<color name="colorPrimary_enseignement_pro">#0d3b5f</color>
|
||||
<color name="colorPrimaryDark_enseignement_pro">#0d3b5f</color>
|
||||
<color name="colorAccent_enseignement_pro">#730FBA</color>
|
||||
<!-- langues -->
|
||||
<color name="colorPrimary_langues">#0d3b5f</color>
|
||||
<color name="colorPrimaryDark_langues">#0d3b5f</color>
|
||||
<color name="colorAccent_langues">#F69622</color>
|
||||
<!-- Action éducative -->
|
||||
<color name="colorPrimary_action_educative">#1B2E35</color>
|
||||
<color name="colorPrimaryDark_action_educative">#1B2E35</color>
|
||||
<color name="colorAccent_action_educative">#E52928</color>
|
||||
<!-- cycle2 -->
|
||||
<color name="colorPrimary_cycle2">#341047</color>
|
||||
<color name="colorPrimaryDark_cycle2">#341047</color>
|
||||
<color name="colorAccent_cycle2">#39A935</color>
|
||||
<!-- cycle3 -->
|
||||
<color name="colorPrimary_cycle3">#341047</color>
|
||||
<color name="colorPrimaryDark_cycle3">#341047</color>
|
||||
<color name="colorAccent_cycle3">#C1661B</color>
|
||||
|
||||
|
||||
|
||||
<color name="tag_color">#bbF2690D</color>
|
||||
<color name="tag_color_text">#FAFAFA</color>
|
||||
<color name="positive_thumbs">#2b90d9</color>
|
||||
<color name="favorite">#ca8f04</color>
|
||||
<color name="bookmark">#795548</color>
|
||||
<color name="negative_thumbs">#F44336</color>
|
||||
<color name="backgroundLight">#DDFFFFFF</color>
|
||||
<color name="backgroundDark">#DD222222</color>
|
||||
<color name="red_1">#F44336</color>
|
||||
<color name="gray_light">#80808080</color>
|
||||
</resources>
|
|
@ -0,0 +1,145 @@
|
|||
<resources>
|
||||
|
||||
<attr name="backgroundView" format="color" />
|
||||
|
||||
|
||||
<style name="BaseTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<item name="backgroundView">@color/backgroundLight</item>
|
||||
</style>
|
||||
<style name="BaseThemeNoAction" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<item name="backgroundView">@color/backgroundLight</item>
|
||||
</style>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="BaseTheme">
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
</style>
|
||||
|
||||
<style name="AppThemeNoActionBar" parent="BaseThemeNoAction">
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
</style>
|
||||
|
||||
<!-- Institutionnel theme. -->
|
||||
<style name="Institutionnel" parent="BaseTheme">
|
||||
<item name="colorPrimary">@color/colorPrimary_institutionnel</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_institutionnel</item>
|
||||
<item name="colorAccent">@color/colorAccent_institutionnel</item>
|
||||
</style>
|
||||
<style name="InstitutionnelNoActionBar" parent="BaseThemeNoAction">
|
||||
<item name="colorPrimary">@color/colorPrimary_institutionnel</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_institutionnel</item>
|
||||
<item name="colorAccent">@color/colorAccent_institutionnel</item>
|
||||
</style>
|
||||
<!-- Maternelle theme. -->
|
||||
<style name="Maternelle" parent="BaseTheme">
|
||||
<item name="colorPrimary">@color/colorPrimary_maternelle</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_maternelle</item>
|
||||
<item name="colorAccent">@color/colorAccent_maternelle</item>
|
||||
</style>
|
||||
<style name="MaternelleNoActionBar" parent="BaseThemeNoAction">
|
||||
<item name="colorPrimary">@color/colorPrimary_maternelle</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_maternelle</item>
|
||||
<item name="colorAccent">@color/colorAccent_maternelle</item>
|
||||
</style>
|
||||
<!-- Art theme. -->
|
||||
<style name="Art" parent="BaseTheme">
|
||||
<item name="colorPrimary">@color/colorPrimary_art</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_art</item>
|
||||
<item name="colorAccent">@color/colorAccent_art</item>
|
||||
</style>
|
||||
<style name="ArtNoActionBar" parent="BaseThemeNoAction">
|
||||
<item name="colorPrimary">@color/colorPrimary_art</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_art</item>
|
||||
<item name="colorAccent">@color/colorAccent_art</item>
|
||||
</style>
|
||||
<!-- Sciences theme. -->
|
||||
<style name="Sciences" parent="BaseTheme">
|
||||
<item name="colorPrimary">@color/colorPrimary_sciences</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_sciences</item>
|
||||
<item name="colorAccent">@color/colorAccent_sciences</item>
|
||||
</style>
|
||||
<style name="SciencesNoActionBar" parent="BaseThemeNoAction">
|
||||
<item name="colorPrimary">@color/colorPrimary_sciences</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_sciences</item>
|
||||
<item name="colorAccent">@color/colorAccent_sciences</item>
|
||||
</style>
|
||||
<!-- Education theme. -->
|
||||
<style name="Education" parent="BaseTheme">
|
||||
<item name="colorPrimary">@color/colorPrimary_education</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_education</item>
|
||||
<item name="colorAccent">@color/colorAccent_education</item>
|
||||
</style>
|
||||
<style name="EducationNoActionBar" parent="BaseThemeNoAction">
|
||||
<item name="colorPrimary">@color/colorPrimary_education</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_education</item>
|
||||
<item name="colorAccent">@color/colorAccent_education</item>
|
||||
</style>
|
||||
<!-- Enseignement Pro theme. -->
|
||||
<style name="EnseignementPro" parent="BaseTheme">
|
||||
<item name="colorPrimary">@color/colorPrimary_enseignement_pro</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_enseignement_pro</item>
|
||||
<item name="colorAccent">@color/colorAccent_enseignement_pro</item>
|
||||
</style>
|
||||
<style name="EnseignementProNoActionBar" parent="BaseThemeNoAction">
|
||||
<item name="colorPrimary">@color/colorPrimary_enseignement_pro</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_enseignement_pro</item>
|
||||
<item name="colorAccent">@color/colorAccent_enseignement_pro</item>
|
||||
</style>
|
||||
<!-- Langues theme. -->
|
||||
<style name="Langues" parent="BaseTheme">
|
||||
<item name="colorPrimary">@color/colorPrimary_langues</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_langues</item>
|
||||
<item name="colorAccent">@color/colorAccent_langues</item>
|
||||
</style>
|
||||
<style name="LanguesNoActionBar" parent="BaseThemeNoAction">
|
||||
<item name="colorPrimary">@color/colorPrimary_langues</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_langues</item>
|
||||
<item name="colorAccent">@color/colorAccent_langues</item>
|
||||
</style>
|
||||
<!-- ActionEducative theme. -->
|
||||
<style name="ActionEducative" parent="BaseTheme">
|
||||
<item name="colorPrimary">@color/colorPrimary_action_educative</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_action_educative</item>
|
||||
<item name="colorAccent">@color/colorAccent_action_educative</item>
|
||||
</style>
|
||||
<style name="ActionEducativeNoActionBar" parent="BaseThemeNoAction">
|
||||
<item name="colorPrimary">@color/colorPrimary_action_educative</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_action_educative</item>
|
||||
<item name="colorAccent">@color/colorAccent_action_educative</item>
|
||||
</style>
|
||||
<!-- Cycle 2 theme. -->
|
||||
<style name="Cycle2" parent="BaseTheme">
|
||||
<item name="colorPrimary">@color/colorPrimary_cycle2</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_cycle2</item>
|
||||
<item name="colorAccent">@color/colorAccent_cycle2</item>
|
||||
</style>
|
||||
<style name="Cycle2NoActionBar" parent="BaseThemeNoAction">
|
||||
<item name="colorPrimary">@color/colorPrimary_cycle2</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_cycle2</item>
|
||||
<item name="colorAccent">@color/colorAccent_cycle2</item>
|
||||
</style>
|
||||
<!-- Cycle 3 theme. -->
|
||||
<style name="Cycle3" parent="BaseTheme">
|
||||
<item name="colorPrimary">@color/colorPrimary_cycle3</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_cycle3</item>
|
||||
<item name="colorAccent">@color/colorAccent_cycle3</item>
|
||||
</style>
|
||||
<style name="Cycle3NoActionBar" parent="BaseThemeNoAction">
|
||||
<item name="colorPrimary">@color/colorPrimary_cycle3</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark_cycle3</item>
|
||||
<item name="colorAccent">@color/colorAccent_cycle3</item>
|
||||
</style>
|
||||
<style name="theme" parent="@style/ThemeOverlay.AppCompat.Dark" />
|
||||
|
||||
<style name="popupTheme" parent="@style/ThemeOverlay.AppCompat.DayNight" />
|
||||
|
||||
<style name="progress" parent="SpinKitView.Circle" />
|
||||
|
||||
<style name="progressBottom" parent="SpinKitView.ThreeBounce" />
|
||||
|
||||
<style name="searchBarSepia" parent="MaterialSearchBarDark" />
|
||||
</resources>
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths>
|
||||
<external-path
|
||||
name="my_images"
|
||||
path="/TubeAcad/" />
|
||||
|
||||
<external-path
|
||||
name="external_files"
|
||||
path="/"/>
|
||||
|
||||
</paths>
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="app.fedilab.fedilabtube">
|
||||
|
||||
|
||||
<application
|
||||
android:name=".FedilabTube"
|
||||
android:allowBackup="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:replace="android:allowBackup">
|
||||
|
||||
<activity
|
||||
android:name=".activities.MainActivity"
|
||||
tools:node="merge"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="content" />
|
||||
<data android:scheme="file" />
|
||||
<data android:host="*" />
|
||||
<data android:mimeType="*/*" />
|
||||
<data android:pathPattern=".*\\.tubelab" />
|
||||
<data android:pathPattern=".*\\..*\\.tubelab" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\.tubelab" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\.tubelab" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.tubelab" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.tubelab" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
</manifest>
|
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="app.fedilab.fedilabtube">
|
||||
|
||||
|
||||
<application
|
||||
android:name=".FedilabTube"
|
||||
android:allowBackup="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:replace="android:allowBackup">
|
||||
|
||||
<activity
|
||||
android:name=".activities.PeertubeActivity"
|
||||
android:exported="true"
|
||||
tools:node="mergeOnlyAttributes">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<!-- The app is a good candidate for URL in https://domain.name/videos/watch/xxxxx-->
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/videos/watch/"
|
||||
android:scheme="https" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
</manifest>
|
After Width: | Height: | Size: 20 KiB |
|
@ -14,22 +14,7 @@ package app.fedilab.fedilabtube;
|
|||
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.multidex.MultiDex;
|
||||
import androidx.multidex.MultiDexApplication;
|
||||
|
||||
import net.gotev.uploadservice.UploadService;
|
||||
|
||||
public class FedilabTube extends MultiDexApplication {
|
||||
@Override
|
||||
protected void attachBaseContext(Context base) {
|
||||
super.attachBaseContext(base);
|
||||
|
||||
MultiDex.install(FedilabTube.this);
|
||||
|
||||
UploadService.NAMESPACE = BuildConfig.APPLICATION_ID;
|
||||
}
|
||||
|
||||
|
||||
public class FedilabTube extends BaseFedilabTube {
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package app.fedilab.fedilabtube;
|
||||
/* Copyright 2020 Thomas Schneider
|
||||
*
|
||||
* This file is a part of TubeLab
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
|
||||
@SuppressWarnings({"unused", "RedundantSuppression"})
|
||||
public class Matomo {
|
||||
|
||||
public static void sendScreen(Context _mcontext, String path, String title) {
|
||||
//Do nothing
|
||||
}
|
||||
|
||||
public static void sendEvent(Context _mcontext, String category, String action, String label, float value) {
|
||||
//Do nothing
|
||||
}
|
||||
|
||||
|
||||
public static void sendValue(Context _mcontext, String path, int index, String dimensionValue) {
|
||||
//Do nothing
|
||||
}
|
||||
|
||||
|
||||
public static void trackInstall(Context _mcontext) {
|
||||
//Do nothing
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package app.fedilab.fedilabtube.activities;
|
||||
/* Copyright 2022 Thomas Schneider
|
||||
*
|
||||
* This file is a part of TubeLab
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
public class BaseActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package app.fedilab.fedilabtube.helper;
|
||||
/* Copyright 2022 Thomas Schneider
|
||||
*
|
||||
* This file is a part of TubeLab
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import app.fedilab.fedilabtube.R;
|
||||
|
||||
public class Theme {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static void setTheme(AppCompatActivity activity, String instance, boolean noActionBar) {
|
||||
activity.setTheme(noActionBar?R.style.AppThemeNoActionBar:R.style.AppTheme);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="@color/colorAccent" android:state_checked="true" />
|
||||
<item android:color="@android:color/tab_indicator_text" />
|
||||
</selector>
|
|
@ -0,0 +1,16 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<group
|
||||
android:scaleX="1.104"
|
||||
android:scaleY="1.104"
|
||||
android:translateX="-1.248"
|
||||
android:translateY="-1.248">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M10,16.5l6,-4.5 -6,-4.5v9zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z" />
|
||||
</group>
|
||||
</vector>
|
After Width: | Height: | Size: 720 B |
After Width: | Height: | Size: 491 B |
After Width: | Height: | Size: 937 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.6 KiB |
|
@ -0,0 +1,21 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<group
|
||||
android:scaleX="2.0409248"
|
||||
android:scaleY="2.0409248"
|
||||
android:translateX="19.44"
|
||||
android:translateY="19.44">
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="m0,0h33.867v33.867h-33.867z" />
|
||||
<path
|
||||
android:fillColor="#f2690d"
|
||||
android:pathData="m15.544,29.459c-0.5613,-0.052 -1.8193,-0.2922 -2.5659,-0.49 -1.4544,-0.3854 -2.6614,-0.9423 -3.8833,-1.7918 -2.3102,-1.606 -3.8461,-3.928 -4.3943,-6.6437 -0.4789,-2.3721 -0.2362,-5.3562 0.6533,-8.0312 0.376,-1.131 0.7053,-1.8387 1.2806,-2.7519 0.9004,-1.4293 1.5877,-2.1804 2.8991,-3.1683 1.3049,-0.983 2.9258,-1.6476 4.88,-2.0009 0.8669,-0.1568 1.1303,-0.1748 2.5858,-0.1775 1.5249,-0.0027 1.6704,0.0078 2.465,0.1789 1.9969,0.43 3.3805,1.0324 4.9616,2.1602 1.8104,1.2913 3.1669,2.8519 4.0578,4.6681 0.896,1.8267 1.3075,3.6274 1.3075,5.7214 0,1.5759 -0.2607,3.1575 -0.7605,4.613 -0.8579,2.4986 -2.193,4.235 -4.4452,5.7811 -1.2142,0.8336 -2.9496,1.4792 -4.8751,1.8136 -0.6105,0.106 -3.4333,0.1862 -4.1663,0.1183zM19.42,26.9851c1.5946,-0.1757 3.0062,-0.5799 4.293,-1.2293 1.048,-0.5289 1.5517,-0.8781 2.271,-1.5743 0.9003,-0.8714 1.3979,-1.6179 1.8328,-2.7494 0.3399,-0.8845 0.4151,-1.1551 0.5267,-1.8953 0.3809,-2.5269 -0.4498,-6.1791 -1.8859,-8.291 -0.9544,-1.4038 -2.0586,-2.3755 -3.7036,-3.2592 -2.538,-1.3635 -6.6246,-1.6184 -9.6573,-0.6023 -1.2489,0.4185 -2.8043,1.4067 -3.6027,2.289 -0.7826,0.8649 -1.5925,2.2749 -1.9531,3.4007 -0.3872,1.2088 -0.4937,2.0043 -0.4947,3.695 -0.0008,1.3192 0.0189,1.6195 0.1484,2.2599 0.2029,1.0037 0.4086,1.6055 0.8491,2.4837 0.9265,1.8474 2.0961,3.1054 3.8624,4.1541 1.3723,0.8148 2.6611,1.2289 4.3987,1.4136 0.4192,0.0446 2.3964,-0.0157 3.1154,-0.0949z" />
|
||||
<path
|
||||
android:fillColor="#f2690d"
|
||||
android:pathData="m14.648,11.972 l7.4433,4.9609 -7.4433,4.9609z" />
|
||||
</group>
|
||||
</vector>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 6.9 KiB |
After Width: | Height: | Size: 5.3 KiB |
After Width: | Height: | Size: 9.6 KiB |
|
@ -0,0 +1,39 @@
|
|||
<resources>
|
||||
|
||||
<attr name="backgroundView" format="color" />
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.DayNight.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
<item name="android:textColor">?attr/colorOnBackground</item>
|
||||
<item name="backgroundView">@color/backgroundDark</item>
|
||||
<item name="android:windowBackground">@android:color/black</item>
|
||||
<item name="android:colorBackground">@android:color/black</item>
|
||||
</style>
|
||||
|
||||
<style name="AppThemeNoActionBar" parent="Theme.AppCompat.DayNight.NoActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
<item name="backgroundView">@color/backgroundDark</item>
|
||||
<item name="android:textColor">?attr/colorOnBackground</item>
|
||||
<item name="android:windowBackground">@android:color/black</item>
|
||||
<item name="android:colorBackground">@android:color/black</item>
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
|
||||
<style name="theme" parent="@style/ThemeOverlay.AppCompat.Dark" />
|
||||
|
||||
<style name="popupTheme" parent="@style/ThemeOverlay.AppCompat.Dark" />
|
||||
|
||||
<style name="progress" parent="SpinKitView.Circle" />
|
||||
|
||||
<style name="progressBottom" parent="SpinKitView.ThreeBounce" />
|
||||
|
||||
<style name="searchBarSepia" parent="MaterialSearchBarDark" />
|
||||
</resources>
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#212529</color>
|
||||
<color name="colorPrimaryDark">#000000</color>
|
||||
<color name="colorAccent">#F2690D</color>
|
||||
<color name="tag_color">#bbF2690D</color>
|
||||
<color name="tag_color_text">#FAFAFA</color>
|
||||
<color name="positive_thumbs">#2b90d9</color>
|
||||
<color name="negative_thumbs">#F44336</color>
|
||||
<color name="favorite">#ca8f04</color>
|
||||
<color name="bookmark">#795548</color>
|
||||
<color name="backgroundDark">#DD000000</color>
|
||||
<color name="red_1">#F44336</color>
|
||||
<color name="gray_light">#80808080</color>
|
||||
</resources>
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#000000</color>
|
||||
</resources>
|
|
@ -1,5 +1,5 @@
|
|||
<resources>
|
||||
|
||||
<attr name="backgroundView" format="color" />
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
|
@ -7,16 +7,27 @@
|
|||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
<item name="android:textColor">?attr/colorOnBackground</item>
|
||||
<item name="backgroundView">@color/white</item>
|
||||
</style>
|
||||
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppThemeNoActionBar" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
<item name="android:textColor">?attr/colorOnBackground</item>
|
||||
<item name="backgroundView">@color/white</item>
|
||||
</style>
|
||||
|
||||
<style name="theme" parent="@style/ThemeOverlay.AppCompat.Dark" />
|
||||
|
||||
<style name="popupTheme" parent="@style/ThemeOverlay.AppCompat.Light" />
|
||||
|
||||
<style name="progress" parent="SpinKitView.Circle" />
|
||||
|
||||
<style name="progressBottom" parent="SpinKitView.ThreeBounce" />
|
||||
|
||||
<style name="searchBarSepia" parent="MaterialSearchBarLight" />
|
||||
|
||||
</resources>
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<external-path
|
||||
name="my_images"
|
||||
path="/TubeLab/" />
|
||||
|
||||
</paths>
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="app.fedilab.fedilabtube">
|
||||
|
||||
|
||||
<application
|
||||
android:name=".FedilabTube"
|
||||
android:allowBackup="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:replace="android:allowBackup">
|
||||
|
||||
<activity
|
||||
android:name=".activities.MainActivity"
|
||||
tools:node="merge"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="content" />
|
||||
<data android:scheme="file" />
|
||||
<data android:host="*" />
|
||||
<data android:mimeType="application/json" />
|
||||
<data android:pathPattern=".*\\.tubelab" />
|
||||
<data android:pathPattern=".*\\..*\\.tubelab" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\.tubelab" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\.tubelab" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.tubelab" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.tubelab" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
|
||||
android:value="app.fedilab.fedilabtube.provider.CastOptionsProvider" />
|
||||
</application>
|
||||
</manifest>
|
|
@ -0,0 +1,42 @@
|
|||
package app.fedilab.fedilabtube;
|
||||
/* Copyright 2021 Thomas Schneider
|
||||
*
|
||||
* This file is a part of TubeLab
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import app.fedilab.fedilabtube.activities.BaseActivity;
|
||||
import app.fedilab.fedilabtube.databinding.ActivityMainBinding;
|
||||
|
||||
public class BaseMainActivity extends BaseActivity {
|
||||
|
||||
protected ActivityMainBinding binding;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||
View view = binding.getRoot();
|
||||
setContentView(view);
|
||||
}
|
||||
|
||||
//Method for discovering cast devices
|
||||
public void discoverCast() {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
package app.fedilab.fedilabtube;
|
||||
/* Copyright 2021 Thomas Schneider
|
||||
*
|
||||
* This file is a part of TubeLab
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.gms.cast.MediaInfo;
|
||||
import com.google.android.gms.cast.MediaMetadata;
|
||||
import com.google.android.gms.cast.framework.CastButtonFactory;
|
||||
import com.google.android.gms.cast.framework.CastContext;
|
||||
import com.google.android.gms.cast.framework.CastSession;
|
||||
import com.google.android.gms.cast.framework.SessionManagerListener;
|
||||
import com.google.android.gms.cast.framework.media.RemoteMediaClient;
|
||||
import com.google.android.gms.common.images.WebImage;
|
||||
|
||||
import app.fedilab.fedilabtube.activities.BaseActivity;
|
||||
import app.fedilab.fedilabtube.client.data.VideoData;
|
||||
import app.fedilab.fedilabtube.databinding.ActivityPeertubeBinding;
|
||||
import app.fedilab.fedilabtube.helper.Helper;
|
||||
|
||||
public class BasePeertubeActivity extends BaseActivity {
|
||||
|
||||
protected ActivityPeertubeBinding binding;
|
||||
protected VideoData.Video peertube;
|
||||
protected SimpleExoPlayer player;
|
||||
protected String videoURL;
|
||||
protected String subtitlesStr;
|
||||
|
||||
private CastContext mCastContext;
|
||||
private CastSession mCastSession;
|
||||
private SessionManagerListener<CastSession> mSessionManagerListener;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = ActivityPeertubeBinding.inflate(getLayoutInflater());
|
||||
View view = binding.getRoot();
|
||||
setContentView(view);
|
||||
final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
|
||||
int search_cast = sharedpreferences.getInt(getString(R.string.set_cast_choice), BuildConfig.cast_enabled);
|
||||
if (search_cast == 1) {
|
||||
setupCastListener();
|
||||
mCastContext = CastContext.getSharedInstance(BasePeertubeActivity.this);
|
||||
mCastSession = mCastContext.getSessionManager().getCurrentCastSession();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected void loadCast() {
|
||||
MediaMetadata movieMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE);
|
||||
|
||||
movieMetadata.putString(MediaMetadata.KEY_TITLE, peertube.getTitle());
|
||||
movieMetadata.putString(MediaMetadata.KEY_ARTIST, peertube.getAccount().getDisplayName());
|
||||
if (subtitlesStr != null) {
|
||||
movieMetadata.putString(MediaMetadata.KEY_SUBTITLE, subtitlesStr);
|
||||
}
|
||||
movieMetadata.addImage(new WebImage(Uri.parse("https://" + peertube.getChannel().getHost() + peertube.getPreviewPath())));
|
||||
MediaInfo mediaInfo = new MediaInfo.Builder(videoURL)
|
||||
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
|
||||
.setMetadata(movieMetadata)
|
||||
.setStreamDuration(peertube.getDuration() * 1000L)
|
||||
.build();
|
||||
if (mCastSession != null) {
|
||||
RemoteMediaClient remoteMediaClient = mCastSession.getRemoteMediaClient();
|
||||
remoteMediaClient.load(mediaInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void setupCastListener() {
|
||||
mSessionManagerListener = new SessionManagerListener<CastSession>() {
|
||||
@Override
|
||||
public void onSessionStarting(@NonNull CastSession castSession) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionStarted(@NonNull CastSession castSession, String s) {
|
||||
onApplicationConnected(castSession, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionStartFailed(@NonNull CastSession castSession, int i) {
|
||||
onApplicationDisconnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionEnding(@NonNull CastSession castSession) {
|
||||
onApplicationDisconnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionEnded(@NonNull CastSession castSession, int i) {
|
||||
onApplicationDisconnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionResuming(@NonNull CastSession castSession, String s) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionResumed(@NonNull CastSession castSession, boolean b) {
|
||||
onApplicationConnected(castSession, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionResumeFailed(@NonNull CastSession castSession, int i) {
|
||||
onApplicationDisconnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionSuspended(@NonNull CastSession castSession, int i) {
|
||||
onApplicationDisconnected();
|
||||
}
|
||||
|
||||
private void onApplicationConnected(CastSession castSession, boolean hide) {
|
||||
mCastSession = castSession;
|
||||
supportInvalidateOptionsMenu();
|
||||
player.setPlayWhenReady(false);
|
||||
if (hide) {
|
||||
binding.doubleTapPlayerView.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
binding.minController.castMiniController.setVisibility(View.VISIBLE);
|
||||
loadCast();
|
||||
}
|
||||
|
||||
private void onApplicationDisconnected() {
|
||||
binding.doubleTapPlayerView.setVisibility(View.VISIBLE);
|
||||
binding.minController.castMiniController.setVisibility(View.GONE);
|
||||
supportInvalidateOptionsMenu();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
mCastContext.getSessionManager().addSessionManagerListener(
|
||||
mSessionManagerListener, CastSession.class);
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
mCastContext.getSessionManager().removeSessionManagerListener(
|
||||
mSessionManagerListener, CastSession.class);
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
getMenuInflater().inflate(R.menu.video_menu, menu);
|
||||
CastButtonFactory.setUpMediaRouteButton(getApplicationContext(),
|
||||
menu,
|
||||
R.id.media_route_button);
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Google LLC. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package app.fedilab.fedilabtube.expandedcontrols;
|
||||
|
||||
import android.view.Menu;
|
||||
|
||||
import com.google.android.gms.cast.framework.CastButtonFactory;
|
||||
import com.google.android.gms.cast.framework.media.widget.ExpandedControllerActivity;
|
||||
|
||||
import app.fedilab.fedilabtube.R;
|
||||
|
||||
|
||||
public class ExpandedControlsActivity extends ExpandedControllerActivity {
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
getMenuInflater().inflate(R.menu.video_menu, menu);
|
||||
CastButtonFactory.setUpMediaRouteButton(this, menu, R.id.media_route_button);
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package app.fedilab.fedilabtube.provider;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.android.gms.cast.framework.CastOptions;
|
||||
import com.google.android.gms.cast.framework.OptionsProvider;
|
||||
import com.google.android.gms.cast.framework.SessionProvider;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import app.fedilab.fedilabtube.helper.Helper;
|
||||
|
||||
public class CastOptionsProvider implements OptionsProvider {
|
||||
@Override
|
||||
public CastOptions getCastOptions(@NonNull Context context) {
|
||||
return new CastOptions.Builder()
|
||||
.setReceiverApplicationId(Helper.CAST_ID)
|
||||
.build();
|
||||
}
|
||||
@Override
|
||||
public List<SessionProvider> getAdditionalSessionProviders(@NonNull Context context) {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/castMiniController"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/black"
|
||||
android:visibility="gone">
|
||||
|
||||
<fragment
|
||||
class="com.google.android.gms.cast.framework.media.widget.MiniControllerFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/media_route_button"
|
||||
android:title="@string/cast"
|
||||
app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
|
||||
app:showAsAction="always" />
|
||||
</menu>
|
|
@ -0,0 +1,278 @@
|
|||
package app.fedilab.fedilabtube;
|
||||
/* Copyright 2021 Thomas Schneider
|
||||
*
|
||||
* This file is a part of TubeLab
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentStatePagerAdapter;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import com.android.billingclient.api.AcknowledgePurchaseParams;
|
||||
import com.android.billingclient.api.BillingClient;
|
||||
import com.android.billingclient.api.BillingClientStateListener;
|
||||
import com.android.billingclient.api.BillingResult;
|
||||
import com.android.billingclient.api.ConsumeParams;
|
||||
import com.android.billingclient.api.ConsumeResponseListener;
|
||||
import com.android.billingclient.api.Purchase;
|
||||
import com.android.billingclient.api.PurchasesUpdatedListener;
|
||||
import com.android.billingclient.api.SkuDetailsParams;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import app.fedilab.fedilabtube.databinding.ActivityDonationBinding;
|
||||
|
||||
import app.fedilab.fedilabtube.fragment.MySubscriptionDonationsFragment;
|
||||
import app.fedilab.fedilabtube.fragment.DonationsFragment;
|
||||
|
||||
|
||||
public class DonationActivity extends AppCompatActivity implements PurchasesUpdatedListener {
|
||||
|
||||
|
||||
DonationsFragment donationsFragment;
|
||||
DonationsFragment subscriptionDonationsFragment;
|
||||
MySubscriptionDonationsFragment mySubscriptionDonationsFragment;
|
||||
private ActivityDonationBinding binding;
|
||||
private BillingClient billingClient;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = ActivityDonationBinding.inflate(getLayoutInflater());
|
||||
View view = binding.getRoot();
|
||||
setContentView(view);
|
||||
billingClient = BillingClient.newBuilder(this)
|
||||
.setListener(this)
|
||||
.enablePendingPurchases()
|
||||
.build();
|
||||
billingClient.startConnection(new BillingClientStateListener() {
|
||||
@Override
|
||||
public void onBillingSetupFinished(@NotNull BillingResult billingResult) {
|
||||
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
|
||||
// The BillingClient is ready. You can query purchases here.
|
||||
donationsFragment.initialized(billingClient);
|
||||
subscriptionDonationsFragment.initialized(billingClient);
|
||||
|
||||
List<Purchase> purchases = queryPurchases();
|
||||
if (purchases != null) {
|
||||
for (Purchase purchase : purchases) {
|
||||
if (!purchase.isAutoRenewing()) {
|
||||
ConsumeParams consumeParams =
|
||||
ConsumeParams.newBuilder()
|
||||
.setPurchaseToken(purchase.getPurchaseToken())
|
||||
.build();
|
||||
|
||||
ConsumeResponseListener listener = (billingResult1, purchaseToken) -> {
|
||||
//noinspection StatementWithEmptyBody
|
||||
if (billingResult1.getResponseCode() == BillingClient.BillingResponseCode.OK) {
|
||||
// Handle the success of the consume operation.
|
||||
}
|
||||
};
|
||||
billingClient.consumeAsync(consumeParams, listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBillingServiceDisconnected() {
|
||||
// Try to restart the connection on the next request to
|
||||
// Google Play by calling the startConnection() method.
|
||||
}
|
||||
});
|
||||
if (getSupportActionBar() != null)
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
donationsFragment = new DonationsFragment();
|
||||
Bundle bundle1 = new Bundle();
|
||||
bundle1.putSerializable("isSubscriptions", false);
|
||||
donationsFragment.setArguments(bundle1);
|
||||
|
||||
|
||||
subscriptionDonationsFragment = new DonationsFragment();
|
||||
Bundle bundle2 = new Bundle();
|
||||
bundle2.putSerializable("isSubscriptions", true);
|
||||
subscriptionDonationsFragment.setArguments(bundle2);
|
||||
|
||||
mySubscriptionDonationsFragment = new MySubscriptionDonationsFragment();
|
||||
|
||||
binding.tablayout.addTab(binding.tablayout.newTab().setText(getString(R.string.one_time)));
|
||||
binding.tablayout.addTab(binding.tablayout.newTab().setText(getString(R.string.subscriptions)));
|
||||
binding.tablayout.addTab(binding.tablayout.newTab().setText(getString(R.string.my_subscriptions)));
|
||||
binding.viewpager.setOffscreenPageLimit(3);
|
||||
|
||||
PagerAdapter mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
|
||||
binding.viewpager.setAdapter(mPagerAdapter);
|
||||
binding.viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
TabLayout.Tab tab = binding.tablayout.getTabAt(position);
|
||||
if (tab != null)
|
||||
tab.select();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
binding.tablayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
|
||||
@Override
|
||||
public void onTabSelected(TabLayout.Tab tab) {
|
||||
binding.viewpager.setCurrentItem(tab.getPosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabUnselected(TabLayout.Tab tab) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabReselected(TabLayout.Tab tab) {
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private List<Purchase> queryPurchases() {
|
||||
Purchase.PurchasesResult purchasesResult = billingClient.queryPurchases(BillingClient.SkuType.SUBS);
|
||||
List<Purchase> purchases = purchasesResult.getPurchasesList();
|
||||
List<String> isSubscriptions = new ArrayList<>();
|
||||
HashMap<String, Purchase> map = new HashMap<>();
|
||||
if (purchases != null) {
|
||||
for (Purchase purchase : purchases) {
|
||||
try {
|
||||
if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) {
|
||||
JSONObject purchaseJson = new JSONObject(purchase.getOriginalJson());
|
||||
String productId = purchaseJson.getString("productId");
|
||||
isSubscriptions.add(productId);
|
||||
map.put(productId, purchase);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
SkuDetailsParams.Builder paramsSub = SkuDetailsParams.newBuilder();
|
||||
paramsSub.setSkusList(isSubscriptions).setType(BillingClient.SkuType.SUBS);
|
||||
billingClient.querySkuDetailsAsync(paramsSub.build(),
|
||||
(billingResult2, skuDetailsList) -> mySubscriptionDonationsFragment.initialized(skuDetailsList, map, billingClient));
|
||||
} else {
|
||||
mySubscriptionDonationsFragment.initialized(new ArrayList<>(), map, billingClient);
|
||||
}
|
||||
return purchases;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List<Purchase> purchases) {
|
||||
String message;
|
||||
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK
|
||||
&& purchases != null) {
|
||||
for (Purchase purchase : purchases) {
|
||||
if (!purchase.isAutoRenewing()) {
|
||||
ConsumeParams consumeParams =
|
||||
ConsumeParams.newBuilder()
|
||||
.setPurchaseToken(purchase.getPurchaseToken())
|
||||
.build();
|
||||
|
||||
ConsumeResponseListener listener = (billingResult1, purchaseToken) -> {
|
||||
};
|
||||
billingClient.consumeAsync(consumeParams, listener);
|
||||
} else {
|
||||
if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) {
|
||||
if (!purchase.isAcknowledged()) {
|
||||
AcknowledgePurchaseParams acknowledgePurchaseParams =
|
||||
AcknowledgePurchaseParams.newBuilder()
|
||||
.setPurchaseToken(purchase.getPurchaseToken())
|
||||
.build();
|
||||
billingClient.acknowledgePurchase(acknowledgePurchaseParams, b -> {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
queryPurchases();
|
||||
}
|
||||
}
|
||||
message = getString(R.string.donation_succeeded_null);
|
||||
} else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED) {
|
||||
message = getString(R.string.donation_cancelled);
|
||||
} else {
|
||||
message = getString(R.string.toast_error);
|
||||
}
|
||||
View parentLayout = findViewById(android.R.id.content);
|
||||
Snackbar snackbar = Snackbar.make(parentLayout, message, Snackbar.LENGTH_INDEFINITE);
|
||||
snackbar.setAction(R.string.close, view -> snackbar.dismiss());
|
||||
snackbar.show();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pager adapter for the 2 fragments
|
||||
*/
|
||||
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
|
||||
|
||||
ScreenSlidePagerAdapter(FragmentManager fm) {
|
||||
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
if (position == 0) {
|
||||
return donationsFragment;
|
||||
} else if (position == 1) {
|
||||
return subscriptionDonationsFragment;
|
||||
} else {
|
||||
return mySubscriptionDonationsFragment;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package app.fedilab.fedilabtube.drawable;
|
||||
/* Copyright 2021 Thomas Schneider
|
||||
*
|
||||
* This file is a part of TubeLab
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.billingclient.api.BillingClient;
|
||||
import com.android.billingclient.api.BillingFlowParams;
|
||||
import com.android.billingclient.api.SkuDetails;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import app.fedilab.fedilabtube.DonationActivity;
|
||||
import app.fedilab.fedilabtube.R;
|
||||
import app.fedilab.fedilabtube.databinding.DrawerDonationBinding;
|
||||
|
||||
|
||||
public class DonationButtonAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
|
||||
private final List<SkuDetails> skuDetails;
|
||||
private final BillingClient billingClient;
|
||||
private Context context;
|
||||
private final boolean isSubscription;
|
||||
|
||||
public DonationButtonAdapter(List<SkuDetails> skuDetails, BillingClient billingClient, boolean subscription) {
|
||||
this.isSubscription = subscription;
|
||||
this.skuDetails = skuDetails;
|
||||
this.billingClient = billingClient;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
context = parent.getContext();
|
||||
DrawerDonationBinding itemBinding = DrawerDonationBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
|
||||
return new ViewHolder(itemBinding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
|
||||
final ViewHolder holder = (ViewHolder) viewHolder;
|
||||
SkuDetails skuDetail = skuDetails.get(position);
|
||||
String currency = skuDetail.getPriceCurrencyCode();
|
||||
String price = skuDetail.getPrice();
|
||||
if (isSubscription) {
|
||||
holder.binding.buttonDonation.setText(String.format(Locale.getDefault(), "%s %s / %s", price, currency, context.getString(R.string.month)));
|
||||
} else {
|
||||
holder.binding.buttonDonation.setText(String.format(Locale.getDefault(), "%s %s", price, currency));
|
||||
}
|
||||
|
||||
holder.binding.buttonDonation.setOnClickListener(v -> {
|
||||
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
|
||||
.setSkuDetails(skuDetail)
|
||||
.build();
|
||||
billingClient.launchBillingFlow((DonationActivity) context, billingFlowParams);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return skuDetails.size();
|
||||
}
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
DrawerDonationBinding binding;
|
||||
|
||||
ViewHolder(DrawerDonationBinding itemView) {
|
||||
super(itemView.getRoot());
|
||||
binding = itemView;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
package app.fedilab.fedilabtube.drawable;
|
||||
/* Copyright 2021 Thomas Schneider
|
||||
*
|
||||
* This file is a part of TubeLab
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.billingclient.api.BillingClient;
|
||||
import com.android.billingclient.api.ConsumeParams;
|
||||
import com.android.billingclient.api.ConsumeResponseListener;
|
||||
import com.android.billingclient.api.Purchase;
|
||||
import com.android.billingclient.api.SkuDetails;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import app.fedilab.fedilabtube.R;
|
||||
import app.fedilab.fedilabtube.databinding.DrawerMyDonationBinding;
|
||||
import es.dmoral.toasty.Toasty;
|
||||
|
||||
|
||||
public class DonationHistoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
|
||||
private final List<SkuDetails> skuDetailsList;
|
||||
private final BillingClient billingClient;
|
||||
private Context context;
|
||||
private final HashMap<String, Purchase> map;
|
||||
|
||||
public DonationHistoryAdapter(List<SkuDetails> SkuDetailsList, HashMap<String, Purchase> map, BillingClient billingClient) {
|
||||
this.skuDetailsList = SkuDetailsList;
|
||||
this.billingClient = billingClient;
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
context = parent.getContext();
|
||||
DrawerMyDonationBinding itemBinding = DrawerMyDonationBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
|
||||
return new ViewHolder(itemBinding);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
|
||||
final ViewHolder holder = (ViewHolder) viewHolder;
|
||||
SkuDetails skuDetails = skuDetailsList.get(position);
|
||||
holder.binding.productTitle.setText(skuDetails.getTitle());
|
||||
holder.binding.productName.setText(skuDetails.getDescription());
|
||||
holder.binding.productInfo.setText(skuDetails.getOriginalPrice());
|
||||
|
||||
holder.binding.cancelDonation.setOnClickListener(v -> {
|
||||
|
||||
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context);
|
||||
dialogBuilder.setMessage(R.string.cancel_subscription_confirm);
|
||||
|
||||
dialogBuilder.setPositiveButton(R.string.cancel_subscription, (dialog, id) -> {
|
||||
JSONObject skudetailsJson;
|
||||
try {
|
||||
skudetailsJson = new JSONObject(skuDetails.getOriginalJson());
|
||||
String productId = skudetailsJson.getString("productId");
|
||||
if (map.containsKey(productId)) {
|
||||
Purchase purchase = map.get(productId);
|
||||
if (purchase != null) {
|
||||
ConsumeParams consumeParams =
|
||||
ConsumeParams.newBuilder()
|
||||
.setPurchaseToken(purchase.getPurchaseToken())
|
||||
.build();
|
||||
if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) {
|
||||
ConsumeResponseListener listener = (billingResult1, purchaseToken) -> {
|
||||
if (billingResult1.getResponseCode() == BillingClient.BillingResponseCode.OK) {
|
||||
Toasty.success(context, context.getString(R.string.subscription_cancelled), Toasty.LENGTH_LONG).show();
|
||||
}
|
||||
skuDetailsList.remove(skuDetails);
|
||||
notifyDataSetChanged();
|
||||
};
|
||||
billingClient.consumeAsync(consumeParams, listener);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
dialog.dismiss();
|
||||
});
|
||||
dialogBuilder.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss());
|
||||
AlertDialog alertDialogLogoutAccount = dialogBuilder.create();
|
||||
alertDialogLogoutAccount.show();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return skuDetailsList.size();
|
||||
}
|
||||
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
DrawerMyDonationBinding binding;
|
||||
|
||||
ViewHolder(DrawerMyDonationBinding itemView) {
|
||||
super(itemView.getRoot());
|
||||
binding = itemView;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
package app.fedilab.fedilabtube.fragment;
|
||||
/* Copyright 2021 Thomas Schneider
|
||||
*
|
||||
* This file is a part of TubeLab
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import com.android.billingclient.api.BillingClient;
|
||||
import com.android.billingclient.api.SkuDetailsParams;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import app.fedilab.fedilabtube.R;
|
||||
import app.fedilab.fedilabtube.databinding.FragmentDonationsBinding;
|
||||
import app.fedilab.fedilabtube.drawable.DonationButtonAdapter;
|
||||
|
||||
|
||||
public class DonationsFragment extends Fragment {
|
||||
|
||||
public static final String[] donations = {"1", "2", "5", "10"};
|
||||
private FragmentDonationsBinding binding;
|
||||
private View rootView;
|
||||
private Context context;
|
||||
private boolean isSubscriptions;
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
binding = FragmentDonationsBinding.inflate(LayoutInflater.from(context));
|
||||
rootView = binding.getRoot();
|
||||
context = getContext();
|
||||
Bundle bundle = this.getArguments();
|
||||
if (bundle != null) {
|
||||
isSubscriptions = bundle.getBoolean("isSubscriptions", false);
|
||||
}
|
||||
int donationText;
|
||||
if (isSubscriptions) {
|
||||
donationText = R.string.recurrent_donation_text;
|
||||
} else {
|
||||
donationText = R.string.one_time_donation_text;
|
||||
}
|
||||
binding.donationText.setText(donationText);
|
||||
binding.loader.setVisibility(View.VISIBLE);
|
||||
binding.lvProducts.setVisibility(View.GONE);
|
||||
return rootView;
|
||||
}
|
||||
|
||||
public void initialized(BillingClient bc) {
|
||||
|
||||
|
||||
List<String> donationsList = new ArrayList<>();
|
||||
for (String val : donations) {
|
||||
donationsList.add("tubelab_donation_" + val + (isSubscriptions ? "_s" : ""));
|
||||
}
|
||||
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
|
||||
if (isSubscriptions) {
|
||||
params.setSkusList(donationsList).setType(BillingClient.SkuType.SUBS);
|
||||
} else {
|
||||
params.setSkusList(donationsList).setType(BillingClient.SkuType.INAPP);
|
||||
}
|
||||
bc.querySkuDetailsAsync(params.build(),
|
||||
(billingResult, skuDetailsList) -> {
|
||||
binding.loader.setVisibility(View.GONE);
|
||||
binding.lvProducts.setVisibility(View.VISIBLE);
|
||||
if (skuDetailsList != null) {
|
||||
Collections.sort(skuDetailsList, (obj1, obj2) -> obj1.getPrice().compareTo(obj2.getPrice()));
|
||||
}
|
||||
DonationButtonAdapter donationButtonAdapter = new DonationButtonAdapter(skuDetailsList, bc, isSubscriptions);
|
||||
binding.lvProducts.setAdapter(donationButtonAdapter);
|
||||
binding.lvProducts.setLayoutManager(new LinearLayoutManager(context));
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
rootView = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle saveInstance) {
|
||||
super.onCreate(saveInstance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(@NonNull Context context) {
|
||||
super.onAttach(context);
|
||||
this.context = context;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package app.fedilab.fedilabtube.fragment;
|
||||
/* Copyright 2021 Thomas Schneider
|
||||
*
|
||||
* This file is a part of TubeLab
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import com.android.billingclient.api.BillingClient;
|
||||
import com.android.billingclient.api.Purchase;
|
||||
import com.android.billingclient.api.SkuDetails;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import app.fedilab.fedilabtube.databinding.FragmentMyDonationsBinding;
|
||||
import app.fedilab.fedilabtube.drawable.DonationHistoryAdapter;
|
||||
|
||||
public class MySubscriptionDonationsFragment extends Fragment {
|
||||
|
||||
private FragmentMyDonationsBinding binding;
|
||||
private View rootView;
|
||||
private Context context;
|
||||
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
binding = FragmentMyDonationsBinding.inflate(LayoutInflater.from(context));
|
||||
rootView = binding.getRoot();
|
||||
context = getContext();
|
||||
binding.loader.setVisibility(View.VISIBLE);
|
||||
binding.lvPurchases.setVisibility(View.GONE);
|
||||
return rootView;
|
||||
}
|
||||
|
||||
public void initialized(List<SkuDetails> skuDetailsList, HashMap<String, Purchase> map, BillingClient bc) {
|
||||
binding.loader.setVisibility(View.GONE);
|
||||
binding.lvPurchases.setVisibility(View.VISIBLE);
|
||||
|
||||
DonationHistoryAdapter donationHistoryAdapter = new DonationHistoryAdapter(skuDetailsList, map, bc);
|
||||
binding.lvPurchases.setAdapter(donationHistoryAdapter);
|
||||
binding.lvPurchases.setLayoutManager(new LinearLayoutManager(context));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
rootView = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle saveInstance) {
|
||||
super.onCreate(saveInstance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(@NonNull Context context) {
|
||||
super.onAttach(context);
|
||||
this.context = context;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Copyright 2021 Thomas Schneider
|
||||
|
||||
This file is a part of TubeLab
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
see <http://www.gnu.org/licenses>.
|
||||
-->
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context=".activities.ShowChannelActivity">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
app:theme="@style/ThemeOverlay.AppCompat.ActionBar">
|
||||
|
||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
app:contentScrim="?attr/colorPrimary"
|
||||
app:expandedTitleMarginEnd="64dp"
|
||||
app:expandedTitleMarginStart="48dp"
|
||||
app:layout_scrollFlags="scroll|exitUntilCollapsed">
|
||||
|
||||
|
||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tablayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:tabGravity="fill"
|
||||
app:tabMode="fixed"
|
||||
app:tabSelectedTextColor="?colorAccent"
|
||||
app:tabTextColor="@android:color/white" />
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
android:id="@+id/viewpager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_donation"
|
||||
style="@style/Widget.AppCompat.Button.Colored"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:paddingStart="40dp"
|
||||
android:paddingTop="15dp"
|
||||
android:paddingEnd="40dp"
|
||||
android:paddingBottom="15dp"
|
||||
android:textSize="25sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
android:layout_margin="10dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/product_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/cancel_donation"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/product_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/cancel_donation"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/product_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/product_info"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/cancel_donation"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/product_name" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/cancel_donation"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/cancel"
|
||||
android:src="@drawable/ic_baseline_delete_24"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Copyright 2020 Thomas Schneider
|
||||
Copyright 2021 Thomas Schneider
|
||||
|
||||
This file is a part of TubeLab
|
||||
|
||||
|
@ -19,28 +19,27 @@
|
|||
android:layout_height="match_parent"
|
||||
android:paddingLeft="@dimen/fab_margin"
|
||||
android:paddingRight="@dimen/fab_margin">
|
||||
<!-- Listview Peertube bookmark -->
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/lv_status"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:scrollbars="none" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/no_action"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone">
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="20dp"
|
||||
android:gravity="center"
|
||||
android:padding="10dp"
|
||||
android:text="@string/bookmark_peertube_empty"
|
||||
android:textSize="25sp" />
|
||||
</RelativeLayout>
|
||||
android:id="@+id/donation_text" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/lv_products"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:divider="@null"
|
||||
android:scrollbars="none" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Main Loader -->
|
||||
<RelativeLayout
|
||||
android:id="@+id/loader"
|
||||
|
@ -49,10 +48,12 @@
|
|||
android:gravity="center"
|
||||
android:visibility="gone">
|
||||
|
||||
<ProgressBar
|
||||
<com.github.ybq.android.spinkit.SpinKitView xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
style="@style/progress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:indeterminate="true" />
|
||||
android:layout_gravity="center"
|
||||
app:SpinKit_Color="?colorAccent" />
|
||||
</RelativeLayout>
|
||||
</RelativeLayout>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Copyright 2020 Thomas Schneider
|
||||
Copyright 2021 Thomas Schneider
|
||||
|
||||
This file is a part of TubeLab
|
||||
|
||||
|
@ -19,38 +19,27 @@
|
|||
android:layout_height="match_parent"
|
||||
android:paddingLeft="@dimen/fab_margin"
|
||||
android:paddingRight="@dimen/fab_margin">
|
||||
<!-- Listview Accounts -->
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/swipeContainer"
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="20dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/donations_description" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/lv_accounts"
|
||||
android:id="@+id/lv_purchases"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:divider="@null"
|
||||
android:scrollbars="none" />
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/no_action"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/no_action_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:padding="10dp"
|
||||
android:text="@string/no_channels"
|
||||
android:textSize="25sp"
|
||||
android:textStyle="italic|bold"
|
||||
android:typeface="serif" />
|
||||
</RelativeLayout>
|
||||
<!-- Main Loader -->
|
||||
<RelativeLayout
|
||||
android:id="@+id/loader"
|
||||
|
@ -59,25 +48,12 @@
|
|||
android:gravity="center"
|
||||
android:visibility="gone">
|
||||
|
||||
<ProgressBar
|
||||
<com.github.ybq.android.spinkit.SpinKitView xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
style="@style/progress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:indeterminate="true" />
|
||||
</RelativeLayout>
|
||||
<!-- Loader for next accounts -->
|
||||
<RelativeLayout
|
||||
android:id="@+id/loading_next_accounts"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
android:gravity="bottom|center_horizontal"
|
||||
android:visibility="gone">
|
||||
|
||||
<ProgressBar
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:indeterminate="true" />
|
||||
android:layout_gravity="center"
|
||||
app:SpinKit_Color="?colorAccent" />
|
||||
</RelativeLayout>
|
||||
</RelativeLayout>
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="app.fedilab.fedilabtube">
|
||||
|
||||
<uses-permission android:name="com.android.vending.BILLING" />
|
||||
<application
|
||||
android:name=".FedilabTube"
|
||||
android:allowBackup="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:replace="android:allowBackup">
|
||||
|
||||
<activity
|
||||
android:name=".activities.PeertubeActivity"
|
||||
android:exported="true"
|
||||
tools:node="merge">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<!-- The app is a good candidate for URL in https://domain.name/videos/watch/xxxxx-->
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/videos/watch/"
|
||||
android:scheme="https" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activities.PeertubeActivity" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".expandedcontrols.ExpandedControlsActivity"
|
||||
android:theme="@style/AppThemeNoActionBar"
|
||||
|
||||
/>
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
|
||||
android:value="app.fedilab.fedilabtube.provider.CastOptionsProvider" />
|
||||
|
||||
<activity
|
||||
android:name=".DonationActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/support_the_app"
|
||||
android:windowSoftInputMode="stateAlwaysHidden" />
|
||||
</application>
|
||||
</manifest>
|
|
@ -5,19 +5,22 @@
|
|||
|
||||
|
||||
<!--
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
tools:ignore="ScopedStorage" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
<application
|
||||
android:name=".FedilabTube"
|
||||
android:allowBackup="false"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
|
@ -25,9 +28,11 @@
|
|||
android:theme="@style/AppTheme"
|
||||
tools:replace="android:allowBackup">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:name=".activities.MainActivity"
|
||||
android:theme="@style/AppThemeNoActionBar"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/app_name">
|
||||
android:exported="true">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
|
@ -36,84 +41,138 @@
|
|||
|
||||
|
||||
<activity
|
||||
android:name=".PeertubeActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:label="@string/app_name" />
|
||||
android:name=".activities.PeertubeActivity"
|
||||
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
|
||||
android:launchMode="singleTask"
|
||||
android:resizeableActivity="true"
|
||||
android:supportsPictureInPicture="true"
|
||||
tools:targetApi="n" />
|
||||
<activity
|
||||
android:name=".PeertubeEditUploadActivity"
|
||||
android:name=".activities.PeertubeEditUploadActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/app_name"
|
||||
android:exported="false"
|
||||
android:windowSoftInputMode="stateAlwaysHidden" />
|
||||
|
||||
<activity
|
||||
android:name=".ShowAccountActivity"
|
||||
android:name=".activities.ShowChannelActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/app_name"
|
||||
android:windowSoftInputMode="stateAlwaysHidden" />
|
||||
<activity
|
||||
android:name=".AccountActivity"
|
||||
android:name=".activities.ShowAccountActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/app_name"
|
||||
android:windowSoftInputMode="stateAlwaysHidden"/>
|
||||
<activity
|
||||
android:name=".SearchActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/app_name"
|
||||
android:windowSoftInputMode="stateAlwaysHidden" />
|
||||
<activity
|
||||
android:name=".AllPlaylistsActivity"
|
||||
android:name=".activities.AccountActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/app_name"
|
||||
android:windowSoftInputMode="stateAlwaysHidden" />
|
||||
<activity
|
||||
android:name=".PlaylistsActivity"
|
||||
android:name=".activities.MyAccountActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/app_name"
|
||||
android:windowSoftInputMode="stateAlwaysHidden" />
|
||||
<activity
|
||||
android:name=".MyVideosActivity"
|
||||
android:name=".activities.SearchActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/app_name"
|
||||
android:windowSoftInputMode="stateAlwaysHidden" />
|
||||
<activity
|
||||
android:name=".WebviewActivity"
|
||||
android:name=".activities.AllPlaylistsActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:windowSoftInputMode="stateAlwaysHidden" />
|
||||
<activity
|
||||
android:name=".activities.AllLocalPlaylistsActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:windowSoftInputMode="stateAlwaysHidden" />
|
||||
<activity
|
||||
android:name=".activities.InstancePickerActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:windowSoftInputMode="stateAlwaysHidden" />
|
||||
|
||||
<activity
|
||||
android:name=".activities.PlaylistsActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:windowSoftInputMode="stateAlwaysHidden" />
|
||||
<activity
|
||||
android:name=".activities.LocalPlaylistsActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:windowSoftInputMode="stateAlwaysHidden" />
|
||||
<activity
|
||||
android:name=".activities.VideosTimelineActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:windowSoftInputMode="stateAlwaysHidden" />
|
||||
<activity
|
||||
android:name=".activities.SepiaSearchActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/sepia_search"
|
||||
android:windowSoftInputMode="stateAlwaysHidden" />
|
||||
<activity
|
||||
android:name=".activities.ManageInstancesActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/instances_picker"
|
||||
android:windowSoftInputMode="stateAlwaysHidden" />
|
||||
<activity
|
||||
android:name=".activities.WebviewActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize" />
|
||||
<activity
|
||||
android:name=".activities.WebviewConnectActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize" />
|
||||
<activity
|
||||
android:name=".activities.MastodonWebviewConnectActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:label="@string/app_name" />
|
||||
/>
|
||||
<activity
|
||||
android:name=".WebviewConnectActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:label="@string/app_name" />
|
||||
<activity
|
||||
android:name=".LoginActivity"
|
||||
android:name=".activities.LoginActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/app_name"
|
||||
android:windowSoftInputMode="stateAlwaysHidden">
|
||||
android:windowSoftInputMode="stateAlwaysHidden"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data
|
||||
android:host="backtotubelab"
|
||||
android:scheme="tubelab" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".SettingsActivity"
|
||||
android:name=".activities.SettingsActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/settings"
|
||||
android:windowSoftInputMode="stateAlwaysHidden">
|
||||
</activity>
|
||||
android:windowSoftInputMode="stateAlwaysHidden" />
|
||||
<activity
|
||||
android:name=".PeertubeRegisterActivity"
|
||||
android:name=".activities.PeertubeRegisterActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/register_account"
|
||||
android:windowSoftInputMode="stateAlwaysHidden" />
|
||||
<activity
|
||||
android:name=".PeertubeUploadActivity"
|
||||
android:name=".activities.PeertubeUploadActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/upload_video"
|
||||
android:windowSoftInputMode="stateAlwaysHidden" />
|
||||
<activity
|
||||
android:name=".activities.AboutActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/about_the_app"
|
||||
android:windowSoftInputMode="stateAlwaysHidden" />
|
||||
|
||||
<service
|
||||
android:name=".services.RetrieveInfoService"
|
||||
android:exported="false" />
|
||||
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileProvider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_paths" />
|
||||
</provider>
|
||||
|
||||
|
||||
|
||||
<receiver
|
||||
android:name=".services.PeertubeUploadReceiver"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="app.fedilab.fedilabtube.uploadservice.broadcast.status" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
</application>
|
||||
|
||||
</manifest>
|
|
@ -0,0 +1 @@
|
|||
{"1":"Music","2":"Films","3":"Vehicles","4":"Art","5":"Sports","6":"Travels","7":"Gaming","8":"People","9":"Comedy","10":"Entertainment","11":"News & Politics","12":"How To","13":"Education","14":"Activism","15":"Science & Technology","16":"Animals","17":"Kids","18":"Food"}
|
|
@ -0,0 +1 @@
|
|||
{"aa":"Afar","ab":"Abkhazian","af":"Afrikaans","ak":"Akan","am":"Amharic","ar":"Arabic","an":"Aragonese","ase":"American Sign Language","as":"Assamese","av":"Avaric","avk":"Kotava","ay":"Aymara","az":"Azerbaijani","ba":"Bashkir","bm":"Bambara","be":"Belarusian","bn":"Bengali","bfi":"British Sign Language","bi":"Bislama","bo":"Tibetan","bs":"Bosnian","br":"Breton","bg":"Bulgarian","bzs":"Brazilian Sign Language","ca":"Catalan","cs":"Czech","ch":"Chamorro","ce":"Chechen","cv":"Chuvash","kw":"Cornish","co":"Corsican","cr":"Cree","cse":"Czech Sign Language","csl":"Chinese Sign Language","cy":"Welsh","da":"Danish","de":"German","dv":"Dhivehi","dsl":"Danish Sign Language","dz":"Dzongkha","el":"Greek","en":"English","eo":"Esperanto","et":"Estonian","eu":"Basque","ee":"Ewe","fo":"Faroese","fa":"Persian","fj":"Fijian","fi":"Finnish","fr":"French","fy":"Western Frisian","fsl":"French Sign Language","ff":"Fulah","gd":"Scottish Gaelic","ga":"Irish","gl":"Galician","gv":"Manx","gn":"Guarani","gsg":"German Sign Language","gu":"Gujarati","ht":"Haitian","ha":"Hausa","sh":"Serbo-Croatian","he":"Hebrew","hz":"Herero","hi":"Hindi","ho":"Hiri Motu","hr":"Croatian","hu":"Hungarian","hy":"Armenian","ig":"Igbo","ii":"Sichuan Yi","iu":"Inuktitut","id":"Indonesian","ik":"Inupiaq","is":"Icelandic","it":"Italian","jv":"Javanese","jbo":"Lojban","ja":"Japanese","jsl":"Japanese Sign Language","kab":"Kabyle","kl":"Kalaallisut","kn":"Kannada","ks":"Kashmiri","ka":"Georgian","kr":"Kanuri","kk":"Kazakh","km":"Khmer","ki":"Kikuyu","rw":"Kinyarwanda","ky":"Kirghiz","kv":"Komi","kg":"Kongo","ko":"Korean","kj":"Kuanyama","ku":"Kurdish","lo":"Lao","la":"Latin","lv":"Latvian","li":"Limburgan","ln":"Lingala","lt":"Lithuanian","lb":"Luxembourgish","lu":"Luba-Katanga","lg":"Ganda","mh":"Marshallese","ml":"Malayalam","mr":"Marathi","mk":"Macedonian","mg":"Malagasy","mt":"Maltese","mn":"Mongolian","mi":"Maori","ms":"Malay (macrolanguage)","my":"Burmese","na":"Nauru","nv":"Navajo","nr":"South Ndebele","nd":"North Ndebele","ng":"Ndonga","ne":"Nepali (macrolanguage)","nl":"Dutch","nn":"Norwegian Nynorsk","nb":"Norwegian Bokmål","no":"Norwegian","ny":"Nyanja","oc":"Occitan","oj":"Ojibwa","or":"Oriya (macrolanguage)","om":"Oromo","os":"Ossetian","pa":"Panjabi","pks":"Pakistan Sign Language","pl":"Polish","pt":"Portuguese","ps":"Pushto","qu":"Quechua","rm":"Romansh","ro":"Romanian","rsl":"Russian Sign Language","rn":"Rundi","ru":"Russian","sg":"Sango","sdl":"Saudi Arabian Sign Language","sfs":"South African Sign Language","si":"Sinhala","sk":"Slovak","sl":"Slovenian","se":"Northern Sami","sm":"Samoan","sn":"Shona","sd":"Sindhi","so":"Somali","st":"Southern Sotho","es":"Spanish","sq":"Albanian","sc":"Sardinian","sr":"Serbian","ss":"Swati","su":"Sundanese","sw":"Swahili (macrolanguage)","sv":"Swedish","swl":"Swedish Sign Language","ty":"Tahitian","ta":"Tamil","tt":"Tatar","te":"Telugu","tg":"Tajik","tl":"Tagalog","th":"Thai","ti":"Tigrinya","tlh":"Klingon","to":"Tonga (Tonga Islands)","tn":"Tswana","ts":"Tsonga","tk":"Turkmen","tr":"Turkish","tw":"Twi","ug":"Uighur","uk":"Ukrainian","ur":"Urdu","uz":"Uzbek","ve":"Venda","vi":"Vietnamese","wa":"Walloon","wo":"Wolof","xh":"Xhosa","yi":"Yiddish","yo":"Yoruba","za":"Zhuang","zh":"Chinese","zu":"Zulu","zxx":"No linguistic content","zh-Hans":"Simplified Chinese","zh-Hant":"Traditional Chinese"}
|
Before Width: | Height: | Size: 16 KiB |
|
@ -1,256 +0,0 @@
|
|||
package app.fedilab.fedilabtube;
|
||||
/* Copyright 2020 Thomas Schneider
|
||||
*
|
||||
* This file is a part of TubeLab
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.os.Bundle;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.text.style.UnderlineSpan;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentStatePagerAdapter;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import app.fedilab.fedilabtube.client.entities.Account;
|
||||
import app.fedilab.fedilabtube.fragment.DisplayAccountsFragment;
|
||||
import app.fedilab.fedilabtube.fragment.DisplayNotificationsFragment;
|
||||
import app.fedilab.fedilabtube.helper.Helper;
|
||||
import app.fedilab.fedilabtube.sqlite.AccountDAO;
|
||||
import app.fedilab.fedilabtube.sqlite.Sqlite;
|
||||
import app.fedilab.fedilabtube.viewmodel.AccountsVM;
|
||||
|
||||
|
||||
public class AccountActivity extends AppCompatActivity {
|
||||
|
||||
|
||||
private ViewPager mPager;
|
||||
private TabLayout tabLayout;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
|
||||
setContentView(R.layout.activity_account);
|
||||
if (getSupportActionBar() != null)
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
|
||||
SpannableString content_create = new SpannableString(getString(R.string.join_peertube));
|
||||
content_create.setSpan(new UnderlineSpan(), 0, content_create.length(), 0);
|
||||
content_create.setSpan(new ForegroundColorSpan(ContextCompat.getColor(AccountActivity.this, R.color.colorAccent)), 0, content_create.length(),
|
||||
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
|
||||
|
||||
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
|
||||
SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
|
||||
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
|
||||
String instance = Helper.getLiveInstance(AccountActivity.this);
|
||||
|
||||
TextView instanceView = findViewById(R.id.instance);
|
||||
Account account = new AccountDAO(AccountActivity.this, db).getUniqAccount(userId, instance);
|
||||
if (account == null) {
|
||||
account = new AccountDAO(AccountActivity.this, db).getUniqAccount(userId, Helper.getPeertubeUrl(instance));
|
||||
}
|
||||
|
||||
|
||||
if (account == null) {
|
||||
Helper.logoutCurrentUser(AccountActivity.this, null);
|
||||
return;
|
||||
}
|
||||
|
||||
ImageView profile_picture = findViewById(R.id.profile_picture);
|
||||
TextView username = findViewById(R.id.username);
|
||||
TextView displayname = findViewById(R.id.displayname);
|
||||
|
||||
setTitle(String.format("@%s", account.getUsername()));
|
||||
|
||||
Helper.loadGiF(AccountActivity.this, account, profile_picture);
|
||||
username.setText(String.format("@%s", account.getUsername()));
|
||||
displayname.setText(account.getDisplay_name());
|
||||
|
||||
instanceView.setText(account.getInstance());
|
||||
|
||||
Button logout_button = findViewById(R.id.logout_button);
|
||||
Account finalAccount = account;
|
||||
logout_button.setOnClickListener(v -> {
|
||||
AlertDialog.Builder dialogBuilderLogoutAccount = new AlertDialog.Builder(AccountActivity.this);
|
||||
dialogBuilderLogoutAccount.setMessage(getString(R.string.logout_account_confirmation, finalAccount.getUsername()));
|
||||
dialogBuilderLogoutAccount.setPositiveButton(R.string.action_logout, (dialog, id) -> {
|
||||
Helper.logoutCurrentUser(AccountActivity.this, finalAccount);
|
||||
dialog.dismiss();
|
||||
});
|
||||
dialogBuilderLogoutAccount.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss());
|
||||
AlertDialog alertDialogLogoutAccount = dialogBuilderLogoutAccount.create();
|
||||
alertDialogLogoutAccount.show();
|
||||
});
|
||||
|
||||
Button settings = findViewById(R.id.settings);
|
||||
settings.setOnClickListener(v -> {
|
||||
Intent intent = new Intent(AccountActivity.this, SettingsActivity.class);
|
||||
startActivity(intent);
|
||||
});
|
||||
|
||||
tabLayout = findViewById(R.id.account_tabLayout);
|
||||
mPager = findViewById(R.id.account_viewpager);
|
||||
tabLayout.addTab(tabLayout.newTab().setText(getString(R.string.title_notifications)));
|
||||
tabLayout.addTab(tabLayout.newTab().setText(getString(R.string.title_muted)));
|
||||
tabLayout.addTab(tabLayout.newTab().setText(getString(R.string.title_channel)));
|
||||
|
||||
|
||||
mPager.setOffscreenPageLimit(3);
|
||||
|
||||
|
||||
mPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
TabLayout.Tab tab = tabLayout.getTabAt(position);
|
||||
if (tab != null)
|
||||
tab.select();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
|
||||
@Override
|
||||
public void onTabSelected(TabLayout.Tab tab) {
|
||||
mPager.setCurrentItem(tab.getPosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabUnselected(TabLayout.Tab tab) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabReselected(TabLayout.Tab tab) {
|
||||
Fragment fragment = null;
|
||||
if (mPager.getAdapter() != null)
|
||||
fragment = (Fragment) mPager.getAdapter().instantiateItem(mPager, tab.getPosition());
|
||||
switch (tab.getPosition()) {
|
||||
case 0:
|
||||
if (fragment != null) {
|
||||
DisplayNotificationsFragment displayNotificationsFragment = ((DisplayNotificationsFragment) fragment);
|
||||
displayNotificationsFragment.scrollToTop();
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
if (fragment != null) {
|
||||
DisplayAccountsFragment displayAccountsFragment = ((DisplayAccountsFragment) fragment);
|
||||
displayAccountsFragment.scrollToTop();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
PagerAdapter mPagerAdapter = new AccountsPagerAdapter(getSupportFragmentManager());
|
||||
mPager.setAdapter(mPagerAdapter);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pager adapter for three tabs (notifications, muted, blocked)
|
||||
*/
|
||||
private class AccountsPagerAdapter extends FragmentStatePagerAdapter {
|
||||
|
||||
AccountsPagerAdapter(FragmentManager fm) {
|
||||
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
Bundle bundle = new Bundle();
|
||||
switch (position) {
|
||||
case 1:
|
||||
case 2:
|
||||
DisplayAccountsFragment displayAccountsFragment = new DisplayAccountsFragment();
|
||||
if (position == 1) {
|
||||
bundle.putSerializable("accountFetch", AccountsVM.accountFetch.MUTED);
|
||||
} else {
|
||||
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
|
||||
SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
|
||||
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
|
||||
String instance = Helper.getLiveInstance(AccountActivity.this);
|
||||
Account account = new AccountDAO(AccountActivity.this, db).getUniqAccount(userId, instance);
|
||||
bundle.putString("name", account.getUsername() + "@" + account.getInstance());
|
||||
bundle.putSerializable("accountFetch", AccountsVM.accountFetch.CHANNEL);
|
||||
}
|
||||
displayAccountsFragment.setArguments(bundle);
|
||||
return displayAccountsFragment;
|
||||
default:
|
||||
return new DisplayNotificationsFragment();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package app.fedilab.fedilabtube;
|
||||
/* Copyright 2020 Thomas Schneider
|
||||
*
|
||||
* This file is a part of TubeLab
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.multidex.MultiDex;
|
||||
import androidx.multidex.MultiDexApplication;
|
||||
|
||||
import net.gotev.uploadservice.UploadServiceConfig;
|
||||
import net.gotev.uploadservice.observer.request.GlobalRequestObserver;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import app.fedilab.fedilabtube.helper.Helper;
|
||||
import app.fedilab.fedilabtube.helper.ThemeHelper;
|
||||
import app.fedilab.fedilabtube.services.GlobalUploadObserver;
|
||||
import app.fedilab.fedilabtube.worker.WorkHelper;
|
||||
|
||||
public class BaseFedilabTube extends MultiDexApplication {
|
||||
|
||||
public static String UPLOAD_CHANNEL_ID = "upload_info_peertube";
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
|
||||
int interval = sharedpreferences.getInt(Helper.NOTIFICATION_INTERVAL, 60);
|
||||
|
||||
if (interval >= 15) {
|
||||
WorkHelper.fetchNotifications(this, interval);
|
||||
}
|
||||
createNotificationChannel();
|
||||
UploadServiceConfig.initialize(BaseFedilabTube.this, UPLOAD_CHANNEL_ID, true);
|
||||
|
||||
new GlobalRequestObserver(this, new GlobalUploadObserver());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context base) {
|
||||
super.attachBaseContext(base);
|
||||
|
||||
MultiDex.install(BaseFedilabTube.this);
|
||||
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
|
||||
int themePref = sharedpreferences.getInt(Helper.SET_THEME, BuildConfig.default_theme);
|
||||
ThemeHelper.switchTo(themePref);
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void createNotificationChannel() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannel channel = new NotificationChannel(UPLOAD_CHANNEL_ID,
|
||||
getString(R.string.notification_channel_name),
|
||||
NotificationManager.IMPORTANCE_LOW);
|
||||
channel.setSound(null, null);
|
||||
((NotificationManager) Objects.requireNonNull(getSystemService(Context.NOTIFICATION_SERVICE))).createNotificationChannel(channel);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,337 +0,0 @@
|
|||
package app.fedilab.fedilabtube;
|
||||
/* Copyright 2020 Thomas Schneider
|
||||
*
|
||||
* This file is a part of TubeLab
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.text.style.UnderlineSpan;
|
||||
import android.view.MenuItem;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
|
||||
import app.fedilab.fedilabtube.client.HttpsConnection;
|
||||
import app.fedilab.fedilabtube.helper.Helper;
|
||||
import es.dmoral.toasty.Toasty;
|
||||
|
||||
import static app.fedilab.fedilabtube.client.HttpsConnection.updateCredential;
|
||||
|
||||
|
||||
public class LoginActivity extends AppCompatActivity {
|
||||
|
||||
|
||||
//Peertube notification type
|
||||
public static int NEW_VIDEO_FROM_SUBSCRIPTION = 1;
|
||||
// public static int NEW_COMMENT_ON_MY_VIDEO = 2;
|
||||
// public static int NEW_VIDEO_ABUSE_FOR_MODERATORS = 3;
|
||||
public static int BLACKLIST_ON_MY_VIDEO = 4;
|
||||
public static int UNBLACKLIST_ON_MY_VIDEO = 5;
|
||||
public static int MY_VIDEO_PUBLISHED = 6;
|
||||
public static int MY_VIDEO_IMPORT_SUCCESS = 7;
|
||||
public static int MY_VIDEO_IMPORT_ERROR = 8;
|
||||
private static String client_id;
|
||||
private static String client_secret;
|
||||
private EditText login_uid;
|
||||
private EditText login_passwd;
|
||||
private Button connectionButton;
|
||||
private String actionToken;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
|
||||
setContentView(R.layout.activity_login);
|
||||
if (getSupportActionBar() != null)
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
TextView create_an_account_peertube = findViewById(R.id.create_an_account_peertube);
|
||||
|
||||
SpannableString content_create = new SpannableString(getString(R.string.join_peertube));
|
||||
content_create.setSpan(new UnderlineSpan(), 0, content_create.length(), 0);
|
||||
content_create.setSpan(new ForegroundColorSpan(ContextCompat.getColor(LoginActivity.this, R.color.colorAccent)), 0, content_create.length(),
|
||||
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
create_an_account_peertube.setText(content_create);
|
||||
|
||||
create_an_account_peertube.setOnClickListener(v -> {
|
||||
Intent mainActivity = new Intent(LoginActivity.this, PeertubeRegisterActivity.class);
|
||||
Bundle b = new Bundle();
|
||||
mainActivity.putExtras(b);
|
||||
startActivity(mainActivity);
|
||||
});
|
||||
|
||||
|
||||
login_uid = findViewById(R.id.login_uid);
|
||||
login_passwd = findViewById(R.id.login_passwd);
|
||||
|
||||
if (Helper.isTablet(LoginActivity.this)) {
|
||||
TextInputLayout login_uid_container = findViewById(R.id.login_uid_container);
|
||||
ViewGroup.LayoutParams layoutParamsU = login_uid_container.getLayoutParams();
|
||||
layoutParamsU.width = (int) Helper.convertDpToPixel(300, LoginActivity.this);
|
||||
login_uid_container.setLayoutParams(layoutParamsU);
|
||||
|
||||
TextInputLayout login_passwd_container = findViewById(R.id.login_passwd_container);
|
||||
ViewGroup.LayoutParams layoutParamsP = login_passwd_container.getLayoutParams();
|
||||
layoutParamsP.width = (int) Helper.convertDpToPixel(300, LoginActivity.this);
|
||||
login_passwd_container.setLayoutParams(layoutParamsP);
|
||||
}
|
||||
|
||||
|
||||
connectionButton = findViewById(R.id.login_button);
|
||||
|
||||
login_uid.setOnFocusChangeListener((v, hasFocus) -> {
|
||||
if (!hasFocus) {
|
||||
if (android.util.Patterns.EMAIL_ADDRESS.matcher(login_uid.getText().toString().trim()).matches()) {
|
||||
String[] emailArray = login_uid.getText().toString().split("@");
|
||||
if (emailArray.length > 1 && Arrays.asList(Helper.openid).contains(emailArray[1])) {
|
||||
connectionButton.callOnClick();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
connectionButton.setOnClickListener(v -> {
|
||||
|
||||
if (!android.util.Patterns.EMAIL_ADDRESS.matcher(login_uid.getText().toString().trim()).matches()) {
|
||||
Toasty.error(LoginActivity.this, getString(R.string.email_error)).show();
|
||||
return;
|
||||
}
|
||||
String[] emailArray = login_uid.getText().toString().split("@");
|
||||
if (emailArray.length > 1 && !Arrays.asList(Helper.valideEmails).contains(emailArray[1])) {
|
||||
Toasty.error(LoginActivity.this, getString(R.string.email_error_domain, emailArray[1])).show();
|
||||
return;
|
||||
}
|
||||
String host = emailArray[1];
|
||||
String instance = Helper.getPeertubeUrl(host);
|
||||
final HashMap<String, String> parameters = new HashMap<>();
|
||||
connectionButton.setEnabled(false);
|
||||
|
||||
try {
|
||||
instance = URLEncoder.encode(instance, "utf-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
Toasty.error(LoginActivity.this, getString(R.string.client_error), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
|
||||
if (Arrays.asList(Helper.openid).contains(host)) {
|
||||
String finalInstance = instance;
|
||||
new Thread(() -> {
|
||||
try {
|
||||
actionToken = "/api/v1/oauth-clients/local";
|
||||
String response = new HttpsConnection(LoginActivity.this).get("https://" + finalInstance + actionToken, 30, null, null);
|
||||
if (response == null) {
|
||||
runOnUiThread(() -> {
|
||||
connectionButton.setEnabled(true);
|
||||
Toasty.error(LoginActivity.this, getString(R.string.client_error), Toast.LENGTH_LONG).show();
|
||||
});
|
||||
return;
|
||||
}
|
||||
JSONObject resobj;
|
||||
resobj = new JSONObject(response);
|
||||
client_id = resobj.get(Helper.CLIENT_ID).toString();
|
||||
client_secret = resobj.get(Helper.CLIENT_SECRET).toString();
|
||||
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = sharedpreferences.edit();
|
||||
editor.putString(Helper.CLIENT_ID, client_id);
|
||||
editor.putString(Helper.CLIENT_SECRET, client_secret);
|
||||
editor.apply();
|
||||
parameters.clear();
|
||||
parameters.put(Helper.CLIENT_ID, sharedpreferences.getString(Helper.CLIENT_ID, null));
|
||||
parameters.put(Helper.CLIENT_SECRET, sharedpreferences.getString(Helper.CLIENT_SECRET, null));
|
||||
Intent intent = new Intent(LoginActivity.this, WebviewConnectActivity.class);
|
||||
Bundle b = new Bundle();
|
||||
b.putString("url", "https://" + Helper.getPeertubeUrl(host) + "/plugins/auth-openid-connect/0.0.1/auth/openid-connect");
|
||||
intent.putExtras(b);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
runOnUiThread(() -> {
|
||||
connectionButton.setEnabled(true);
|
||||
Toasty.error(LoginActivity.this, getString(R.string.client_error), Toast.LENGTH_LONG).show();
|
||||
});
|
||||
}
|
||||
|
||||
}).start();
|
||||
} else {
|
||||
parameters.clear();
|
||||
parameters.put(Helper.CLIENT_NAME, Helper.CLIENT_NAME_VALUE);
|
||||
parameters.put(Helper.REDIRECT_URIS, Helper.REDIRECT_CONTENT);
|
||||
parameters.put(Helper.SCOPES, Helper.OAUTH_SCOPES_PEERTUBE);
|
||||
parameters.put(Helper.WEBSITE, Helper.WEBSITE_VALUE);
|
||||
String finalInstance = instance;
|
||||
new Thread(() -> {
|
||||
try {
|
||||
actionToken = "/api/v1/oauth-clients/local";
|
||||
String response = new HttpsConnection(LoginActivity.this).get("https://" + finalInstance + actionToken, 30, parameters, null);
|
||||
if (response == null) {
|
||||
runOnUiThread(() -> {
|
||||
connectionButton.setEnabled(true);
|
||||
Toasty.error(LoginActivity.this, getString(R.string.client_error), Toast.LENGTH_LONG).show();
|
||||
});
|
||||
return;
|
||||
}
|
||||
JSONObject resobj;
|
||||
try {
|
||||
resobj = new JSONObject(response);
|
||||
client_id = resobj.get(Helper.CLIENT_ID).toString();
|
||||
client_secret = resobj.get(Helper.CLIENT_SECRET).toString();
|
||||
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = sharedpreferences.edit();
|
||||
editor.putString(Helper.CLIENT_ID, client_id);
|
||||
editor.putString(Helper.CLIENT_SECRET, client_secret);
|
||||
editor.apply();
|
||||
parameters.clear();
|
||||
parameters.put(Helper.CLIENT_ID, sharedpreferences.getString(Helper.CLIENT_ID, null));
|
||||
parameters.put(Helper.CLIENT_SECRET, sharedpreferences.getString(Helper.CLIENT_SECRET, null));
|
||||
parameters.put("grant_type", "password");
|
||||
try {
|
||||
parameters.put("username", URLEncoder.encode(login_uid.getText().toString().trim(), "UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
parameters.put("username", login_uid.getText().toString().trim());
|
||||
}
|
||||
try {
|
||||
parameters.put("password", URLEncoder.encode(login_passwd.getText().toString(), "UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
parameters.put("password", login_passwd.getText().toString());
|
||||
}
|
||||
parameters.put("scope", "user");
|
||||
String oauthUrl = "/api/v1/users/token";
|
||||
try {
|
||||
String responseLogin = new HttpsConnection(LoginActivity.this).post("https://" + finalInstance + oauthUrl, 30, parameters, null);
|
||||
proceedLogin(responseLogin, host);
|
||||
} catch (final Exception e) {
|
||||
parameters.clear();
|
||||
parameters.put(Helper.CLIENT_ID, sharedpreferences.getString(Helper.CLIENT_ID, null));
|
||||
parameters.put(Helper.CLIENT_SECRET, sharedpreferences.getString(Helper.CLIENT_SECRET, null));
|
||||
parameters.put("grant_type", "password");
|
||||
try {
|
||||
parameters.put("username", URLEncoder.encode(login_uid.getText().toString().toLowerCase().trim(), "UTF-8"));
|
||||
} catch (UnsupportedEncodingException e2) {
|
||||
parameters.put("username", login_uid.getText().toString().toLowerCase().trim());
|
||||
}
|
||||
try {
|
||||
parameters.put("password", URLEncoder.encode(login_passwd.getText().toString(), "UTF-8"));
|
||||
} catch (UnsupportedEncodingException e2) {
|
||||
parameters.put("password", login_passwd.getText().toString());
|
||||
}
|
||||
parameters.put("scope", "user");
|
||||
try {
|
||||
String responseLogin = new HttpsConnection(LoginActivity.this).post("https://" + finalInstance + oauthUrl, 30, parameters, null);
|
||||
proceedLogin(responseLogin, host);
|
||||
} catch (final Exception e2) {
|
||||
e2.printStackTrace();
|
||||
runOnUiThread(() -> {
|
||||
connectionButton.setEnabled(true);
|
||||
String message;
|
||||
if (e2.getLocalizedMessage() != null && e2.getLocalizedMessage().trim().length() > 0)
|
||||
message = e2.getLocalizedMessage();
|
||||
else if (e2.getMessage() != null && e2.getMessage().trim().length() > 0)
|
||||
message = e2.getMessage();
|
||||
else
|
||||
message = getString(R.string.client_error);
|
||||
Toasty.error(LoginActivity.this, message, Toast.LENGTH_LONG).show();
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
e.printStackTrace();
|
||||
runOnUiThread(() -> connectionButton.setEnabled(true));
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
runOnUiThread(() -> {
|
||||
connectionButton.setEnabled(true);
|
||||
String message = null;
|
||||
if (e.getLocalizedMessage() != null) {
|
||||
message = e.getMessage();
|
||||
}
|
||||
if (message == null) {
|
||||
message = getString(R.string.client_error);
|
||||
}
|
||||
Toasty.error(LoginActivity.this, message, Toast.LENGTH_LONG).show();
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private void proceedLogin(String responseLogin, String host) {
|
||||
runOnUiThread(() -> {
|
||||
JSONObject resobjLogin;
|
||||
try {
|
||||
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = sharedpreferences.edit();
|
||||
resobjLogin = new JSONObject(responseLogin);
|
||||
String token = resobjLogin.getString("access_token");
|
||||
String refresh_token = resobjLogin.getString("refresh_token");
|
||||
editor.putString(Helper.PREF_KEY_OAUTH_TOKEN, token);
|
||||
editor.putString(Helper.PREF_INSTANCE, host);
|
||||
editor.apply();
|
||||
//Update the account with the token;
|
||||
updateCredential(LoginActivity.this, token, client_id, client_secret, refresh_token, host);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
runOnUiThread(() -> connectionButton.setEnabled(true));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,252 +0,0 @@
|
|||
package app.fedilab.fedilabtube;
|
||||
/* Copyright 2020 Thomas Schneider
|
||||
*
|
||||
* This file is a part of TubeLab
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.NavGraph;
|
||||
import androidx.navigation.NavInflater;
|
||||
import androidx.navigation.Navigation;
|
||||
import androidx.navigation.fragment.NavHostFragment;
|
||||
import androidx.navigation.ui.AppBarConfiguration;
|
||||
import androidx.navigation.ui.NavigationUI;
|
||||
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import app.fedilab.fedilabtube.client.HttpsConnection;
|
||||
import app.fedilab.fedilabtube.client.PeertubeAPI;
|
||||
import app.fedilab.fedilabtube.client.entities.Account;
|
||||
import app.fedilab.fedilabtube.client.entities.PeertubeInformation;
|
||||
import app.fedilab.fedilabtube.helper.Helper;
|
||||
import app.fedilab.fedilabtube.sqlite.AccountDAO;
|
||||
import app.fedilab.fedilabtube.sqlite.Sqlite;
|
||||
import app.fedilab.fedilabtube.viewmodel.FeedsVM;
|
||||
|
||||
import static app.fedilab.fedilabtube.helper.Helper.academies;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
public static PeertubeInformation peertubeInformation;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
BottomNavigationView navView = findViewById(R.id.nav_view);
|
||||
|
||||
if (Helper.isLoggedIn(MainActivity.this)) {
|
||||
navView.inflateMenu(R.menu.bottom_nav_menu_connected);
|
||||
} else {
|
||||
navView.inflateMenu(R.menu.bottom_nav_menu);
|
||||
}
|
||||
|
||||
peertubeInformation = new PeertubeInformation();
|
||||
peertubeInformation.setCategories(new LinkedHashMap<>());
|
||||
peertubeInformation.setLanguages(new LinkedHashMap<>());
|
||||
peertubeInformation.setLicences(new LinkedHashMap<>());
|
||||
peertubeInformation.setPrivacies(new LinkedHashMap<>());
|
||||
peertubeInformation.setPlaylistPrivacies(new LinkedHashMap<>());
|
||||
peertubeInformation.setTranslations(new LinkedHashMap<>());
|
||||
new Thread(() -> {
|
||||
try {
|
||||
peertubeInformation = new PeertubeAPI(MainActivity.this).getPeertubeInformation();
|
||||
} catch (HttpsConnection.HttpsConnectionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}).start();
|
||||
|
||||
// Passing each menu ID as a set of Ids because each
|
||||
// menu should be considered as top level destinations.
|
||||
AppBarConfiguration appBarConfiguration;
|
||||
//Bottom menu won't be the same if the user is authenticated
|
||||
//When the user is authenticated, the subscription entry will be added and the local one removed.
|
||||
if (Helper.isLoggedIn(MainActivity.this)) {
|
||||
appBarConfiguration = new AppBarConfiguration.Builder(
|
||||
R.id.navigation_discover, R.id.navigation_subscription, R.id.navigation_trending, R.id.navigation_most_liked, R.id.navigation_recently_added)
|
||||
.build();
|
||||
} else {
|
||||
appBarConfiguration = new AppBarConfiguration.Builder(
|
||||
R.id.navigation_discover, R.id.navigation_trending, R.id.navigation_most_liked, R.id.navigation_recently_added, R.id.navigation_home)
|
||||
.build();
|
||||
}
|
||||
|
||||
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
|
||||
if (navHostFragment != null) {
|
||||
NavInflater inflater = navHostFragment.getNavController().getNavInflater();
|
||||
NavGraph graph;
|
||||
//the menu is inflated for authenticated or not authenticated account
|
||||
if (Helper.isLoggedIn(MainActivity.this)) {
|
||||
graph = inflater.inflate(R.navigation.mobile_navigation_connected);
|
||||
} else {
|
||||
graph = inflater.inflate(R.navigation.mobile_navigation);
|
||||
}
|
||||
navHostFragment.getNavController().setGraph(graph);
|
||||
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
|
||||
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
|
||||
NavigationUI.setupWithNavController(navView, navController);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(@NotNull Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.main_menu, menu);
|
||||
|
||||
MenuItem myActionMenuItem = menu.findItem(R.id.action_search);
|
||||
SearchView searchView = (SearchView) myActionMenuItem.getActionView();
|
||||
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(String query) {
|
||||
Intent intent = new Intent(MainActivity.this, SearchActivity.class);
|
||||
Bundle b = new Bundle();
|
||||
String search = query.trim();
|
||||
b.putString("search", search);
|
||||
intent.putExtras(b);
|
||||
startActivity(intent);
|
||||
if (!searchView.isIconified()) {
|
||||
searchView.setIconified(true);
|
||||
}
|
||||
myActionMenuItem.collapseActionView();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(String s) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
MenuItem instanceItem = menu.findItem(R.id.action_change_instance);
|
||||
MenuItem uploadItem = menu.findItem(R.id.action_upload);
|
||||
MenuItem myVideosItem = menu.findItem(R.id.action_myvideos);
|
||||
MenuItem playslistItem = menu.findItem(R.id.action_playlist);
|
||||
MenuItem historyItem = menu.findItem(R.id.action_history);
|
||||
if (Helper.isLoggedIn(MainActivity.this)) {
|
||||
instanceItem.setVisible(false);
|
||||
uploadItem.setVisible(true);
|
||||
myVideosItem.setVisible(true);
|
||||
playslistItem.setVisible(true);
|
||||
historyItem.setVisible(true);
|
||||
final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
|
||||
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
|
||||
String instance = Helper.getLiveInstance(MainActivity.this);
|
||||
SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
|
||||
Account account = new AccountDAO(MainActivity.this, db).getUniqAccount(userId, instance);
|
||||
if (account != null) {
|
||||
new Thread(() -> new PeertubeAPI(MainActivity.this).refreshToken(account.getToken(), account.getInstance())).start();
|
||||
}
|
||||
} else {
|
||||
instanceItem.setVisible(true);
|
||||
uploadItem.setVisible(false);
|
||||
myVideosItem.setVisible(false);
|
||||
playslistItem.setVisible(false);
|
||||
historyItem.setVisible(false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == R.id.action_change_instance) {
|
||||
showRadioButtonDialog();
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.action_account) {
|
||||
Intent intent;
|
||||
if (Helper.isLoggedIn(MainActivity.this)) {
|
||||
intent = new Intent(MainActivity.this, AccountActivity.class);
|
||||
} else {
|
||||
intent = new Intent(MainActivity.this, LoginActivity.class);
|
||||
}
|
||||
startActivity(intent);
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.action_upload) {
|
||||
Intent intent = new Intent(MainActivity.this, PeertubeUploadActivity.class);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.action_myvideos) {
|
||||
Intent intent = new Intent(MainActivity.this, MyVideosActivity.class);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putSerializable("type", FeedsVM.Type.MYVIDEOS);
|
||||
intent.putExtras(bundle);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.action_history) {
|
||||
Intent intent = new Intent(MainActivity.this, MyVideosActivity.class);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putSerializable("type", FeedsVM.Type.PEERTUBE_HISTORY);
|
||||
intent.putExtras(bundle);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.action_playlist) {
|
||||
Intent intent = new Intent(MainActivity.this, AllPlaylistsActivity.class);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
if (intent == null)
|
||||
return;
|
||||
Bundle extras = intent.getExtras();
|
||||
if (extras != null && extras.containsKey(Helper.INTENT_ACTION)) {
|
||||
if (extras.getInt(Helper.INTENT_ACTION) == Helper.ADD_USER_INTENT) {
|
||||
recreate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
private void showRadioButtonDialog() {
|
||||
|
||||
AlertDialog.Builder alt_bld = new AlertDialog.Builder(this);
|
||||
alt_bld.setTitle(R.string.instance_choice);
|
||||
final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
|
||||
String acad = Helper.getLiveInstance(MainActivity.this);
|
||||
int i = 0;
|
||||
for (String item : academies) {
|
||||
if (Helper.getPeertubeUrl(item).compareTo(acad) == 0) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
alt_bld.setSingleChoiceItems(academies, i, (dialog, item) -> {
|
||||
String newInstance = academies[item];
|
||||
SharedPreferences.Editor editor = sharedpreferences.edit();
|
||||
editor.putString(Helper.PREF_INSTANCE, newInstance);
|
||||
editor.commit();
|
||||
dialog.dismiss();
|
||||
recreate();
|
||||
});
|
||||
alt_bld.setPositiveButton(R.string.close, (dialog, id) -> dialog.dismiss());
|
||||
AlertDialog alert = alt_bld.create();
|
||||
alert.show();
|
||||
}
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
package app.fedilab.fedilabtube;
|
||||
/* Copyright 2020 Thomas Schneider
|
||||
*
|
||||
* This file is a part of TubeLab
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
import app.fedilab.fedilabtube.fragment.DisplayStatusFragment;
|
||||
import app.fedilab.fedilabtube.viewmodel.FeedsVM;
|
||||
|
||||
|
||||
public class MyVideosActivity extends AppCompatActivity {
|
||||
|
||||
private FeedsVM.Type type;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.activity_search_result);
|
||||
|
||||
if (getSupportActionBar() != null)
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
Bundle b = getIntent().getExtras();
|
||||
if (b != null)
|
||||
type = (FeedsVM.Type) b.get("type");
|
||||
|
||||
if (type == FeedsVM.Type.MYVIDEOS) {
|
||||
setTitle(R.string.my_videos);
|
||||
} else if (type == FeedsVM.Type.PSUBSCRIPTIONS) {
|
||||
setTitle(R.string.subscriptions);
|
||||
} else if (type == FeedsVM.Type.PEERTUBE_HISTORY) {
|
||||
setTitle(R.string.my_history);
|
||||
}
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
DisplayStatusFragment displayStatusFragment = new DisplayStatusFragment();
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putSerializable("type", type);
|
||||
displayStatusFragment.setArguments(bundle);
|
||||
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
|
||||
ft.add(R.id.container, displayStatusFragment).commit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,843 +0,0 @@
|
|||
package app.fedilab.fedilabtube;
|
||||
/* Copyright 2020 Thomas Schneider
|
||||
*
|
||||
* This file is a part of TubeLab
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.Html;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.AppCompatImageView;
|
||||
import androidx.appcompat.widget.PopupMenu;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.graphics.drawable.DrawableCompat;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.exoplayer2.ExoPlayerFactory;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
|
||||
import com.google.android.exoplayer2.ui.PlayerControlView;
|
||||
import com.google.android.exoplayer2.ui.PlayerView;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
|
||||
import app.fedilab.fedilabtube.client.APIResponse;
|
||||
import app.fedilab.fedilabtube.client.PeertubeAPI;
|
||||
import app.fedilab.fedilabtube.client.TLSSocketFactory;
|
||||
import app.fedilab.fedilabtube.client.entities.Account;
|
||||
import app.fedilab.fedilabtube.client.entities.Peertube;
|
||||
import app.fedilab.fedilabtube.client.entities.Playlist;
|
||||
import app.fedilab.fedilabtube.client.entities.PlaylistElement;
|
||||
import app.fedilab.fedilabtube.client.entities.Status;
|
||||
import app.fedilab.fedilabtube.client.entities.StatusDrawerParams;
|
||||
import app.fedilab.fedilabtube.drawer.StatusListAdapter;
|
||||
import app.fedilab.fedilabtube.helper.CacheDataSourceFactory;
|
||||
import app.fedilab.fedilabtube.helper.FullScreenMediaController;
|
||||
import app.fedilab.fedilabtube.helper.Helper;
|
||||
import app.fedilab.fedilabtube.sqlite.AccountDAO;
|
||||
import app.fedilab.fedilabtube.sqlite.PeertubeFavoritesDAO;
|
||||
import app.fedilab.fedilabtube.sqlite.Sqlite;
|
||||
import app.fedilab.fedilabtube.viewmodel.CommentVM;
|
||||
import app.fedilab.fedilabtube.viewmodel.FeedsVM;
|
||||
import app.fedilab.fedilabtube.viewmodel.PlaylistsVM;
|
||||
import app.fedilab.fedilabtube.viewmodel.PostActionsVM;
|
||||
import app.fedilab.fedilabtube.webview.CustomWebview;
|
||||
import app.fedilab.fedilabtube.webview.MastalabWebChromeClient;
|
||||
import app.fedilab.fedilabtube.webview.MastalabWebViewClient;
|
||||
import es.dmoral.toasty.Toasty;
|
||||
|
||||
import static app.fedilab.fedilabtube.helper.Helper.getAttColor;
|
||||
import static app.fedilab.fedilabtube.helper.Helper.isLoggedIn;
|
||||
import static app.fedilab.fedilabtube.viewmodel.PlaylistsVM.action.GET_PLAYLIST;
|
||||
import static app.fedilab.fedilabtube.viewmodel.PlaylistsVM.action.GET_PLAYLIST_FOR_VIDEO;
|
||||
|
||||
|
||||
public class PeertubeActivity extends AppCompatActivity {
|
||||
|
||||
public static String video_id;
|
||||
private String peertubeInstance, videoId;
|
||||
private FullScreenMediaController.fullscreen fullscreen;
|
||||
private RelativeLayout loader;
|
||||
private TextView peertube_view_count, peertube_playlist, peertube_bookmark, peertube_like_count, peertube_dislike_count, peertube_share, peertube_download, peertube_description, peertube_title;
|
||||
private ScrollView peertube_information_container;
|
||||
private Peertube peertube;
|
||||
private PlayerView playerView;
|
||||
private SimpleExoPlayer player;
|
||||
private boolean fullScreenMode;
|
||||
private Dialog fullScreenDialog;
|
||||
private AppCompatImageView fullScreenIcon;
|
||||
private TextView resolution;
|
||||
private int mode;
|
||||
private LinearLayout write_comment_container;
|
||||
private ImageView send;
|
||||
private TextView add_comment_read;
|
||||
private EditText add_comment_write;
|
||||
private List<PlaylistElement> playlistForVideo;
|
||||
private List<Playlist> playlists;
|
||||
private PlaylistsVM playlistsViewModel;
|
||||
|
||||
public static void hideKeyboard(Activity activity) {
|
||||
if (activity != null && activity.getWindow() != null) {
|
||||
activity.getWindow().getDecorView();
|
||||
InputMethodManager imm = (InputMethodManager) activity.getSystemService(INPUT_METHOD_SERVICE);
|
||||
assert imm != null;
|
||||
imm.hideSoftInputFromWindow(activity.getWindow().getDecorView().getWindowToken(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
|
||||
fullscreen = FullScreenMediaController.fullscreen.OFF;
|
||||
fullScreenMode = false;
|
||||
playlistForVideo = new ArrayList<>();
|
||||
setContentView(R.layout.activity_peertube);
|
||||
loader = findViewById(R.id.loader);
|
||||
peertube_view_count = findViewById(R.id.peertube_view_count);
|
||||
peertube_bookmark = findViewById(R.id.peertube_bookmark);
|
||||
peertube_like_count = findViewById(R.id.peertube_like_count);
|
||||
peertube_dislike_count = findViewById(R.id.peertube_dislike_count);
|
||||
peertube_share = findViewById(R.id.peertube_share);
|
||||
peertube_download = findViewById(R.id.peertube_download);
|
||||
peertube_description = findViewById(R.id.peertube_description);
|
||||
peertube_title = findViewById(R.id.peertube_title);
|
||||
peertube_information_container = findViewById(R.id.peertube_information_container);
|
||||
CustomWebview webview_video = findViewById(R.id.webview_video);
|
||||
playerView = findViewById(R.id.media_video);
|
||||
write_comment_container = findViewById(R.id.write_comment_container);
|
||||
ImageView my_pp = findViewById(R.id.my_pp);
|
||||
add_comment_read = findViewById(R.id.add_comment_read);
|
||||
add_comment_write = findViewById(R.id.add_comment_write);
|
||||
peertube_playlist = findViewById(R.id.peertube_playlist);
|
||||
send = findViewById(R.id.send);
|
||||
|
||||
|
||||
peertube_playlist.setVisibility(View.VISIBLE);
|
||||
peertube_bookmark.setVisibility(View.GONE);
|
||||
|
||||
if (Helper.isTablet(PeertubeActivity.this)) {
|
||||
RelativeLayout video_container = findViewById(R.id.video_container);
|
||||
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
0,
|
||||
2.0f
|
||||
);
|
||||
video_container.setLayoutParams(param);
|
||||
}
|
||||
|
||||
SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
|
||||
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
|
||||
String instance = Helper.getLiveInstance(PeertubeActivity.this);
|
||||
Account account = new AccountDAO(PeertubeActivity.this, db).getUniqAccount(userId, instance);
|
||||
Helper.loadGiF(PeertubeActivity.this, account, my_pp);
|
||||
Bundle b = getIntent().getExtras();
|
||||
if (b != null) {
|
||||
peertubeInstance = b.getString("peertube_instance", Helper.getLiveInstance(PeertubeActivity.this));
|
||||
videoId = b.getString("video_id", null);
|
||||
}
|
||||
|
||||
if (getSupportActionBar() != null)
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
|
||||
mode = sharedpreferences.getInt(Helper.SET_VIDEO_MODE, Helper.VIDEO_MODE_NORMAL);
|
||||
if (mode != Helper.VIDEO_MODE_WEBVIEW && mode != Helper.VIDEO_MODE_NORMAL)
|
||||
mode = Helper.VIDEO_MODE_NORMAL;
|
||||
if (mode == Helper.VIDEO_MODE_WEBVIEW) {
|
||||
webview_video.setVisibility(View.VISIBLE);
|
||||
playerView.setVisibility(View.GONE);
|
||||
|
||||
webview_video = Helper.initializeWebview(PeertubeActivity.this, R.id.webview_video, null);
|
||||
FrameLayout webview_container = findViewById(R.id.main_media_frame);
|
||||
final ViewGroup videoLayout = findViewById(R.id.videoLayout);
|
||||
|
||||
MastalabWebChromeClient mastalabWebChromeClient = new MastalabWebChromeClient(PeertubeActivity.this, webview_video, webview_container, videoLayout);
|
||||
mastalabWebChromeClient.setOnToggledFullscreen(fullscreen -> {
|
||||
|
||||
if (fullscreen) {
|
||||
videoLayout.setVisibility(View.VISIBLE);
|
||||
WindowManager.LayoutParams attrs = getWindow().getAttributes();
|
||||
attrs.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
|
||||
attrs.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
|
||||
getWindow().setAttributes(attrs);
|
||||
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
|
||||
peertube_information_container.setVisibility(View.GONE);
|
||||
} else {
|
||||
WindowManager.LayoutParams attrs = getWindow().getAttributes();
|
||||
attrs.flags &= ~WindowManager.LayoutParams.FLAG_FULLSCREEN;
|
||||
attrs.flags &= ~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
|
||||
getWindow().setAttributes(attrs);
|
||||
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
|
||||
videoLayout.setVisibility(View.GONE);
|
||||
peertube_information_container.setVisibility(View.VISIBLE);
|
||||
}
|
||||
});
|
||||
webview_video.getSettings().setAllowFileAccess(true);
|
||||
webview_video.setWebChromeClient(mastalabWebChromeClient);
|
||||
webview_video.getSettings().setDomStorageEnabled(true);
|
||||
webview_video.getSettings().setAppCacheEnabled(true);
|
||||
webview_video.getSettings().setMediaPlaybackRequiresUserGesture(false);
|
||||
webview_video.setWebViewClient(new MastalabWebViewClient(PeertubeActivity.this));
|
||||
webview_video.loadUrl("https://" + peertubeInstance + "/videos/embed/" + videoId);
|
||||
} else {
|
||||
webview_video.setVisibility(View.GONE);
|
||||
playerView.setVisibility(View.VISIBLE);
|
||||
loader.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
|
||||
if (mode != Helper.VIDEO_MODE_WEBVIEW) {
|
||||
playerView.setControllerShowTimeoutMs(1000);
|
||||
playerView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FIT);
|
||||
initFullscreenDialog();
|
||||
initFullscreenButton();
|
||||
}
|
||||
playlistsViewModel = new ViewModelProvider(PeertubeActivity.this).get(PlaylistsVM.class);
|
||||
if (Helper.isLoggedIn(PeertubeActivity.this)) {
|
||||
playlistsViewModel.manage(GET_PLAYLIST, null, null, null).observe(PeertubeActivity.this, apiResponse -> manageVIewPlaylists(GET_PLAYLIST, apiResponse));
|
||||
}
|
||||
|
||||
FeedsVM feedsViewModel = new ViewModelProvider(PeertubeActivity.this).get(FeedsVM.class);
|
||||
feedsViewModel.getVideo(peertubeInstance, videoId).observe(PeertubeActivity.this, this::manageVIewVideo);
|
||||
}
|
||||
|
||||
public void change() {
|
||||
if (fullscreen == FullScreenMediaController.fullscreen.ON) {
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN |
|
||||
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
Objects.requireNonNull(getSupportActionBar()).hide();
|
||||
peertube_information_container.setVisibility(View.GONE);
|
||||
} else {
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
|
||||
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
|
||||
Objects.requireNonNull(getSupportActionBar()).show();
|
||||
peertube_information_container.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
View v = getCurrentFocus();
|
||||
|
||||
if ((ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_MOVE) &&
|
||||
v instanceof EditText &&
|
||||
v.getId() == R.id.add_comment_write) {
|
||||
int[] scrcoords = new int[2];
|
||||
v.getLocationOnScreen(scrcoords);
|
||||
float x = ev.getRawX() + v.getLeft() - scrcoords[0];
|
||||
float y = ev.getRawY() + v.getTop() - scrcoords[1];
|
||||
|
||||
if (x < v.getLeft() || x > v.getRight() || y < v.getTop() || y > v.getBottom()) {
|
||||
add_comment_read.setVisibility(View.VISIBLE);
|
||||
add_comment_write.setVisibility(View.GONE);
|
||||
send.setVisibility(View.GONE);
|
||||
hideKeyboard(PeertubeActivity.this);
|
||||
}
|
||||
}
|
||||
return super.dispatchTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(@NotNull Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.main_peertube, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
finish();
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.action_report) {
|
||||
androidx.appcompat.app.AlertDialog.Builder dialogBuilder = new androidx.appcompat.app.AlertDialog.Builder(PeertubeActivity.this);
|
||||
LayoutInflater inflater1 = getLayoutInflater();
|
||||
View dialogView = inflater1.inflate(R.layout.popup_report_choice, new LinearLayout(PeertubeActivity.this), false);
|
||||
dialogBuilder.setView(dialogView);
|
||||
Button report_video = dialogView.findViewById(R.id.report_video);
|
||||
Button report_account = dialogView.findViewById(R.id.report_account);
|
||||
dialogBuilder.setNeutralButton(R.string.cancel, (dialog, id) -> dialog.dismiss());
|
||||
androidx.appcompat.app.AlertDialog alertDialog = dialogBuilder.create();
|
||||
alertDialog.show();
|
||||
report_video.setOnClickListener(v -> reportAlert(PeertubeAPI.reportType.VIDEO, alertDialog));
|
||||
report_account.setOnClickListener(v -> reportAlert(PeertubeAPI.reportType.ACCOUNT, alertDialog));
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void reportAlert(PeertubeAPI.reportType type, androidx.appcompat.app.AlertDialog alertDialog) {
|
||||
androidx.appcompat.app.AlertDialog.Builder dialogBuilder = new androidx.appcompat.app.AlertDialog.Builder(PeertubeActivity.this);
|
||||
LayoutInflater inflater1 = getLayoutInflater();
|
||||
View dialogView = inflater1.inflate(R.layout.popup_report, new LinearLayout(PeertubeActivity.this), false);
|
||||
dialogBuilder.setView(dialogView);
|
||||
EditText report_content = dialogView.findViewById(R.id.report_content);
|
||||
dialogBuilder.setNeutralButton(R.string.cancel, (dialog, id) -> dialog.dismiss());
|
||||
dialogBuilder.setPositiveButton(R.string.report, (dialog, id) -> {
|
||||
if (report_content.getText().toString().trim().length() == 0) {
|
||||
Toasty.info(PeertubeActivity.this, getString(R.string.report_comment_size), Toasty.LENGTH_LONG).show();
|
||||
} else {
|
||||
if (type == PeertubeAPI.reportType.VIDEO) {
|
||||
PostActionsVM viewModel = new ViewModelProvider(PeertubeActivity.this).get(PostActionsVM.class);
|
||||
viewModel.post(PeertubeAPI.StatusAction.REPORT_VIDEO, peertube.getId(), report_content.getText().toString(), null).observe(PeertubeActivity.this, apiResponse -> manageVIewPostActions(PeertubeAPI.StatusAction.REPORT_VIDEO, apiResponse));
|
||||
alertDialog.dismiss();
|
||||
dialog.dismiss();
|
||||
} else if (type == PeertubeAPI.reportType.ACCOUNT) {
|
||||
PostActionsVM viewModel = new ViewModelProvider(PeertubeActivity.this).get(PostActionsVM.class);
|
||||
viewModel.post(PeertubeAPI.StatusAction.REPORT_ACCOUNT, peertube.getAccount().getId(), report_content.getText().toString(), null).observe(PeertubeActivity.this, apiResponse -> manageVIewPostActions(PeertubeAPI.StatusAction.REPORT_ACCOUNT, apiResponse));
|
||||
alertDialog.dismiss();
|
||||
dialog.dismiss();
|
||||
}
|
||||
}
|
||||
});
|
||||
androidx.appcompat.app.AlertDialog alertDialog2 = dialogBuilder.create();
|
||||
alertDialog2.show();
|
||||
}
|
||||
|
||||
public FullScreenMediaController.fullscreen getFullscreen() {
|
||||
return fullscreen;
|
||||
}
|
||||
|
||||
public void setFullscreen(FullScreenMediaController.fullscreen fullscreen) {
|
||||
this.fullscreen = fullscreen;
|
||||
}
|
||||
|
||||
public void manageVIewVideo(APIResponse apiResponse) {
|
||||
|
||||
if (apiResponse == null || (apiResponse.getError() != null) || apiResponse.getPeertubes() == null || apiResponse.getPeertubes().size() == 0) {
|
||||
Toasty.error(PeertubeActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
|
||||
loader.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
if (apiResponse.getPeertubes() == null || apiResponse.getPeertubes().get(0) == null || apiResponse.getPeertubes().get(0).getFileUrl(null, PeertubeActivity.this) == null) {
|
||||
Toasty.error(PeertubeActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
|
||||
loader.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
|
||||
peertube = apiResponse.getPeertubes().get(0);
|
||||
//TODO: currently streaming service gives the wrong values for duration
|
||||
playlistsViewModel.manage(GET_PLAYLIST_FOR_VIDEO, null, peertube.getId(), null).observe(PeertubeActivity.this, apiResponse2 -> manageVIewPlaylists(GET_PLAYLIST_FOR_VIDEO, apiResponse2));
|
||||
|
||||
add_comment_read.setOnClickListener(v -> {
|
||||
if (isLoggedIn(PeertubeActivity.this)) {
|
||||
add_comment_read.setVisibility(View.GONE);
|
||||
add_comment_write.setVisibility(View.VISIBLE);
|
||||
send.setVisibility(View.VISIBLE);
|
||||
add_comment_write.requestFocus();
|
||||
add_comment_write.setSelection(add_comment_write.getText().length());
|
||||
} else {
|
||||
Toasty.error(PeertubeActivity.this, getString(R.string.not_logged_in), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
});
|
||||
send.setOnClickListener(v -> {
|
||||
if (isLoggedIn(PeertubeActivity.this)) {
|
||||
String comment = add_comment_write.getText().toString();
|
||||
if (comment.trim().length() > 0) {
|
||||
PostActionsVM viewModel = new ViewModelProvider(PeertubeActivity.this).get(PostActionsVM.class);
|
||||
viewModel.post(PeertubeAPI.StatusAction.PEERTUBECOMMENT, peertube.getAccount().getId(), comment, null).observe(PeertubeActivity.this, apiResponse1 -> manageVIewPostActions(PeertubeAPI.StatusAction.PEERTUBECOMMENT, apiResponse1));
|
||||
add_comment_write.setText("");
|
||||
add_comment_read.setVisibility(View.VISIBLE);
|
||||
add_comment_write.setVisibility(View.GONE);
|
||||
send.setVisibility(View.GONE);
|
||||
add_comment_read.requestFocus();
|
||||
}
|
||||
} else {
|
||||
Toasty.error(PeertubeActivity.this, getString(R.string.not_logged_in), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
peertube_playlist.setOnClickListener(v -> {
|
||||
if (playlists != null && peertube.getId() != null) {
|
||||
PopupMenu popup = new PopupMenu(PeertubeActivity.this, peertube_playlist);
|
||||
|
||||
for (Playlist playlist : playlists) {
|
||||
String title = null;
|
||||
boolean isPresent = false;
|
||||
String elementId = null;
|
||||
PlaylistElement playlistElementFinal = null;
|
||||
for (PlaylistElement playlistElement : playlistForVideo) {
|
||||
if (playlist.getId().equals(playlistElement.getPlaylistId())) {
|
||||
title = "✔ " + playlist.getDisplayName();
|
||||
isPresent = true;
|
||||
elementId = playlistElement.getPlaylistElementId();
|
||||
playlistElementFinal = playlistElement;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (title == null) {
|
||||
title = playlist.getDisplayName();
|
||||
}
|
||||
MenuItem item = popup.getMenu().add(0, 0, Menu.NONE, title);
|
||||
boolean finalIsPresent = isPresent;
|
||||
String finalElementId = elementId;
|
||||
PlaylistElement finalPlaylistElementFinal = playlistElementFinal;
|
||||
item.setOnMenuItemClickListener(item1 -> {
|
||||
item1.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
|
||||
item1.setActionView(new View(PeertubeActivity.this));
|
||||
item1.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
|
||||
@Override
|
||||
public boolean onMenuItemActionExpand(MenuItem item1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemActionCollapse(MenuItem item1) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if (finalIsPresent) {
|
||||
item1.setTitle(playlist.getDisplayName());
|
||||
playlistsViewModel.manage(PlaylistsVM.action.DELETE_VIDEOS, playlist, finalElementId, null).observe(PeertubeActivity.this, apiResponse3 -> manageVIewPlaylists(PlaylistsVM.action.DELETE_VIDEOS, apiResponse3));
|
||||
playlistForVideo.remove(finalPlaylistElementFinal);
|
||||
} else {
|
||||
item1.setTitle("✔ " + playlist.getDisplayName());
|
||||
playlistsViewModel.manage(PlaylistsVM.action.ADD_VIDEOS, playlist, peertube.getId(), null).observe(PeertubeActivity.this, apiResponse3 -> manageVIewPlaylists(PlaylistsVM.action.ADD_VIDEOS, apiResponse3));
|
||||
PlaylistElement playlistElement = new PlaylistElement();
|
||||
playlistElement.setPlaylistElementId(finalElementId);
|
||||
playlistElement.setPlaylistId(playlist.getId());
|
||||
playlistForVideo.add(playlistElement);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
popup.show();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (peertube.isCommentsEnabled()) {
|
||||
CommentVM commentViewModel = new ViewModelProvider(PeertubeActivity.this).get(CommentVM.class);
|
||||
commentViewModel.getComment(peertubeInstance, videoId).observe(PeertubeActivity.this, this::manageVIewComment);
|
||||
write_comment_container.setVisibility(View.VISIBLE);
|
||||
|
||||
} else {
|
||||
RelativeLayout no_action = findViewById(R.id.no_action);
|
||||
TextView no_action_text = findViewById(R.id.no_action_text);
|
||||
no_action_text.setText(getString(R.string.comment_no_allowed_peertube));
|
||||
no_action.setVisibility(View.VISIBLE);
|
||||
write_comment_container.setVisibility(View.GONE);
|
||||
}
|
||||
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
|
||||
setTitle(peertube.getName());
|
||||
peertube_description.setText(peertube.getDescription());
|
||||
peertube_title.setText(peertube.getName());
|
||||
peertube_dislike_count.setText(String.valueOf(peertube.getDislike()));
|
||||
peertube_like_count.setText(String.valueOf(peertube.getLike()));
|
||||
peertube_view_count.setText(String.valueOf(peertube.getView()));
|
||||
video_id = peertube.getId();
|
||||
|
||||
changeColor();
|
||||
initResolution();
|
||||
|
||||
peertube_like_count.setOnClickListener(v -> {
|
||||
if (isLoggedIn(PeertubeActivity.this)) {
|
||||
String newState = peertube.getMyRating().equals("like") ? "none" : "like";
|
||||
PostActionsVM viewModel = new ViewModelProvider(PeertubeActivity.this).get(PostActionsVM.class);
|
||||
viewModel.post(PeertubeAPI.StatusAction.RATEVIDEO, peertube.getId(), newState, null).observe(PeertubeActivity.this, apiResponse1 -> manageVIewPostActions(PeertubeAPI.StatusAction.RATEVIDEO, apiResponse1));
|
||||
peertube.setMyRating(newState);
|
||||
int count = Integer.parseInt(peertube_like_count.getText().toString());
|
||||
if (newState.compareTo("none") == 0) {
|
||||
count--;
|
||||
if (count - 1 < 0) {
|
||||
count = 0;
|
||||
}
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
peertube_like_count.setText(String.valueOf(count));
|
||||
changeColor();
|
||||
} else {
|
||||
Toasty.error(PeertubeActivity.this, getString(R.string.not_logged_in), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
peertube_dislike_count.setOnClickListener(v -> {
|
||||
if (isLoggedIn(PeertubeActivity.this)) {
|
||||
String newState = peertube.getMyRating().equals("dislike") ? "none" : "dislike";
|
||||
PostActionsVM viewModel = new ViewModelProvider(PeertubeActivity.this).get(PostActionsVM.class);
|
||||
viewModel.post(PeertubeAPI.StatusAction.RATEVIDEO, peertube.getId(), newState, null).observe(PeertubeActivity.this, apiResponse1 -> manageVIewPostActions(PeertubeAPI.StatusAction.RATEVIDEO, apiResponse1));
|
||||
peertube.setMyRating(newState);
|
||||
int count = Integer.parseInt(peertube_dislike_count.getText().toString());
|
||||
if (newState.compareTo("none") == 0) {
|
||||
count--;
|
||||
if (count - 1 < 0) {
|
||||
count = 0;
|
||||
}
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
peertube_dislike_count.setText(String.valueOf(count));
|
||||
changeColor();
|
||||
} else {
|
||||
Toasty.error(PeertubeActivity.this, getString(R.string.not_logged_in), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(new TLSSocketFactory());
|
||||
} catch (KeyManagementException | NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (mode == Helper.VIDEO_MODE_NORMAL) {
|
||||
|
||||
int video_cache = sharedpreferences.getInt(Helper.SET_VIDEO_CACHE, Helper.DEFAULT_VIDEO_CACHE_MB);
|
||||
ProgressiveMediaSource videoSource;
|
||||
if (video_cache == 0) {
|
||||
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(PeertubeActivity.this,
|
||||
Util.getUserAgent(PeertubeActivity.this, null), null);
|
||||
videoSource = new ProgressiveMediaSource.Factory(dataSourceFactory)
|
||||
.createMediaSource(Uri.parse(apiResponse.getPeertubes().get(0).getFileUrl(null, PeertubeActivity.this)));
|
||||
} else {
|
||||
CacheDataSourceFactory cacheDataSourceFactory = new CacheDataSourceFactory(PeertubeActivity.this);
|
||||
videoSource = new ProgressiveMediaSource.Factory(cacheDataSourceFactory)
|
||||
.createMediaSource(Uri.parse(apiResponse.getPeertubes().get(0).getFileUrl(null, PeertubeActivity.this)));
|
||||
}
|
||||
|
||||
player = ExoPlayerFactory.newSimpleInstance(PeertubeActivity.this);
|
||||
playerView.setPlayer(player);
|
||||
loader.setVisibility(View.GONE);
|
||||
player.prepare(videoSource);
|
||||
player.setPlayWhenReady(true);
|
||||
}
|
||||
|
||||
|
||||
peertube_download.setOnClickListener(v -> {
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
if (ContextCompat.checkSelfPermission(PeertubeActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(PeertubeActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(PeertubeActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, Helper.EXTERNAL_STORAGE_REQUEST_CODE);
|
||||
} else {
|
||||
Helper.manageDownloads(PeertubeActivity.this, peertube.getFileDownloadUrl(null, PeertubeActivity.this));
|
||||
}
|
||||
} else {
|
||||
Helper.manageDownloads(PeertubeActivity.this, peertube.getFileDownloadUrl(null, PeertubeActivity.this));
|
||||
}
|
||||
});
|
||||
SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
|
||||
List<Peertube> peertubes = new PeertubeFavoritesDAO(PeertubeActivity.this, db).getSinglePeertube(peertube);
|
||||
|
||||
Drawable img;
|
||||
|
||||
if (peertubes == null || peertubes.size() == 0)
|
||||
img = ContextCompat.getDrawable(PeertubeActivity.this, R.drawable.ic_baseline_bookmark_border_24);
|
||||
else
|
||||
img = ContextCompat.getDrawable(PeertubeActivity.this, R.drawable.ic_baseline_bookmark_24);
|
||||
peertube_bookmark.setCompoundDrawablesWithIntrinsicBounds(null, img, null, null);
|
||||
|
||||
peertube_bookmark.setOnClickListener(v -> {
|
||||
List<Peertube> peertubes1 = new PeertubeFavoritesDAO(PeertubeActivity.this, db).getSinglePeertube(peertube);
|
||||
if (peertubes1 == null || peertubes1.size() == 0) {
|
||||
new PeertubeFavoritesDAO(PeertubeActivity.this, db).insert(peertube);
|
||||
Toasty.success(PeertubeActivity.this, getString(R.string.bookmark_add_peertube), Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
new PeertubeFavoritesDAO(PeertubeActivity.this, db).remove(peertube);
|
||||
Toasty.success(PeertubeActivity.this, getString(R.string.bookmark_remove_peertube), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
if (peertubes1 != null && peertubes1.size() > 0) //Was initially in cache
|
||||
peertube_bookmark.setCompoundDrawablesWithIntrinsicBounds(null, ContextCompat.getDrawable(PeertubeActivity.this, R.drawable.ic_baseline_bookmark_border_24), null, null);
|
||||
else
|
||||
peertube_bookmark.setCompoundDrawablesWithIntrinsicBounds(null, ContextCompat.getDrawable(PeertubeActivity.this, R.drawable.ic_baseline_bookmark_24), null, null);
|
||||
});
|
||||
|
||||
peertube_share.setOnClickListener(v -> {
|
||||
Intent sendIntent = new Intent(Intent.ACTION_SEND);
|
||||
sendIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.shared_via));
|
||||
String url;
|
||||
|
||||
url = "https://" + peertube.getInstance() + "/videos/watch/" + peertube.getUuid();
|
||||
boolean share_details = sharedpreferences.getBoolean(Helper.SET_SHARE_DETAILS, true);
|
||||
String extra_text;
|
||||
if (share_details) {
|
||||
extra_text = "@" + peertube.getAccount().getAcct();
|
||||
extra_text += "\r\n\r\n" + peertube.getName();
|
||||
extra_text += "\n\n\uD83D\uDD17 " + url + "\r\n-\n";
|
||||
final String contentToot;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
|
||||
contentToot = Html.fromHtml(peertube.getDescription(), Html.FROM_HTML_MODE_LEGACY).toString();
|
||||
else
|
||||
contentToot = Html.fromHtml(peertube.getDescription()).toString();
|
||||
extra_text += contentToot;
|
||||
} else {
|
||||
extra_text = url;
|
||||
}
|
||||
sendIntent.putExtra(Intent.EXTRA_TEXT, extra_text);
|
||||
sendIntent.setType("text/plain");
|
||||
startActivity(Intent.createChooser(sendIntent, getString(R.string.share_with)));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(@NotNull Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
if (mode != Helper.VIDEO_MODE_WEBVIEW) {
|
||||
openFullscreenDialog();
|
||||
}
|
||||
setFullscreen(FullScreenMediaController.fullscreen.ON);
|
||||
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
if (mode != Helper.VIDEO_MODE_WEBVIEW) {
|
||||
closeFullscreenDialog();
|
||||
}
|
||||
setFullscreen(FullScreenMediaController.fullscreen.OFF);
|
||||
}
|
||||
change();
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void manageVIewComment(APIResponse apiResponse) {
|
||||
if (apiResponse == null || (apiResponse.getError() != null && apiResponse.getError().getStatusCode() != 404 && apiResponse.getError() != null && apiResponse.getError().getStatusCode() != 501)) {
|
||||
if (apiResponse == null)
|
||||
Toasty.error(PeertubeActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
|
||||
else
|
||||
Toasty.error(PeertubeActivity.this, apiResponse.getError().getError(), Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
List<Status> statuses = apiResponse.getStatuses();
|
||||
RecyclerView lv_comments = findViewById(R.id.peertube_comments);
|
||||
if (statuses != null && statuses.size() > 0) {
|
||||
lv_comments.setVisibility(View.VISIBLE);
|
||||
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
|
||||
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
|
||||
StatusDrawerParams statusDrawerParams = new StatusDrawerParams();
|
||||
statusDrawerParams.setTargetedId(userId);
|
||||
statusDrawerParams.setStatuses(statuses);
|
||||
StatusListAdapter statusListAdapter = new StatusListAdapter(statusDrawerParams);
|
||||
LinearLayoutManager mLayoutManager = new LinearLayoutManager(PeertubeActivity.this);
|
||||
lv_comments.setLayoutManager(mLayoutManager);
|
||||
lv_comments.setNestedScrollingEnabled(false);
|
||||
lv_comments.setAdapter(statusListAdapter);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (player != null)
|
||||
player.release();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
if (player != null) {
|
||||
player.setPlayWhenReady(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
if (player != null) {
|
||||
player.setPlayWhenReady(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void displayResolution() {
|
||||
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
|
||||
|
||||
AlertDialog.Builder builderSingle = new AlertDialog.Builder(PeertubeActivity.this);
|
||||
builderSingle.setTitle(R.string.pickup_resolution);
|
||||
final ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(PeertubeActivity.this, android.R.layout.select_dialog_item);
|
||||
for (String resolution : peertube.getResolution())
|
||||
arrayAdapter.add(resolution + "p");
|
||||
builderSingle.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
|
||||
builderSingle.setAdapter(arrayAdapter, (dialog, which) -> {
|
||||
String res = Objects.requireNonNull(arrayAdapter.getItem(which)).substring(0, Objects.requireNonNull(arrayAdapter.getItem(which)).length() - 1);
|
||||
|
||||
if (playerView != null) {
|
||||
loader.setVisibility(View.VISIBLE);
|
||||
long position = player.getCurrentPosition();
|
||||
PlayerControlView controlView = playerView.findViewById(R.id.exo_controller);
|
||||
resolution = controlView.findViewById(R.id.resolution);
|
||||
resolution.setText(String.format("%sp", res));
|
||||
if (mode == Helper.VIDEO_MODE_NORMAL) {
|
||||
if (player != null)
|
||||
player.release();
|
||||
player = ExoPlayerFactory.newSimpleInstance(PeertubeActivity.this);
|
||||
playerView.setPlayer(player);
|
||||
loader.setVisibility(View.GONE);
|
||||
int video_cache = sharedpreferences.getInt(Helper.SET_VIDEO_CACHE, Helper.DEFAULT_VIDEO_CACHE_MB);
|
||||
ProgressiveMediaSource videoSource;
|
||||
if (video_cache == 0) {
|
||||
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(PeertubeActivity.this,
|
||||
Util.getUserAgent(PeertubeActivity.this, null), null);
|
||||
videoSource = new ProgressiveMediaSource.Factory(dataSourceFactory)
|
||||
.createMediaSource(Uri.parse(peertube.getFileUrl(res, PeertubeActivity.this)));
|
||||
} else {
|
||||
CacheDataSourceFactory cacheDataSourceFactory = new CacheDataSourceFactory(PeertubeActivity.this);
|
||||
videoSource = new ProgressiveMediaSource.Factory(cacheDataSourceFactory)
|
||||
.createMediaSource(Uri.parse(peertube.getFileUrl(res, PeertubeActivity.this)));
|
||||
}
|
||||
player.prepare(videoSource);
|
||||
player.seekTo(0, position);
|
||||
player.setPlayWhenReady(true);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
builderSingle.show();
|
||||
}
|
||||
|
||||
public void manageVIewPostActions(PeertubeAPI.StatusAction statusAction, APIResponse apiResponse) {
|
||||
|
||||
|
||||
if (peertube.isCommentsEnabled() && statusAction == PeertubeAPI.StatusAction.PEERTUBECOMMENT) {
|
||||
CommentVM commentViewModel = new ViewModelProvider(PeertubeActivity.this).get(CommentVM.class);
|
||||
commentViewModel.getComment(peertubeInstance, videoId).observe(PeertubeActivity.this, this::manageVIewComment);
|
||||
} else if (statusAction == PeertubeAPI.StatusAction.REPORT_ACCOUNT) {
|
||||
Toasty.success(PeertubeActivity.this, getString(R.string.successful_report), Toasty.LENGTH_LONG).show();
|
||||
} else if (statusAction == PeertubeAPI.StatusAction.REPORT_VIDEO) {
|
||||
Toasty.success(PeertubeActivity.this, getString(R.string.successful_video_report), Toasty.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void initFullscreenDialog() {
|
||||
|
||||
fullScreenDialog = new Dialog(this, android.R.style.Theme_Black_NoTitleBar_Fullscreen) {
|
||||
public void onBackPressed() {
|
||||
if (fullScreenMode)
|
||||
closeFullscreenDialog();
|
||||
super.onBackPressed();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void openFullscreenDialog() {
|
||||
|
||||
((ViewGroup) playerView.getParent()).removeView(playerView);
|
||||
fullScreenDialog.addContentView(playerView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
fullScreenIcon.setImageDrawable(ContextCompat.getDrawable(PeertubeActivity.this, R.drawable.ic_baseline_fullscreen_exit_24));
|
||||
fullScreenMode = true;
|
||||
fullScreenDialog.show();
|
||||
}
|
||||
|
||||
private void closeFullscreenDialog() {
|
||||
|
||||
((ViewGroup) playerView.getParent()).removeView(playerView);
|
||||
((FrameLayout) findViewById(R.id.main_media_frame)).addView(playerView);
|
||||
fullScreenMode = false;
|
||||
fullScreenDialog.dismiss();
|
||||
fullScreenIcon.setImageDrawable(ContextCompat.getDrawable(PeertubeActivity.this, R.drawable.ic_baseline_fullscreen_24));
|
||||
}
|
||||
|
||||
private void initFullscreenButton() {
|
||||
|
||||
PlayerControlView controlView = playerView.findViewById(R.id.exo_controller);
|
||||
fullScreenIcon = controlView.findViewById(R.id.exo_fullscreen_icon);
|
||||
View fullScreenButton = controlView.findViewById(R.id.exo_fullscreen_button);
|
||||
fullScreenButton.setOnClickListener(v -> {
|
||||
if (!fullScreenMode)
|
||||
openFullscreenDialog();
|
||||
else
|
||||
closeFullscreenDialog();
|
||||
});
|
||||
}
|
||||
|
||||
private void initResolution() {
|
||||
PlayerControlView controlView = playerView.findViewById(R.id.exo_controller);
|
||||
resolution = controlView.findViewById(R.id.resolution);
|
||||
resolution.setText(String.format("%sp", peertube.getResolution().get(0)));
|
||||
resolution.setOnClickListener(v -> displayResolution());
|
||||
}
|
||||
|
||||
private void changeColor() {
|
||||
|
||||
Drawable thumbUp = ContextCompat.getDrawable(PeertubeActivity.this, R.drawable.ic_baseline_thumb_up_alt_24);
|
||||
Drawable thumbDown = ContextCompat.getDrawable(PeertubeActivity.this, R.drawable.ic_baseline_thumb_down_alt_24);
|
||||
int color = getAttColor(this, android.R.attr.colorControlNormal);
|
||||
|
||||
if (thumbUp != null) {
|
||||
thumbUp.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
|
||||
DrawableCompat.setTint(thumbUp, color);
|
||||
}
|
||||
if (thumbDown != null) {
|
||||
thumbDown.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
|
||||
DrawableCompat.setTint(thumbDown, color);
|
||||
}
|
||||
if (peertube.getMyRating() != null && peertube.getMyRating().compareTo("like") == 0) {
|
||||
if (thumbUp != null) {
|
||||
thumbUp.setColorFilter(getResources().getColor(R.color.positive_thumbs), PorterDuff.Mode.SRC_ATOP);
|
||||
DrawableCompat.setTint(thumbUp, getResources().getColor(R.color.positive_thumbs));
|
||||
}
|
||||
} else if (peertube.getMyRating() != null && peertube.getMyRating().compareTo("dislike") == 0) {
|
||||
if (thumbDown != null) {
|
||||
thumbDown.setColorFilter(getResources().getColor(R.color.negative_thumbs), PorterDuff.Mode.SRC_ATOP);
|
||||
DrawableCompat.setTint(thumbDown, getResources().getColor(R.color.negative_thumbs));
|
||||
}
|
||||
}
|
||||
peertube_like_count.setCompoundDrawablesWithIntrinsicBounds(null, thumbUp, null, null);
|
||||
peertube_dislike_count.setCompoundDrawablesWithIntrinsicBounds(null, thumbDown, null, null);
|
||||
}
|
||||
|
||||
public void manageVIewPlaylists(PlaylistsVM.action actionType, APIResponse apiResponse) {
|
||||
|
||||
if (actionType == GET_PLAYLIST_FOR_VIDEO && apiResponse != null) {
|
||||
playlistForVideo = apiResponse.getPlaylistForVideos();
|
||||
} else if (actionType == GET_PLAYLIST && apiResponse != null) {
|
||||
playlists = apiResponse.getPlaylists();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,661 +0,0 @@
|
|||
package app.fedilab.fedilabtube;
|
||||
/* Copyright 2020 Thomas Schneider
|
||||
*
|
||||
* This file is a part of TubeLab
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import net.gotev.uploadservice.MultipartUploadRequest;
|
||||
import net.gotev.uploadservice.ServerResponse;
|
||||
import net.gotev.uploadservice.UploadInfo;
|
||||
import net.gotev.uploadservice.UploadNotificationConfig;
|
||||
import net.gotev.uploadservice.UploadStatusDelegate;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import app.fedilab.fedilabtube.client.APIResponse;
|
||||
import app.fedilab.fedilabtube.client.PeertubeAPI;
|
||||
import app.fedilab.fedilabtube.client.entities.Account;
|
||||
import app.fedilab.fedilabtube.client.entities.Peertube;
|
||||
import app.fedilab.fedilabtube.helper.Helper;
|
||||
import app.fedilab.fedilabtube.viewmodel.ChannelsVM;
|
||||
import app.fedilab.fedilabtube.viewmodel.FeedsVM;
|
||||
import app.fedilab.fedilabtube.viewmodel.PostActionsVM;
|
||||
import es.dmoral.toasty.Toasty;
|
||||
import mabbas007.tagsedittext.TagsEditText;
|
||||
|
||||
import static app.fedilab.fedilabtube.MainActivity.peertubeInformation;
|
||||
|
||||
|
||||
public class PeertubeEditUploadActivity extends AppCompatActivity {
|
||||
|
||||
|
||||
private final int PICK_IMAGE = 50378;
|
||||
private final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 724;
|
||||
HashMap<Integer, String> categoryToSend;
|
||||
HashMap<Integer, String> licenseToSend;
|
||||
HashMap<Integer, String> privacyToSend;
|
||||
HashMap<String, String> languageToSend;
|
||||
HashMap<String, String> channelToSend;
|
||||
private Button set_upload_submit;
|
||||
private Spinner set_upload_privacy, set_upload_categories, set_upload_licenses, set_upload_languages, set_upload_channel;
|
||||
private EditText p_video_title, p_video_description;
|
||||
private TagsEditText p_video_tags;
|
||||
private CheckBox set_upload_nsfw, set_upload_enable_comments;
|
||||
private LinkedHashMap<String, String> channels;
|
||||
private String videoId;
|
||||
private Account channel;
|
||||
private ImageView p_video_preview;
|
||||
private Button set_preview;
|
||||
private Peertube peertube;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
|
||||
|
||||
Bundle b = getIntent().getExtras();
|
||||
|
||||
if (b != null) {
|
||||
videoId = b.getString("video_id", null);
|
||||
}
|
||||
if (videoId == null) {
|
||||
videoId = sharedpreferences.getString(Helper.VIDEO_ID, null);
|
||||
}
|
||||
if (getSupportActionBar() != null)
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
setContentView(R.layout.activity_peertube_edit);
|
||||
set_upload_submit = findViewById(R.id.set_upload_submit);
|
||||
Button set_upload_delete = findViewById(R.id.set_upload_delete);
|
||||
set_upload_privacy = findViewById(R.id.set_upload_privacy);
|
||||
set_upload_channel = findViewById(R.id.set_upload_channel);
|
||||
set_upload_categories = findViewById(R.id.set_upload_categories);
|
||||
set_upload_licenses = findViewById(R.id.set_upload_licenses);
|
||||
set_upload_languages = findViewById(R.id.set_upload_languages);
|
||||
p_video_title = findViewById(R.id.p_video_title);
|
||||
p_video_description = findViewById(R.id.p_video_description);
|
||||
p_video_tags = findViewById(R.id.p_video_tags);
|
||||
p_video_preview = findViewById(R.id.p_video_preview);
|
||||
set_upload_nsfw = findViewById(R.id.set_upload_nsfw);
|
||||
set_upload_enable_comments = findViewById(R.id.set_upload_enable_comments);
|
||||
set_preview = findViewById(R.id.set_preview);
|
||||
|
||||
set_upload_delete.setOnClickListener(v -> {
|
||||
AlertDialog.Builder builderInner;
|
||||
builderInner = new AlertDialog.Builder(PeertubeEditUploadActivity.this);
|
||||
builderInner.setMessage(getString(R.string.delete_video_confirmation));
|
||||
builderInner.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
|
||||
builderInner.setPositiveButton(R.string.yes, (dialog, which) -> {
|
||||
PostActionsVM viewModel = new ViewModelProvider(PeertubeEditUploadActivity.this).get(PostActionsVM.class);
|
||||
viewModel.post(PeertubeAPI.StatusAction.PEERTUBEDELETEVIDEO, videoId, null, null).observe(PeertubeEditUploadActivity.this, apiResponse -> manageVIewPostActions(PeertubeAPI.StatusAction.PEERTUBEDELETEVIDEO, apiResponse));
|
||||
dialog.dismiss();
|
||||
});
|
||||
builderInner.show();
|
||||
});
|
||||
//Get params from the API
|
||||
LinkedHashMap<Integer, String> categories = new LinkedHashMap<>(peertubeInformation.getCategories());
|
||||
LinkedHashMap<Integer, String> licences = new LinkedHashMap<>(peertubeInformation.getLicences());
|
||||
LinkedHashMap<Integer, String> privacies = new LinkedHashMap<>(peertubeInformation.getPrivacies());
|
||||
LinkedHashMap<String, String> languages = new LinkedHashMap<>(peertubeInformation.getLanguages());
|
||||
LinkedHashMap<String, String> translations = null;
|
||||
|
||||
if (peertubeInformation.getTranslations() != null)
|
||||
translations = new LinkedHashMap<>(peertubeInformation.getTranslations());
|
||||
//Populate catgories
|
||||
String[] categoriesA = new String[categories.size()];
|
||||
Iterator<Map.Entry<Integer, String>> it = categories.entrySet().iterator();
|
||||
int i = 0;
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<Integer, String> pair = it.next();
|
||||
if (translations == null || translations.size() == 0 || !translations.containsKey(pair.getValue()))
|
||||
categoriesA[i] = pair.getValue();
|
||||
else
|
||||
categoriesA[i] = translations.get(pair.getValue());
|
||||
it.remove();
|
||||
i++;
|
||||
}
|
||||
ArrayAdapter<String> adapterCatgories = new ArrayAdapter<>(PeertubeEditUploadActivity.this,
|
||||
android.R.layout.simple_spinner_dropdown_item, categoriesA);
|
||||
set_upload_categories.setAdapter(adapterCatgories);
|
||||
|
||||
|
||||
//Populate licenses
|
||||
String[] licensesA = new String[licences.size()];
|
||||
it = licences.entrySet().iterator();
|
||||
i = 0;
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<Integer, String> pair = it.next();
|
||||
if (translations == null || translations.size() == 0 || !translations.containsKey(pair.getValue()))
|
||||
licensesA[i] = pair.getValue();
|
||||
else
|
||||
licensesA[i] = translations.get(pair.getValue());
|
||||
it.remove();
|
||||
i++;
|
||||
}
|
||||
ArrayAdapter<String> adapterLicenses = new ArrayAdapter<>(PeertubeEditUploadActivity.this,
|
||||
android.R.layout.simple_spinner_dropdown_item, licensesA);
|
||||
set_upload_licenses.setAdapter(adapterLicenses);
|
||||
|
||||
|
||||
//Populate languages
|
||||
String[] languagesA = new String[languages.size()];
|
||||
Iterator<Map.Entry<String, String>> itl = languages.entrySet().iterator();
|
||||
i = 0;
|
||||
while (itl.hasNext()) {
|
||||
Map.Entry<String, String> pair = itl.next();
|
||||
if (translations == null || translations.size() == 0 || !translations.containsKey(pair.getValue()))
|
||||
languagesA[i] = pair.getValue();
|
||||
else
|
||||
languagesA[i] = translations.get(pair.getValue());
|
||||
itl.remove();
|
||||
i++;
|
||||
}
|
||||
ArrayAdapter<String> adapterLanguages = new ArrayAdapter<>(PeertubeEditUploadActivity.this,
|
||||
android.R.layout.simple_spinner_dropdown_item, languagesA);
|
||||
set_upload_languages.setAdapter(adapterLanguages);
|
||||
|
||||
|
||||
//Populate languages
|
||||
String[] privaciesA = new String[privacies.size()];
|
||||
it = privacies.entrySet().iterator();
|
||||
i = 0;
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<Integer, String> pair = it.next();
|
||||
if (translations == null || translations.size() == 0 || !translations.containsKey(pair.getValue()))
|
||||
privaciesA[i] = pair.getValue();
|
||||
else
|
||||
privaciesA[i] = translations.get(pair.getValue());
|
||||
it.remove();
|
||||
i++;
|
||||
}
|
||||
|
||||
ArrayAdapter<String> adapterPrivacies = new ArrayAdapter<>(PeertubeEditUploadActivity.this,
|
||||
android.R.layout.simple_spinner_dropdown_item, privaciesA);
|
||||
set_upload_privacy.setAdapter(adapterPrivacies);
|
||||
|
||||
|
||||
String peertubeInstance = Helper.getLiveInstance(PeertubeEditUploadActivity.this);
|
||||
FeedsVM feedsViewModel = new ViewModelProvider(PeertubeEditUploadActivity.this).get(FeedsVM.class);
|
||||
feedsViewModel.getVideo(peertubeInstance, videoId).observe(PeertubeEditUploadActivity.this, this::manageVIewVideo);
|
||||
channels = new LinkedHashMap<>();
|
||||
|
||||
setTitle(R.string.edit_video);
|
||||
}
|
||||
|
||||
|
||||
public void manageVIewVideo(APIResponse apiResponse) {
|
||||
if (apiResponse.getError() != null || apiResponse.getPeertubes() == null || apiResponse.getPeertubes().size() == 0) {
|
||||
if (apiResponse.getError() != null && apiResponse.getError().getError() != null)
|
||||
Toasty.error(PeertubeEditUploadActivity.this, apiResponse.getError().getError(), Toast.LENGTH_LONG).show();
|
||||
else
|
||||
Toasty.error(PeertubeEditUploadActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
|
||||
set_upload_submit.setEnabled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
//Peertube video
|
||||
peertube = apiResponse.getPeertubes().get(0);
|
||||
|
||||
if (peertube.isUpdate()) {
|
||||
Toasty.success(PeertubeEditUploadActivity.this, getString(R.string.toast_peertube_video_updated), Toast.LENGTH_LONG).show();
|
||||
peertube.setUpdate(false);
|
||||
set_upload_submit.setEnabled(true);
|
||||
} else {
|
||||
ChannelsVM viewModelC = new ViewModelProvider(PeertubeEditUploadActivity.this).get(ChannelsVM.class);
|
||||
viewModelC.get().observe(PeertubeEditUploadActivity.this, this::manageVIewChannels);
|
||||
}
|
||||
|
||||
languageToSend = peertube.getLanguage();
|
||||
licenseToSend = peertube.getLicense();
|
||||
privacyToSend = peertube.getPrivacy();
|
||||
categoryToSend = peertube.getCategory();
|
||||
|
||||
Glide.with(PeertubeEditUploadActivity.this)
|
||||
.load("https://" + peertube.getInstance() + peertube.getThumbnailPath())
|
||||
.into(p_video_preview);
|
||||
|
||||
set_preview.setOnClickListener(v -> {
|
||||
if (ContextCompat.checkSelfPermission(PeertubeEditUploadActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) !=
|
||||
PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(PeertubeEditUploadActivity.this,
|
||||
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
|
||||
MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
|
||||
return;
|
||||
}
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setType("image/jpg");
|
||||
String[] mimetypes = {"image/jpg", "image/jpeg"};
|
||||
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimetypes);
|
||||
startActivityForResult(intent, PICK_IMAGE);
|
||||
|
||||
});
|
||||
|
||||
if (languageToSend == null) {
|
||||
LinkedHashMap<String, String> languages = new LinkedHashMap<>(peertubeInformation.getLanguages());
|
||||
Map.Entry<String, String> entryString = languages.entrySet().iterator().next();
|
||||
languageToSend = new HashMap<>();
|
||||
languageToSend.put(entryString.getKey(), entryString.getValue());
|
||||
}
|
||||
|
||||
if (licenseToSend == null) {
|
||||
LinkedHashMap<Integer, String> licences = new LinkedHashMap<>(peertubeInformation.getLicences());
|
||||
Map.Entry<Integer, String> entryInt = licences.entrySet().iterator().next();
|
||||
licenseToSend = new HashMap<>();
|
||||
licenseToSend.put(entryInt.getKey(), entryInt.getValue());
|
||||
}
|
||||
|
||||
if (categoryToSend == null) {
|
||||
LinkedHashMap<Integer, String> categories = new LinkedHashMap<>(peertubeInformation.getCategories());
|
||||
Map.Entry<Integer, String> entryInt = categories.entrySet().iterator().next();
|
||||
categoryToSend = new HashMap<>();
|
||||
categoryToSend.put(entryInt.getKey(), entryInt.getValue());
|
||||
}
|
||||
if (privacyToSend == null) {
|
||||
LinkedHashMap<Integer, String> privacies = new LinkedHashMap<>(peertubeInformation.getPrivacies());
|
||||
Map.Entry<Integer, String> entryInt = privacies.entrySet().iterator().next();
|
||||
privacyToSend = new HashMap<>();
|
||||
privacyToSend.put(entryInt.getKey(), entryInt.getValue());
|
||||
}
|
||||
|
||||
String language = null;
|
||||
if (languageToSend != null) {
|
||||
Map.Entry<String, String> entryString = languageToSend.entrySet().iterator().next();
|
||||
language = entryString.getValue();
|
||||
}
|
||||
|
||||
String license = null;
|
||||
if (licenseToSend != null) {
|
||||
Map.Entry<Integer, String> entryInt = licenseToSend.entrySet().iterator().next();
|
||||
license = entryInt.getValue();
|
||||
}
|
||||
|
||||
String privacy = null;
|
||||
if (privacyToSend != null) {
|
||||
Map.Entry<Integer, String> entryInt = privacyToSend.entrySet().iterator().next();
|
||||
privacy = entryInt.getValue();
|
||||
}
|
||||
|
||||
String category = null;
|
||||
if (categoryToSend != null) {
|
||||
Map.Entry<Integer, String> entryInt = categoryToSend.entrySet().iterator().next();
|
||||
category = entryInt.getValue();
|
||||
}
|
||||
channel = peertube.getChannel();
|
||||
String title = peertube.getName();
|
||||
boolean commentEnabled = peertube.isCommentsEnabled();
|
||||
boolean isNSFW = peertube.isSensitive();
|
||||
|
||||
set_upload_enable_comments.setChecked(commentEnabled);
|
||||
set_upload_nsfw.setChecked(isNSFW);
|
||||
|
||||
p_video_title.setText(title);
|
||||
p_video_description.setText(peertube.getDescription());
|
||||
|
||||
LinkedHashMap<Integer, String> categories = new LinkedHashMap<>(peertubeInformation.getCategories());
|
||||
LinkedHashMap<Integer, String> licences = new LinkedHashMap<>(peertubeInformation.getLicences());
|
||||
LinkedHashMap<Integer, String> privacies = new LinkedHashMap<>(peertubeInformation.getPrivacies());
|
||||
LinkedHashMap<String, String> languages = new LinkedHashMap<>(peertubeInformation.getLanguages());
|
||||
|
||||
|
||||
int languagePosition = 0;
|
||||
if (languages.containsValue(language)) {
|
||||
Iterator<Map.Entry<String, String>> it = languages.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<String, String> pair = it.next();
|
||||
if (pair.getValue().equals(language))
|
||||
break;
|
||||
it.remove();
|
||||
languagePosition++;
|
||||
}
|
||||
}
|
||||
int privacyPosition = 0;
|
||||
if (privacy != null && privacies.containsValue(privacy)) {
|
||||
Iterator<Map.Entry<Integer, String>> it = privacies.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<Integer, String> pair = it.next();
|
||||
if (pair.getValue().equals(privacy))
|
||||
break;
|
||||
it.remove();
|
||||
privacyPosition++;
|
||||
}
|
||||
}
|
||||
int licensePosition = 0;
|
||||
if (license != null && licences.containsValue(license)) {
|
||||
Iterator<Map.Entry<Integer, String>> it = licences.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<Integer, String> pair = it.next();
|
||||
if (pair.getValue().equals(license))
|
||||
break;
|
||||
it.remove();
|
||||
licensePosition++;
|
||||
}
|
||||
}
|
||||
int categoryPosition = 0;
|
||||
if (category != null && categories.containsValue(category)) {
|
||||
Iterator<Map.Entry<Integer, String>> it = categories.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<Integer, String> pair = it.next();
|
||||
if (pair.getValue().equals(category))
|
||||
break;
|
||||
it.remove();
|
||||
categoryPosition++;
|
||||
}
|
||||
}
|
||||
//Manage privacies
|
||||
set_upload_privacy.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
LinkedHashMap<Integer, String> privaciesCheck = new LinkedHashMap<>(peertubeInformation.getPrivacies());
|
||||
Iterator<Map.Entry<Integer, String>> it = privaciesCheck.entrySet().iterator();
|
||||
int i = 0;
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<Integer, String> pair = it.next();
|
||||
if (i == position) {
|
||||
privacyToSend = new HashMap<>();
|
||||
privacyToSend.put(pair.getKey(), pair.getValue());
|
||||
break;
|
||||
}
|
||||
it.remove();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
|
||||
}
|
||||
});
|
||||
set_upload_licenses.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
LinkedHashMap<Integer, String> licensesCheck = new LinkedHashMap<>(peertubeInformation.getLicences());
|
||||
Iterator<Map.Entry<Integer, String>> it = licensesCheck.entrySet().iterator();
|
||||
int i = 0;
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<Integer, String> pair = it.next();
|
||||
if (i == position) {
|
||||
licenseToSend = new HashMap<>();
|
||||
licenseToSend.put(pair.getKey(), pair.getValue());
|
||||
break;
|
||||
}
|
||||
it.remove();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
|
||||
}
|
||||
});
|
||||
//Manage categories
|
||||
set_upload_categories.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
LinkedHashMap<Integer, String> categoriesCheck = new LinkedHashMap<>(peertubeInformation.getCategories());
|
||||
Iterator<Map.Entry<Integer, String>> it = categoriesCheck.entrySet().iterator();
|
||||
int i = 0;
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<Integer, String> pair = it.next();
|
||||
if (i == position) {
|
||||
categoryToSend = new HashMap<>();
|
||||
categoryToSend.put(pair.getKey(), pair.getValue());
|
||||
break;
|
||||
}
|
||||
it.remove();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
//Manage languages
|
||||
set_upload_languages.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
LinkedHashMap<String, String> languagesCheck = new LinkedHashMap<>(peertubeInformation.getLanguages());
|
||||
Iterator<Map.Entry<String, String>> it = languagesCheck.entrySet().iterator();
|
||||
int i = 0;
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<String, String> pair = it.next();
|
||||
if (i == position) {
|
||||
languageToSend = new HashMap<>();
|
||||
languageToSend.put(pair.getKey(), pair.getValue());
|
||||
break;
|
||||
}
|
||||
it.remove();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
|
||||
}
|
||||
});
|
||||
//Manage languages
|
||||
set_upload_channel.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
LinkedHashMap<String, String> channelsCheck = new LinkedHashMap<>(channels);
|
||||
Iterator<Map.Entry<String, String>> it = channelsCheck.entrySet().iterator();
|
||||
int i = 0;
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<String, String> pair = it.next();
|
||||
if (i == position) {
|
||||
channelToSend = new HashMap<>();
|
||||
channelToSend.put(pair.getKey(), pair.getValue());
|
||||
|
||||
break;
|
||||
}
|
||||
it.remove();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
set_upload_submit.setOnClickListener(v -> {
|
||||
String title1 = p_video_title.getText().toString().trim();
|
||||
String description = p_video_description.getText().toString().trim();
|
||||
boolean isNSFW1 = set_upload_nsfw.isChecked();
|
||||
boolean commentEnabled1 = set_upload_enable_comments.isChecked();
|
||||
peertube.setName(title1);
|
||||
peertube.setDescription(description);
|
||||
peertube.setSensitive(isNSFW1);
|
||||
peertube.setCommentsEnabled(commentEnabled1);
|
||||
peertube.setCategory(categoryToSend);
|
||||
peertube.setLicense(licenseToSend);
|
||||
peertube.setLanguage(languageToSend);
|
||||
peertube.setChannelForUpdate(channelToSend);
|
||||
peertube.setPrivacy(privacyToSend);
|
||||
List<String> tags = p_video_tags.getTags();
|
||||
peertube.setTags(tags);
|
||||
set_upload_submit.setEnabled(false);
|
||||
FeedsVM feedsViewModel = new ViewModelProvider(PeertubeEditUploadActivity.this).get(FeedsVM.class);
|
||||
feedsViewModel.updateVideo(peertube).observe(PeertubeEditUploadActivity.this, this::manageVIewVideo);
|
||||
});
|
||||
|
||||
set_upload_privacy.setSelection(privacyPosition);
|
||||
set_upload_languages.setSelection(languagePosition);
|
||||
set_upload_licenses.setSelection(licensePosition);
|
||||
set_upload_categories.setSelection(categoryPosition);
|
||||
|
||||
List<String> tags = peertube.getTags();
|
||||
if (tags != null && tags.size() > 0) {
|
||||
String[] tagsA = tags.toArray(new String[0]);
|
||||
p_video_tags.setTags(tagsA);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (requestCode == PICK_IMAGE && resultCode == Activity.RESULT_OK) {
|
||||
if (data == null || data.getData() == null) {
|
||||
Toasty.error(PeertubeEditUploadActivity.this, getString(R.string.toot_select_image_error), Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
UploadNotificationConfig uploadConfig = new UploadNotificationConfig();
|
||||
uploadConfig.getCompleted().autoClear = true;
|
||||
try {
|
||||
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
|
||||
String token = sharedpreferences.getString(Helper.PREF_KEY_OAUTH_TOKEN, null);
|
||||
Uri uri = data.getData();
|
||||
try {
|
||||
String uploadId = UUID.randomUUID().toString();
|
||||
new MultipartUploadRequest(PeertubeEditUploadActivity.this, uploadId, "https://" + Helper.getLiveInstance(PeertubeEditUploadActivity.this) + "/api/v1/" + String.format("/videos/%s", peertube.getId()))
|
||||
.addFileToUpload(uri.toString().replace("file://", ""), "previewfile")
|
||||
.setMethod("PUT")
|
||||
.addHeader("Authorization", "Bearer " + token)
|
||||
.setNotificationConfig(uploadConfig)
|
||||
.setMaxRetries(2)
|
||||
.setDelegate(new UploadStatusDelegate() {
|
||||
@Override
|
||||
public void onProgress(Context context, UploadInfo uploadInfo) {
|
||||
// your code here
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Context context, UploadInfo uploadInfo, ServerResponse serverResponse,
|
||||
Exception exception) {
|
||||
Toasty.error(PeertubeEditUploadActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompleted(Context context, UploadInfo uploadInfo, ServerResponse serverResponse) {
|
||||
Glide.with(PeertubeEditUploadActivity.this)
|
||||
.load(uri)
|
||||
.into(p_video_preview);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancelled(Context context, UploadInfo uploadInfo) {
|
||||
// your code here
|
||||
}
|
||||
})
|
||||
.startUpload();
|
||||
} catch (FileNotFoundException e) {
|
||||
Toasty.error(PeertubeEditUploadActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
Toasty.error(PeertubeEditUploadActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
|
||||
public void manageVIewChannels(APIResponse apiResponse) {
|
||||
if (apiResponse.getError() != null || apiResponse.getAccounts() == null || apiResponse.getAccounts().size() == 0) {
|
||||
if (apiResponse.getError().getError() != null)
|
||||
Toasty.error(PeertubeEditUploadActivity.this, apiResponse.getError().getError(), Toast.LENGTH_LONG).show();
|
||||
else
|
||||
Toasty.error(PeertubeEditUploadActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
//Populate channels
|
||||
List<Account> accounts = apiResponse.getAccounts();
|
||||
String[] channelName = new String[accounts.size()];
|
||||
int i = 0;
|
||||
for (Account account : accounts) {
|
||||
channels.put(account.getUsername(), account.getId());
|
||||
channelName[i] = account.getUsername();
|
||||
i++;
|
||||
}
|
||||
ArrayAdapter<String> adapterChannel = new ArrayAdapter<>(PeertubeEditUploadActivity.this,
|
||||
android.R.layout.simple_spinner_dropdown_item, channelName);
|
||||
set_upload_channel.setAdapter(adapterChannel);
|
||||
int channelPosition = 0;
|
||||
if (channels.containsKey(channel.getUsername())) {
|
||||
LinkedHashMap<String, String> channelsIterator = new LinkedHashMap<>(channels);
|
||||
Iterator<Map.Entry<String, String>> it = channelsIterator.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<String, String> pair = it.next();
|
||||
if (pair.getKey().equals(channel.getUsername())) {
|
||||
channelToSend = new HashMap<>();
|
||||
channelToSend.put(pair.getKey(), pair.getValue());
|
||||
break;
|
||||
}
|
||||
it.remove();
|
||||
channelPosition++;
|
||||
}
|
||||
}
|
||||
set_upload_channel.setSelection(channelPosition);
|
||||
set_upload_submit.setEnabled(true);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void manageVIewPostActions(PeertubeAPI.StatusAction statusAction, APIResponse apiResponse) {
|
||||
Intent intent = new Intent(PeertubeEditUploadActivity.this, MainActivity.class);
|
||||
intent.putExtra(Helper.INTENT_ACTION, Helper.RELOAD_MYVIDEOS);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
}
|