Compare commits

...

603 Commits

Author SHA1 Message Date
Thomas e19526dbf6 Release 1.15 2022-07-01 09:47:30 +02:00
Thomas f6192881d3 Fixes 2022-07-01 09:44:00 +02:00
Thomas 309c6aa890 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!67
2022-07-01 07:41:54 +00:00
Thomas 9f6ac90074 New Crowdin updates 2022-07-01 07:41:54 +00:00
Thomas 8d4418bf2b Release 1.15.0 2022-07-01 08:43:47 +02:00
Thomas 3d85e74957 Fix playlist export/import 2022-06-03 11:41:26 +02:00
Thomas fda17ee8fe Fix issue #21 - Prompt instances for avoiding default down ones 2022-05-30 11:06:24 +02:00
Thomas 5696809c1d fix manifest issues 2022-05-30 09:01:23 +02:00
Thomas e03147c6da fix 2022-05-13 16:52:49 +02:00
Thomas 7c695f5f82 remove torrent lib 2022-05-13 16:41:58 +02:00
Thomas 1c6f7858ca some fixes 2022-05-13 14:11:11 +02:00
Thomas 1ef0389997 some fixes 2022-05-13 10:58:38 +02:00
Thomas 1c54d44a22 Some layout improvements 2022-05-12 17:46:08 +02:00
Thomas 724b43ca4d Some layout improvements 2022-05-12 15:12:18 +02:00
Thomas ed3d978b03 Fix theme between flavors 2022-05-10 10:47:51 +02:00
Thomas af53071b08 Fix authentication with openid 2022-05-10 10:19:45 +02:00
Thomas bd8e2a50d9 Fix some color issues 2022-05-10 09:20:01 +02:00
Thomas e5c918af51 Fix some color issues 2022-05-10 08:30:14 +02:00
Thomas 4077c5bc55 some cleaning 2022-05-10 08:06:32 +02:00
Thomas 2b43f32772 Fetch openId version 2022-05-09 12:03:49 +02:00
Thomas 1e0eafef9b Customize instances 2022-05-09 10:40:51 +02:00
Thomas 45b35d0718 Customize instances 2022-05-09 10:25:07 +02:00
Thomas a9286ab150 theming 2022-05-05 10:08:04 +02:00
Thomas fcb1974e78 theming 2022-05-05 08:53:25 +02:00
Thomas 2456e8f782 Merge branch 'develop' of https://framagit.org/tom79/fedilab-tube into develop
 Conflicts:
	app/build.gradle
	app/src/main/java/app/fedilab/fedilabtube/helper/HelperAcadInstance.java
2022-05-05 08:28:01 +02:00
Thomas ce4913452b some upgrades 2022-05-04 09:43:54 +02:00
Thomas e605dd8417 some upgrades 2022-05-03 15:10:37 +02:00
Thomas 8434f9ee00 change 2021-08-26 11:16:05 +02:00
Thomas 61bb7d962d remove flavor 2021-08-23 15:43:32 +02:00
Thomas 35aec32070 some changes 2021-05-02 18:59:05 +02:00
Thomas 274bcc8be7 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!66
2021-05-02 16:55:11 +00:00
Thomas ce70df5137 New Crowdin updates 2021-05-02 16:55:11 +00:00
Thomas d9dca3ef23 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!65
2021-01-29 17:04:22 +00:00
Thomas e3635c3f01 New Crowdin updates 2021-01-29 18:04:21 +01:00
Thomas 2cdabbcb70 Release 1.13.1 2021-01-23 17:23:53 +01:00
Thomas d5ad9b181b Release 1.13.1 2021-01-23 17:14:32 +01:00
Thomas 540fb3e2dc Update ReadMe remove useless accounts 2021-01-23 17:07:58 +01:00
Thomas edbe65593b Some fixes 2021-01-23 17:03:26 +01:00
Thomas d5f394dfea Fix issue with Manifest merging 2021-01-17 10:29:13 +01:00
Thomas d5a5fdf52e Release 1.13.0 2021-01-16 18:25:59 +01:00
Thomas a7f9256947 Small fixes 2021-01-16 14:14:15 +01:00
Thomas d769729901 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!64
2021-01-16 11:34:44 +01:00
Thomas b2026c8784 New Crowdin updates 2021-01-16 11:34:44 +01:00
Thomas b29de141ef Add cast library for Google release only - Checked through Exodus 2021-01-16 11:33:59 +01:00
Thomas 6d4772da75 Fix issue #170 2021-01-11 17:42:54 +01:00
Thomas 2344fe0942 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!63
2021-01-09 18:47:38 +01:00
Thomas 7c309b68b8 New Crowdin updates 2021-01-09 18:47:38 +01:00
Thomas c8c5e56a17 Cannot comment reply with Pleroma accounts 2021-01-09 18:47:08 +01:00
Thomas cef227ba42 Release notes 2021-01-09 17:38:25 +01:00
Thomas 02296b038a Release 1.12.0 2021-01-09 17:33:53 +01:00
Thomas b76a4cfcf5 Fix issue #160 #87 #88 - Notification counter + mark them all as read 2021-01-09 17:18:32 +01:00
Thomas f168f101bc Fix issue #160 - Add a notification counter 2021-01-09 14:13:34 +01:00
Thomas 2e8a86fe20 Fix issue #160 - Move account item to make it visible in top bar 2021-01-09 10:52:34 +01:00
Thomas fe0d2fe726 fix gradle issue 2021-01-09 10:48:11 +01:00
Thomas 9b322cc922 Fix issue #165 2021-01-09 10:42:37 +01:00
Thomas 346656e53d Fix issue #167 2021-01-09 09:21:26 +01:00
Thomas 6e6187175a Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!62
2021-01-08 18:08:28 +01:00
Thomas 5e832fa046 New Crowdin updates 2021-01-08 18:08:28 +01:00
Thomas 34007d4507 remove signingConfigs 2021-01-08 17:57:26 +01:00
Thomas fd400f025e Merge branch 'donation_google' into develop
# Conflicts:
#	.gitignore
2021-01-08 17:45:00 +01:00
Thomas f3f474ee13 Some fixes 2021-01-08 17:44:32 +01:00
Thomas d971032d52 Some changes 2021-01-08 11:29:49 +01:00
Thomas 961c77103e Some changes 2021-01-08 11:18:01 +01:00
Thomas b22b21c47a Some changes 2021-01-07 17:39:47 +01:00
Thomas 6d70bd758a Some changes 2021-01-06 19:23:44 +01:00
Thomas 087ac92f15 gitignore 2021-01-06 10:30:05 +01:00
Thomas 99fe789f30 Fix issue #164 & #156 2021-01-05 18:37:58 +01:00
Thomas 10892f92f1 Fix issue #162 2021-01-05 17:41:38 +01:00
Thomas 0a919c85ab Fix issue #163 2021-01-05 17:37:27 +01:00
Thomas 761abc013f Allow donation through Google 2021-01-05 17:26:21 +01:00
Thomas 327f6f0e8d Release notes 2021-01-03 16:06:15 +01:00
Thomas d6f1a360d2 Release notes 2021-01-03 16:05:47 +01:00
Thomas 24ec69d7f7 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!61
2021-01-03 16:01:01 +01:00
Thomas c80692bd34 New Crowdin updates 2021-01-03 16:01:00 +01:00
Thomas b5e9f70be6 Allow to reblog/unreblog, favourite/unfavourite, bookmark/unbookmark videos from mastodon/pleroma Accounts 2021-01-03 12:10:34 +01:00
Thomas d446081331 Small fix 2021-01-03 10:02:11 +01:00
Thomas 8178cff72c Small fix 2021-01-02 18:28:13 +01:00
Thomas 950d99b5de Prevent to check notifications for remote accounts 2021-01-02 18:20:36 +01:00
Thomas b7855cb1a2 Working post comments from Mastodon/Pleroma 2021-01-02 18:09:09 +01:00
Thomas b298fbfa3e Some changes 2021-01-02 13:38:58 +01:00
Thomas d83929f80a Some changes 2021-01-02 11:21:30 +01:00
Thomas b932ed2c13 Some fixes 2020-12-31 15:32:38 +01:00
Thomas 36073d340d Allow connection with Mastodon & Pleroma accounts 2020-12-31 14:19:26 +01:00
Thomas 0e14540b69 Allow connection of Mastodon & Pleroma accounts 2020-12-31 11:19:43 +01:00
Thomas 57327a8ad0 Check rights 2020-12-30 16:20:49 +01:00
Thomas bbfa278d6b Implement logic 2020-12-30 15:37:09 +01:00
Thomas 439decf6a9 Merge remote-tracking branch 'origin/develop' into develop 2020-12-30 12:21:49 +01:00
Thomas 2277cc5f05 Some changes 2020-12-30 12:21:40 +01:00
Thomas 4204ffccee Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!60
2020-12-30 10:11:25 +01:00
Thomas 31407e709d New Crowdin updates 2020-12-30 10:11:25 +01:00
Thomas 44d26bb1cf Merge remote-tracking branch 'origin/develop' into develop 2020-12-29 17:11:56 +01:00
Thomas 8a8a433023 Some changes 2020-12-29 17:11:36 +01:00
Thomas 5c27292543 Fix #138 #155 2020-12-29 16:53:02 +01:00
Thomas e475348d39 Some fixes 2020-12-29 09:55:15 +01:00
Thomas 9f8358e471 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!59
2020-12-28 17:36:02 +01:00
Thomas 4fd8d42d85 Some fixes 2020-12-28 15:43:59 +01:00
Thomas 498990c48a New translations strings.xml (French) 2020-12-28 15:43:37 +01:00
Thomas 1cddf26c9a Some fixes 2020-12-28 15:39:18 +01:00
Thomas 325a239b86 clean 2020-12-26 17:34:30 +01:00
Thomas 2c4ef9c3ce New translations strings.xml (Russian) 2020-12-25 20:06:50 +01:00
Thomas 4dbd191c4f Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!58
2020-12-25 10:33:12 +01:00
Thomas 01e489da10 New Crowdin updates 2020-12-25 10:33:12 +01:00
Thomas 53a7062c6d clean 2020-12-24 17:10:16 +01:00
Thomas 3425e1e593 Merge remote-tracking branch 'origin/develop' into develop 2020-12-24 16:40:35 +01:00
Thomas 9970635ff8 Fix issue #154 2020-12-24 16:40:18 +01:00
Thomas c1f174a5b8 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!57
2020-12-24 15:32:59 +01:00
Thomas 3587e7c524 New Crowdin updates 2020-12-24 15:32:59 +01:00
Thomas 3911ad15a6 fix name 2020-12-24 12:01:59 +01:00
Thomas d40b35da59 Fix issue #158 2020-12-24 11:57:27 +01:00
Thomas ccb6e184cc Fix issue #151 2020-12-24 11:42:06 +01:00
Thomas 74e45b1820 Quick fix 2020-12-18 18:36:32 +01:00
Thomas 0a1336f0e0 Release 1.10.2 2020-12-18 18:00:47 +01:00
Thomas d5a0dcb980 Fix issue #152 2020-12-18 16:49:18 +01:00
Thomas 83e7c41ca0 Merge branch 'l10n_develop' into develop 2020-12-18 16:35:05 +01:00
Thomas 1d1b0c11a9 fix CI 2020-12-18 14:41:48 +01:00
Thomas 3b2c4e2ac6 New translations strings.xml (Chinese Traditional) 2020-12-18 14:41:27 +01:00
Thomas 2d77fe580f New translations strings.xml (Chinese Simplified) 2020-12-18 14:41:23 +01:00
Thomas 7ae20f43f8 New translations strings.xml (Swedish) 2020-12-18 14:41:19 +01:00
Thomas f03c1b206b New translations strings.xml (Russian) 2020-12-18 14:41:16 +01:00
Thomas d99a58f2cf New translations strings.xml (Portuguese) 2020-12-18 14:41:12 +01:00
Thomas 5aeaf7f34b New translations strings.xml (Polish) 2020-12-18 14:41:09 +01:00
Thomas af0b484d16 New translations strings.xml (Dutch) 2020-12-18 14:41:06 +01:00
Thomas 0a6791b752 New translations strings.xml (Korean) 2020-12-18 14:41:02 +01:00
Thomas e73e306d05 New translations strings.xml (Japanese) 2020-12-18 14:40:58 +01:00
Thomas 52189abbff New translations strings.xml (Italian) 2020-12-18 14:40:53 +01:00
Thomas d721f12d74 New translations strings.xml (Greek) 2020-12-18 14:40:49 +01:00
Thomas 69f28bb647 New translations strings.xml (German) 2020-12-18 14:40:45 +01:00
Thomas 2b2295d831 New translations strings.xml (Arabic) 2020-12-18 14:40:41 +01:00
Thomas 179586b8c4 New translations strings.xml (Spanish) 2020-12-18 14:40:38 +01:00
Thomas 1afad9e06a New translations strings.xml (French) 2020-12-18 14:40:35 +01:00
Thomas 59c73fd864 New translations strings.xml (Romanian) 2020-12-18 14:40:30 +01:00
Thomas 6820344750 Fix #145 and #153 2020-12-18 14:31:36 +01:00
Thomas 680504791c New translations strings.xml (Chinese Traditional) 2020-12-17 17:53:31 +01:00
Thomas 41e500a8f8 New translations strings.xml (Chinese Simplified) 2020-12-17 17:53:28 +01:00
Thomas 448af1ef9a New translations strings.xml (Swedish) 2020-12-17 17:53:23 +01:00
Thomas 041e8c0bd6 New translations strings.xml (Russian) 2020-12-17 17:53:19 +01:00
Thomas 0b7300e93a New translations strings.xml (Polish) 2020-12-17 17:53:16 +01:00
Thomas 94c5f5a705 New translations strings.xml (Dutch) 2020-12-17 17:53:12 +01:00
Thomas fa2f8a7b05 New translations strings.xml (Korean) 2020-12-17 17:53:09 +01:00
Thomas aeb288142e New translations strings.xml (Japanese) 2020-12-17 17:53:06 +01:00
Thomas 635c43f458 New translations strings.xml (Italian) 2020-12-17 17:53:03 +01:00
Thomas d36138431b New translations strings.xml (Greek) 2020-12-17 17:52:58 +01:00
Thomas 9cdf857730 New translations strings.xml (German) 2020-12-17 17:52:55 +01:00
Thomas 52a6152af6 New translations strings.xml (Arabic) 2020-12-17 17:52:52 +01:00
Thomas 9d3312c081 New translations strings.xml (Spanish) 2020-12-17 17:52:48 +01:00
Thomas 1146236f46 New translations strings.xml (Portuguese) 2020-12-17 17:52:44 +01:00
Thomas ec19ee1e55 New translations strings.xml (French) 2020-12-17 17:52:39 +01:00
Thomas cc37e40158 New translations strings.xml (Romanian) 2020-12-17 17:52:05 +01:00
Thomas bdd12de34d Fix issues #150 #149 #148 #147 2020-12-17 17:37:40 +01:00
Thomas e64692d0d3 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!55
2020-12-17 14:37:10 +01:00
Thomas 7da8c0f664 New Crowdin updates 2020-12-17 14:37:10 +01:00
Thomas fc41c077dc move fastlane 2020-12-17 14:16:49 +01:00
Thomas 50800da4b9 move fastlane 2020-12-17 14:01:35 +01:00
Thomas a9219e8a91 move fastlane 2020-12-17 14:00:12 +01:00
Thomas 5eedadef47 New instance acad + matomo (acad flavor only) 2020-12-16 17:24:23 +01:00
Thomas 14cde8e625 Fixes 2020-12-16 10:14:46 +01:00
Thomas 1f2ecd591d Matomo for acad flavor 2020-12-14 16:41:29 +01:00
Thomas 9a2eb6cd49 Support openid 2020-12-14 14:42:28 +01:00
Thomas aa38514bcb Merge branch 'develop' of https://framagit.org/tom79/fedilab-tube into develop 2020-12-14 08:27:49 +01:00
Thomas f2fddfb16c typo 2020-12-13 15:41:26 +01:00
Thomas 05300682c1 Fixes 2020-12-13 15:41:00 +01:00
Thomas a3714a4ecf Fix issue #143 2020-12-13 11:48:56 +01:00
Thomas 500584b9ef Fix some issues 2020-12-13 09:32:33 +01:00
Thomas 33ac822957 fix issue #142 2020-12-13 08:53:22 +01:00
Thomas 1f6107e238 Truncate long descriptions for instances with a way to expand them. 2020-12-12 15:41:28 +01:00
Thomas 2b7639599c Prepare release notes 2020-12-12 15:07:43 +01:00
Thomas dedf7b0163 Fix issue #125 2020-12-12 14:58:28 +01:00
Thomas 88b5a83fb1 Fix issue #127 2020-12-12 14:47:59 +01:00
Thomas efd6b0088f Fix issue #119 2020-12-12 14:45:14 +01:00
Thomas ccb5cd20b1 Merge remote-tracking branch 'origin/develop' into develop 2020-12-12 14:39:29 +01:00
Thomas 668e41bc9b Fix issue #122 2020-12-12 14:39:20 +01:00
Thomas 46123fa7d6 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!54
2020-12-12 14:34:48 +01:00
Thomas b079965de8 New Crowdin updates 2020-12-12 14:34:47 +01:00
Thomas 842ab914a4 Reverse to Fastlane with Flavors 2020-12-12 14:17:29 +01:00
Thomas fcb93b7dc6 update details 2020-12-12 09:32:55 +01:00
Thomas f1420fe29e Create flavor 2020-12-11 18:37:35 +01:00
Thomas 23f8674adc Fix #136 - crash with download button and lives 2020-12-11 17:59:24 +01:00
Thomas 76a4aa5ae6 Fix #136 - crash with download button and lives 2020-12-11 17:16:29 +01:00
Thomas 85ffb4064b clean 2020-12-09 18:26:52 +01:00
Thomas 73c9e639b6 Some improvements with cast 2020-12-09 18:26:11 +01:00
Thomas 5172695784 some fixes 2020-12-09 15:45:54 +01:00
Thomas fcc10f97b5 Fix issue #134 2020-12-06 17:15:04 +01:00
Thomas 0a12020fd8 Fix issue #129 2020-12-06 11:24:36 +01:00
Thomas e9c10b17e0 Fix issue #124 - typo 2020-12-06 10:59:01 +01:00
Thomas f4698f1312 Issue #133 - history not working in URL 2020-12-06 10:46:18 +01:00
Thomas 1690507a18 Issue #123 - a small fix 2020-12-05 18:48:41 +01:00
Thomas fbeb87e29e Issue #123 - improve player 2020-12-05 18:41:07 +01:00
Thomas de14e95e90 Issue #123 - Working cast 2020-12-05 17:28:25 +01:00
Thomas 35c5713b0a #123 - some tests 2020-12-05 14:01:08 +01:00
Thomas 413792087e #123 - some tests 2020-12-05 11:27:27 +01:00
Thomas 21c53d2b4d Add cast support #123 - try 2020-12-02 18:37:54 +01:00
Thomas 5757a8b1d8 Add cast support #123 2020-12-02 18:05:35 +01:00
Thomas 680bdf7bd2 Split code 2020-12-01 18:35:54 +01:00
Thomas 6911fbd124 Limits some actions 2020-12-01 16:09:14 +01:00
Thomas 9fdffc9709 svg 2020-11-29 12:00:04 +01:00
Thomas 0b722a5ecc Add flavors 2020-11-29 11:59:27 +01:00
Thomas 6ae42ffefe Allow to change thumbnail for Playlists 2020-11-28 17:56:16 +01:00
Thomas 3a8c82ce63 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!52
2020-11-28 16:48:55 +01:00
Thomas 04c2b277ce New Crowdin updates 2020-11-28 16:48:55 +01:00
Thomas 962462ff84 Fix some bugs 2020-11-28 16:41:21 +01:00
Thomas 964b0f2690 Fix some bugs when playing 2020-11-28 14:54:47 +01:00
Thomas 4b25b61680 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!51
2020-11-28 10:40:17 +01:00
Thomas 61c3735e57 New Crowdin updates 2020-11-28 10:40:16 +01:00
Thomas b0e29c0ba4 Some fixes 2020-11-28 10:33:13 +01:00
Thomas e7f55aace9 Fix issue #117 2020-11-28 10:26:20 +01:00
Thomas 2955206b07 Some improvements with nsfw dialog 2020-11-28 09:32:31 +01:00
Thomas b59d97279d Fix issue #115 - Filter with remote accounts does not work 2020-11-28 09:20:44 +01:00
Thomas 7d9e299940 Update release notes 2020-11-27 19:00:57 +01:00
Thomas e15252a0f8 Some fixes 2020-11-27 18:56:37 +01:00
Thomas e0907f1dc8 Swipe to change timelines 2020-11-27 18:36:31 +01:00
Thomas 1107391c43 Fix a crash 2020-11-27 15:00:25 +01:00
Thomas 2500035c33 Fix issue #58 - Remove more option menu for other channels 2020-11-27 14:29:29 +01:00
Thomas 24ad4dbc0f Fix issue #58 - Allow to search channels 2020-11-27 14:06:42 +01:00
Thomas 550394a5e4 Merge branch 'improve_comments' into develop
# Conflicts:
#	app/src/main/java/app/fedilab/fedilabtube/drawer/CommentListAdapter.java
2020-11-27 11:39:07 +01:00
Thomas 720c13fa2d add decoration 2020-11-27 11:38:36 +01:00
Thomas a02b8b79c1 some tests 2020-11-26 14:16:44 +01:00
Thomas c2f99e130d clean adapter for comment 2020-11-25 15:11:13 +01:00
Thomas 250aa03e9a some tries 2020-11-25 15:08:38 +01:00
Thomas dd7d253a1b Fix orientation issues 2020-11-25 11:26:14 +01:00
Thomas f2b46fffe0 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!50
2020-11-25 09:34:44 +01:00
Thomas 60630cc4ea New Crowdin updates 2020-11-25 09:34:44 +01:00
Thomas 85164c18e9 Fix issue #99 2020-11-25 09:31:39 +01:00
Thomas 3634e5e232 Some fixes 2020-11-24 17:32:18 +01:00
Thomas f7d44cb547 Some fixes 2020-11-24 13:50:06 +01:00
Thomas 85b89507db Fix issue #113 2020-11-23 18:37:26 +01:00
Thomas 7415b752cc Release 1.8.0 2020-11-22 17:03:18 +01:00
Thomas 0a52060223 Merge remote-tracking branch 'origin/develop' into develop 2020-11-22 16:46:11 +01:00
Thomas 1024b1e6f9 color fixes + update lib 2020-11-22 16:46:05 +01:00
Thomas 23fc061711 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!49
2020-11-22 16:44:56 +01:00
Thomas bfa3ede06b New Crowdin updates 2020-11-22 16:44:55 +01:00
Thomas c7f6cdc8c6 Fix indentation 2020-11-22 11:15:49 +01:00
Thomas 58f280d347 Fix issue #106 2020-11-22 11:15:31 +01:00
Thomas 0715824ae1 Fix issue #108 2020-11-22 11:04:46 +01:00
Thomas 5540c8cacc Fix issue #109 2020-11-22 10:59:30 +01:00
Thomas 14efbdd08f Some fixes 2020-11-21 18:54:54 +01:00
Thomas 7ceb04d548 Fix remote videos not playing 2020-11-21 18:51:30 +01:00
Thomas e9608f63db Prepare release 1.8.0 2020-11-21 17:26:28 +01:00
Thomas 64e1c7ca81 Update release notes 2020-11-21 17:24:28 +01:00
Thomas 7823b30900 Merge remote-tracking branch 'origin/develop' into develop 2020-11-21 17:17:42 +01:00
Thomas 1e45e4454c Change profile picture for channels 2020-11-21 17:17:34 +01:00
Thomas 1dd3a193c5 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!48
2020-11-21 14:17:16 +01:00
Thomas 30416837a9 New Crowdin updates 2020-11-21 14:17:16 +01:00
Thomas 363132d331 Fix 2020-11-21 11:06:26 +01:00
Thomas ebc0d744ed Fix 2020-11-21 09:59:33 +01:00
Thomas d685031ee8 Fix upload 2020-11-21 09:37:18 +01:00
Thomas 3ea012f62e Change lib 2020-11-20 18:48:29 +01:00
Thomas 9a06f5660b Some fixes 2020-11-20 15:03:06 +01:00
Thomas dff76aada1 Some fixes 2020-11-20 08:58:28 +01:00
Thomas 50a9f8a1b0 Some improvements 2020-11-19 18:08:28 +01:00
Thomas 8ff3b81112 Some fixes 2020-11-19 12:00:39 +01:00
Thomas 38f73a5d60 Some fixes 2020-11-18 19:15:19 +01:00
Thomas 15f6835a0c Some fixes 2020-11-18 19:04:54 +01:00
Thomas 84e3264726 Some fixes 2020-11-18 18:15:45 +01:00
Thomas dbd068d95f Some fixes 2020-11-18 17:24:18 +01:00
Thomas acba219e44 Fix issue #85 2020-11-18 15:44:47 +01:00
Thomas c8e7c23855 Fix issue #89 2020-11-18 15:07:22 +01:00
Thomas f0ff8a6feb Some fixes with video menu 2020-11-18 10:09:29 +01:00
Thomas 91a1380fef Fix issue #91 2020-11-18 10:00:25 +01:00
Thomas 3351ef7d91 Fix issue #76 2020-11-17 18:49:43 +01:00
Thomas 564cda58a5 Merge remote-tracking branch 'origin/develop' into develop 2020-11-17 18:31:17 +01:00
Thomas 3233fe673d Some fixes 2020-11-17 18:30:56 +01:00
Thomas 8cc8b284ce Some fixes 2020-11-17 18:10:45 +01:00
Thomas 3ecdedc17c Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!47
2020-11-17 17:55:52 +01:00
Thomas 8f361c605a New Crowdin updates 2020-11-17 17:55:51 +01:00
Thomas 9d599e8b57 some improvements 2020-11-17 17:47:10 +01:00
Thomas 9c676d8002 some improvements 2020-11-16 18:54:59 +01:00
Thomas d3ffc32d9b Merge branch 'develop' of https://framagit.org/tom79/fedilab-tube into develop
 Conflicts:
	app/src/main/java/app/fedilab/fedilabtube/PeertubeActivity.java
	app/src/main/java/app/fedilab/fedilabtube/drawer/CommentListAdapter.java
	app/src/main/java/app/fedilab/fedilabtube/helper/CommentDecorationHelper.java
	app/src/main/res/layout/activity_peertube.xml
2020-11-16 08:24:35 +01:00
Thomas 8c95554d8e Fix issue #70 2020-11-15 18:09:14 +01:00
Thomas 3ed5248c2a Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!46
2020-11-15 11:49:35 +01:00
Thomas 32990932ad New Crowdin updates 2020-11-15 11:49:34 +01:00
Thomas 6d0a47903c Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!45
2020-11-15 11:40:01 +01:00
Thomas 05eaa196b4 Prepare release 1.7.0 2020-11-15 11:34:18 +01:00
Thomas 2cd076bfb8 Comment issue #46 - Allow to delete history 2020-11-15 11:27:38 +01:00
Thomas 02cd267cae Fix issue #68 - Videos in unlisted playlists cannot be displayed 2020-11-15 09:54:55 +01:00
Thomas 21394cb585 New translations strings.xml (Polish) 2020-11-15 03:16:43 +01:00
Thomas 73cd48b94a Release 1.7.0 2020-11-14 19:13:59 +01:00
Thomas ea2cf58e5f Merge remote-tracking branch 'origin/develop' into develop 2020-11-14 17:52:32 +01:00
Thomas 2f3e29b037 Improve comments 2020-11-14 17:52:17 +01:00
Thomas 33d597c2c0 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!44
2020-11-14 17:49:49 +01:00
Thomas 66afb3f4ee New Crowdin updates 2020-11-14 17:49:48 +01:00
Thomas dad94d753d Remove lib 2020-11-14 17:19:37 +01:00
Thomas 1727bebf58 update release notes 2020-11-14 15:26:36 +01:00
Thomas 37576c69ce fixes 2020-11-14 15:22:48 +01:00
Thomas b8f83a7227 Merge branch 'bug_fixes_1-6-0' into develop
# Conflicts:
#	app/src/main/java/app/fedilab/fedilabtube/PeertubeActivity.java
2020-11-14 15:21:58 +01:00
Thomas 3a14abaf2e fixes 2020-11-14 15:18:16 +01:00
Thomas 0e03a55aef Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!43
2020-11-14 15:10:47 +01:00
Thomas 931fb30330 New Crowdin updates 2020-11-14 15:10:47 +01:00
Thomas b893dc9c4f Merge remote-tracking branch 'origin/develop' into develop 2020-11-14 15:10:27 +01:00
Thomas f6ddd99449 Last fixes 2020-11-14 15:09:52 +01:00
Thomas ddcbbfe670 Last fixes 2020-11-14 15:05:44 +01:00
Thomas 0f7438fa54 Some fixes 2020-11-14 12:19:37 +01:00
Thomas fbbab1db68 Some fixes 2020-11-14 09:50:48 +01:00
Thomas 15725dceb0 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!42
2020-11-13 18:46:58 +01:00
Thomas 1bcbcec8b8 New Crowdin updates 2020-11-13 18:46:57 +01:00
Thomas c3e475be6f Allow to export/import 2020-11-13 18:45:55 +01:00
Thomas 150a81adc6 Some fixes 2020-11-12 17:08:43 +01:00
Thomas a984607ee8 Update release notes 2020-11-11 18:28:50 +01:00
Thomas 2bf929986e Change button 2020-11-11 15:47:42 +01:00
Thomas 860edec2e6 Follow remote accounts 2020-11-11 15:36:15 +01:00
Thomas 90cfcbb7ae Fix issue #67 - Reaching profile edition from the account activity 2020-11-11 11:36:01 +01:00
Thomas c63048730f Fix issue #62 - Errors with pull to refresh 2020-11-11 11:13:29 +01:00
Thomas 55bbafdbb5 Fix issue #63 - Reach owner from channels 2020-11-11 10:42:40 +01:00
Thomas 0923a07e42 Fix issue #59 - Follow button from sepia search 2020-11-11 10:37:49 +01:00
Thomas 431c21e066 Last fixes 2020-11-11 10:34:28 +01:00
Thomas 17c84f6c37 Switch from accounts 2020-11-10 18:44:48 +01:00
Thomas 58f10d9372 Add the logic 2020-11-09 18:48:10 +01:00
Thomas a6dfd842e3 improve comments 2020-11-09 15:49:29 +01:00
Thomas dfdda7627f Release 1.6.0 2020-11-08 17:48:13 +01:00
Thomas 1711826c43 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!41
2020-11-08 17:42:24 +01:00
Thomas 4627de23b4 New Crowdin updates 2020-11-08 17:42:24 +01:00
Thomas 023ab2d4b2 Release 1.6.0 2020-11-08 17:42:01 +01:00
Thomas 2a375318ea fix issue link 2020-11-08 16:50:20 +01:00
Thomas fee593d059 Fix issue #44 - Sync NSFW + add them in settings to apply them. 2020-11-08 16:45:38 +01:00
Thomas fe3546e282 Fix issue #57 - Allow to share channel and account links 2020-11-08 10:43:27 +01:00
Thomas b61b6868a6 Fix issue #55 - Honor downloads disabled 2020-11-08 10:27:40 +01:00
Thomas 2f8ecd1f3e Prepare release 2020-11-07 17:23:53 +01:00
Thomas 8a9ead3f0d Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!40
2020-11-07 15:55:16 +01:00
Thomas 43e2762d4d New Crowdin updates 2020-11-07 15:55:16 +01:00
Thomas 8ab237a957 Fix issue #47 - Seek to last known position 2020-11-07 15:51:38 +01:00
Thomas ffa5d0883a Update release notes 2020-11-07 10:42:19 +01:00
Thomas 14f0a47f52 Fix issue #40 - Allow search to resolve peertube links 2020-11-07 10:38:30 +01:00
Thomas 4c1e466866 Fix issue #42 - Allow to display channels from playing video activity 2020-11-07 10:24:56 +01:00
Thomas 24c6f79b51 small fix 2020-11-07 10:17:45 +01:00
Thomas 8c958a2563 Fix issue #31 - Show more content when available (with a toggle button) 2020-11-07 10:09:58 +01:00
Thomas 02cc00780d Merge remote-tracking branch 'origin/develop' into develop 2020-11-07 09:43:14 +01:00
Thomas d13cce3997 Fix issue #39 - Allow to display videos in smaller lists 2020-11-07 09:42:56 +01:00
Thomas 985835429b Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!39
2020-11-06 19:10:28 +01:00
Thomas 00751cedab New Crowdin updates 2020-11-06 19:10:28 +01:00
Thomas c4e85a7161 Some improvements 2020-11-06 19:09:37 +01:00
Thomas 253b61fb11 Fix issue #29 - Accept URL for instances 2020-11-06 18:52:29 +01:00
Thomas 54ffbe2e15 Fix issue #30 2020-11-06 18:40:55 +01:00
Thomas 86d9ba930c Useless translations 2020-11-06 18:22:56 +01:00
Thomas fb96efc8cf Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!38
2020-11-06 18:01:22 +01:00
Thomas aaac1652e9 New Crowdin updates 2020-11-06 18:01:21 +01:00
Thomas c8fc98ee71 Add torrent 2020-11-06 17:32:12 +01:00
Thomas 4457259dfd Update README.md 2020-11-05 18:03:21 +01:00
Thomas 6dbb11f6e9 Fix notification settings 2020-11-05 17:56:26 +01:00
Thomas 08a4b4b49a Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!37
2020-11-05 17:53:29 +01:00
Thomas 4afd2ca341 New Crowdin updates 2020-11-05 17:53:29 +01:00
Thomas 0c048877e0 Some new features 2020-11-05 17:38:57 +01:00
Thomas 825a74de4a Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!36
2020-11-04 18:55:41 +01:00
Thomas 79ca0ceb88 New Crowdin updates 2020-11-04 18:55:41 +01:00
Thomas a5ccc9bf6f Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!35
2020-11-04 18:40:32 +01:00
Thomas 685467266a New Crowdin updates 2020-11-04 18:40:31 +01:00
Thomas 599e53b10c Merge remote-tracking branch 'origin/develop' into develop 2020-11-04 18:40:21 +01:00
Thomas 029b8b57ae push notifications 2020-11-04 18:39:45 +01:00
Thomas 631264eb57 push notifications 2020-11-04 17:43:38 +01:00
Thomas e7eef5b760 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!34
2020-11-03 07:32:14 +01:00
Thomas 59741e5979 New Crowdin updates 2020-11-03 07:32:14 +01:00
Thomas 0f38ad180a Allow to edit profile + profile picture 2020-11-01 18:34:53 +01:00
Thomas fdc6e6e325 Allow to edit profile 2020-10-31 18:24:52 +01:00
Thomas ed9e79496a Auto play video when ended 2020-10-31 10:37:17 +01:00
Thomas 4f909417f1 Fix issue #14 2020-10-30 16:21:56 +01:00
Thomas aecb4034ad Fix issue #20 2020-10-30 14:45:37 +01:00
Thomas f0335d96d2 Fix issue #18 2020-10-29 18:56:57 +01:00
Thomas 65f3886355 upgrade lib 2020-10-29 10:05:40 +01:00
Thomas 8e2f1fb8fe Merge remote-tracking branch 'origin/develop' into develop 2020-10-28 15:03:15 +01:00
Thomas 852cfee310 Fix double click for pausing and exit fullscreen 2020-10-28 15:03:07 +01:00
Thomas 6620a12957 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!33
2020-10-28 08:25:38 +01:00
Thomas 11e8135cbd New translations strings.xml (German) 2020-10-27 11:45:01 +01:00
Thomas 824c4e0cbb Comment #16 - Redirect to another app if the URL can't be open with TubeLab 2020-10-26 19:02:55 +01:00
Thomas 9af7934448 Fix issue #16 2020-10-26 14:38:51 +01:00
Thomas 4ffa027e8d Merge remote-tracking branch 'origin/develop' into develop 2020-10-25 17:40:27 +01:00
Thomas 7e8ab3359a Add CHANGELOG + CONTRIBUTING.md + issue_template.md + FUNDING.yml 2020-10-25 17:40:09 +01:00
Thomas 8e72655731 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!32
2020-10-25 09:40:17 +01:00
Thomas 5c098857bd New Crowdin updates 2020-10-25 09:40:17 +01:00
Thomas 7fece740af Merge remote-tracking branch 'origin/develop' into develop 2020-10-24 16:36:54 +02:00
Thomas 857ab65f93 Some improvements 2020-10-24 16:36:49 +02:00
Thomas 807655da5b Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!31
2020-10-24 15:57:05 +02:00
Thomas a77f37e564 New Crowdin updates 2020-10-24 15:57:04 +02:00
Thomas 1194209c82 Fix #13 - #14 - #15 Settings for auto fullscreen/ disable auto playblack / pause videos in fullscreen with key back 2020-10-24 14:42:51 +02:00
Thomas f31b6e9ac8 Fix mini video view not supported on some devices 2020-10-23 15:33:35 +02:00
Thomas 3353b7205b Fix issue #10 2020-10-22 08:57:51 +02:00
Thomas 0f995cc615 Fix issue #11 2020-10-21 18:43:56 +02:00
Thomas 7be0f72292 Release 1.5.1 2020-10-17 18:53:13 +02:00
Thomas ffbe8877a8 Merge branch 'develop' of https://framagit.org/tom79/fedilab-tube into develop 2020-10-17 18:50:26 +02:00
Thomas 74feb7e8f0 Release 1.5.1 2020-10-17 18:50:20 +02:00
Thomas cbaef4bcfe Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!30
2020-10-17 18:08:38 +02:00
Thomas 38a387a423 New Crowdin updates 2020-10-17 18:08:38 +02:00
Thomas 1092eefc76 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!29
2020-10-17 16:47:12 +02:00
Thomas 3615b43b97 New Crowdin updates 2020-10-17 16:47:11 +02:00
Thomas e17c7fb01d Fix some crashes 2020-10-17 10:55:25 +02:00
Thomas f3d69e19a0 Merge branch 'develop' of https://framagit.org/tom79/fedilab-tube into develop 2020-10-17 10:53:11 +02:00
Thomas ea102eb485 Fix some crashes 2020-10-17 10:52:56 +02:00
Thomas 2e4c01ed62 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!28
2020-10-17 05:55:39 +02:00
Thomas ed22892d10 New Crowdin updates 2020-10-17 05:55:39 +02:00
Thomas 017bd5a6a2 Release 1.5.0 2020-10-16 18:03:41 +02:00
Thomas 967f11ddb4 Release 1.5.0 2020-10-16 17:53:30 +02:00
Thomas 6b4abd019e typo 2020-10-16 17:43:18 +02:00
Thomas 8b66c4030f Some fixes 2020-10-16 17:41:07 +02:00
Thomas 34f058358e Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!27
2020-10-16 17:26:37 +02:00
Thomas 2bab907777 New Crowdin updates 2020-10-16 17:26:37 +02:00
Thomas 52e64b6d85 Fix issue #9 2020-10-16 17:25:52 +02:00
Thomas 9510678a9f Manage accounts 2020-10-16 17:03:07 +02:00
Thomas b4e7c3f8e2 New fixes 2020-10-16 11:37:40 +02:00
Thomas d800d2b10c Fix comment layout 2020-10-15 19:07:58 +02:00
Thomas 785b4949e6 Fix a register issue 2020-10-15 19:02:12 +02:00
Thomas b79e17cb60 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!26
2020-10-15 18:59:22 +02:00
Thomas 19fcbeb4b9 New Crowdin updates 2020-10-15 18:59:22 +02:00
Thomas ffb355d1a2 Add notifications for abuse reports 2020-10-15 18:59:08 +02:00
Thomas 43fd2945cc Some improvements 2020-10-15 18:37:50 +02:00
Thomas d93c74a449 Reply to comments 2020-10-15 18:11:37 +02:00
Thomas 7a197993c9 Support Emoji and replies 2020-10-15 15:16:41 +02:00
Thomas dc2a252dd5 Prepare the new layout. 2020-10-14 19:14:54 +02:00
Thomas 2c33f7a7f8 Prepare the new layout. 2020-10-14 19:11:53 +02:00
Thomas 24a8a0dc00 Some improvements 2020-10-14 16:39:27 +02:00
Thomas b78894b33c Merge remote-tracking branch 'origin/develop' into develop 2020-10-14 16:06:24 +02:00
Thomas 2d33d7f970 Fix comment issue when posting 2020-10-14 16:06:17 +02:00
Thomas 8823eb74ba Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!25
2020-10-14 15:24:32 +02:00
Thomas 7f77b86272 New Crowdin updates 2020-10-14 15:24:32 +02:00
Thomas 2f773b2f0f Custom instances per country 2020-10-14 10:57:28 +02:00
Thomas ca69a6e86d Code cleaning 2020-10-14 10:31:02 +02:00
Thomas 3e5cefbf24 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!24
2020-10-13 18:12:03 +02:00
Thomas 245ef64ebe New Crowdin updates 2020-10-13 18:12:03 +02:00
Thomas a0ff454dd9 Some improvements 2020-10-13 18:11:53 +02:00
Thomas fa6b1560f8 Prepare release 1.4.2 2020-10-13 17:57:35 +02:00
Thomas 518b5f617b Merge remote-tracking branch 'origin/develop' into develop 2020-10-13 17:50:57 +02:00
Thomas 7c4ce7701c some fixes 2020-10-13 17:50:52 +02:00
Thomas 0b6557f9c5 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!23
2020-10-13 16:36:10 +02:00
Thomas a8e00d137a New Crowdin updates 2020-10-13 16:36:10 +02:00
Thomas 75d3f74e48 Merge remote-tracking branch 'origin/develop' into develop 2020-10-13 16:35:56 +02:00
Thomas 3866317597 some fixes 2020-10-13 16:35:51 +02:00
Thomas 10e904fe4a Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!22
2020-10-13 14:32:42 +02:00
Thomas be655f6c2b New Crowdin updates 2020-10-13 14:32:42 +02:00
Thomas 676e540059 Dark/Light/Automatic theme 2020-10-13 14:30:08 +02:00
Thomas 87763a050c Merge remote-tracking branch 'origin/develop' into develop 2020-10-13 11:06:58 +02:00
Thomas ab45c1f80c Fix some issues + check if video is federated for Sepia search 2020-10-13 11:04:35 +02:00
Thomas ec5f2c7c45 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!21
2020-10-12 07:35:45 +02:00
Thomas c4448f22b9 New Crowdin updates 2020-10-12 07:35:44 +02:00
Thomas 62af5c54aa Release 1.4.1 2020-10-11 17:21:45 +02:00
Thomas 5872f5c99f Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!20
2020-10-11 17:18:41 +02:00
Thomas 2b1a63e08b New Crowdin updates 2020-10-11 17:18:41 +02:00
Thomas 7b96cf32b3 App rater for Google Full version 2020-10-10 15:40:16 +02:00
Thomas 6108bd143c App rater for Google Full version 2020-10-10 15:33:25 +02:00
Thomas 0127b9bffa Censor videos having youtube + download in their title (Google Play release only). 2020-10-10 15:21:46 +02:00
Thomas 8dddfc5497 Last fixes 2020-10-10 15:05:39 +02:00
Thomas bf119a5808 Fix strings 2020-10-10 11:52:57 +02:00
Thomas 89ade69c5f Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!19
2020-10-10 11:49:50 +02:00
Thomas 93eaec8544 Fix some elements 2020-10-10 11:49:18 +02:00
Thomas ce984de339 New translations strings.xml (French) 2020-10-10 10:32:08 +02:00
Thomas b089ae93e1 Refresh subscription 2020-10-10 10:28:45 +02:00
Thomas fc95708a84 Merge remote-tracking branch 'origin/develop' into develop 2020-10-10 09:43:40 +02:00
Thomas 7262690999 Fix translations 2020-10-10 09:43:35 +02:00
Thomas f818c74943 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!18
2020-10-10 09:38:05 +02:00
Thomas d7c5a04965 New Crowdin updates 2020-10-10 09:38:05 +02:00
Thomas 257a00fa1e Some fixes 2020-10-10 09:37:44 +02:00
Thomas 23875a2ceb Fix channel filter for subscriptions 2020-10-10 09:25:00 +02:00
Thomas 3f1883fbbc Fix an issue with overlapping views 2020-10-09 19:14:20 +02:00
Thomas c5269a3129 comment #5 - Some improvements 2020-10-09 18:37:54 +02:00
Thomas 056092ac71 comment #5 - Add searches 2020-10-09 18:22:05 +02:00
Thomas fd7632f001 comment #5 - searches 2020-10-09 14:54:01 +02:00
Thomas fb83a1927d comment #5 - prepare layouts 2020-10-09 10:19:46 +02:00
Thomas 641a616c96 Change readme + fix titles 2020-10-08 18:46:18 +02:00
Thomas fc051d8d1d Merge branch 'develop' of https://framagit.org/tom79/fedilab-tube into develop 2020-10-08 18:44:30 +02:00
Thomas b8bec4f357 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!17
2020-10-08 18:44:22 +02:00
Thomas fe78c8bf7e New Crowdin updates 2020-10-08 18:44:21 +02:00
Thomas 42caaa9dc9 Fix titles 2020-10-08 18:35:35 +02:00
Thomas 74d6cb8041 Prepare release 1.3.0 2020-10-08 18:30:47 +02:00
Thomas 7678da2bb6 Change description + fix pagination 2020-10-08 18:13:04 +02:00
Thomas e771153f35 Some changes 2020-10-08 17:16:42 +02:00
Thomas e96b9f7f02 Some fixes 2020-10-08 16:21:14 +02:00
Thomas 0604ac9ba8 Merge remote-tracking branch 'origin/develop' into develop 2020-10-07 17:46:25 +02:00
Thomas bd0c59a69e Improve menu for videos 2020-10-07 17:46:15 +02:00
Thomas 0a84b75518 typo error 2020-10-07 09:25:58 +02:00
Thomas c4b49b58cf typo error 2020-10-07 09:25:41 +02:00
Thomas afbb27896e Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!16
2020-10-07 08:53:17 +02:00
Thomas e0ff6c0ac3 New Crowdin updates 2020-10-07 08:53:17 +02:00
Thomas 4d7c7e88bb typo error 2020-10-06 19:02:25 +02:00
Thomas 7eef023277 some fixes 2020-10-06 18:49:15 +02:00
Thomas 6a762a8fd6 some fixes 2020-10-06 17:11:25 +02:00
Thomas 752e3d50c1 some fixes 2020-10-06 16:05:34 +02:00
Thomas 8377f9bb8a Merge branch 'develop' into new_feature
# Conflicts:
#	app/src/main/java/app/fedilab/fedilabtube/drawer/PeertubeAdapter.java
#	app/src/main/java/app/fedilab/fedilabtube/helper/Helper.java
2020-10-06 15:32:04 +02:00
Thomas 5ff06a29d2 Merge branch 'develop' of https://framagit.org/tom79/fedilab-tube into develop
 Conflicts:
	app/build.gradle
2020-10-06 15:30:53 +02:00
Thomas 50aeb075b1 test 2020-10-06 15:30:15 +02:00
Thomas 79ff617d67 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!15
2020-10-06 14:09:02 +02:00
Thomas 5de8524f2a New Crowdin updates 2020-10-06 14:09:02 +02:00
Thomas 6164ff9163 change versionCode 2020-10-05 14:43:18 +02:00
Thomas 6e8b304b63 Fix crashes 2020-10-05 14:34:22 +02:00
Thomas 3be0cd727f Fix crashes 2020-10-05 14:34:01 +02:00
Thomas 451dd53230 Merge remote-tracking branch 'origin/develop' into develop 2020-10-04 17:51:15 +02:00
Thomas 34c1222fbc Code clean 2020-10-04 17:51:09 +02:00
Thomas ccf2fc877b Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!14
2020-10-04 17:26:04 +02:00
Thomas 10a496c299 New Crowdin updates 2020-10-04 17:26:04 +02:00
Thomas ba1bfd1f9c Change loader 2020-10-04 17:25:08 +02:00
Thomas b9622da6c6 Merge remote-tracking branch 'origin/develop' into develop 2020-10-04 14:01:11 +02:00
Thomas b3e9100c2f Fix inverted strings 2020-10-04 13:53:07 +02:00
Thomas fb0e87397d Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!13
2020-10-04 13:51:25 +02:00
Thomas bed1bb634b New Crowdin updates 2020-10-04 13:51:25 +02:00
Thomas 4db288743e typo 2020-10-03 19:10:00 +02:00
Thomas ba569b2d40 change version code 2020-10-03 19:04:02 +02:00
Thomas c774dcee96 Last fixes 2020-10-03 18:37:34 +02:00
Thomas 48fe22c8db Merge remote-tracking branch 'origin/develop' into develop 2020-10-03 17:02:59 +02:00
Thomas 3f282c8116 Some fixes 2020-10-03 17:02:48 +02:00
Thomas 4f4cdd68b5 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!12
2020-10-03 17:01:54 +02:00
Thomas 9c350c922b New Crowdin updates 2020-10-03 17:01:53 +02:00
Thomas 8548777c50 some checks 2020-10-03 16:22:19 +02:00
Thomas 30d344987c Fix an issue 2020-10-03 13:41:33 +02:00
Thomas 80c8e1a356 Release notes 2020-10-03 11:54:18 +02:00
Thomas 8ce7eb386f Release 1.2.0 2020-10-03 11:44:00 +02:00
Thomas c50a587250 Some improvements 2020-10-03 11:24:26 +02:00
Thomas a8b17ce0b2 Add cache for videos 2020-10-03 10:59:31 +02:00
Thomas 731863ef6c Merge remote-tracking branch 'origin/develop' into develop 2020-10-03 09:08:41 +02:00
Thomas 04b8294022 Fix triple-t 2020-10-03 09:08:36 +02:00
Thomas 4937ff43e5 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!11
2020-10-03 08:18:02 +02:00
Thomas 1670867a1d New Crowdin updates 2020-10-03 08:18:02 +02:00
Thomas 5e947cd221 Beta release 2020-10-02 19:33:57 +02:00
Thomas 1f8c5cbc05 Fix strings 2020-10-02 19:31:00 +02:00
Thomas c2ab7a3608 Some improvements 2020-10-02 19:29:00 +02:00
Thomas d62ff6d18f some fixes 2020-10-02 18:22:19 +02:00
Thomas 92a0af8b36 Fix full screen 2020-10-02 15:23:36 +02:00
Thomas 34ed36f9ae Fix issue 2020-10-02 15:14:08 +02:00
Thomas 7777317eb8 Merge remote-tracking branch 'origin/develop' into develop 2020-10-02 07:09:01 +02:00
Thomas 4d53612adc Some fixes 2020-10-02 07:03:36 +02:00
Thomas e08d9805f1 Some improvements 2020-10-01 17:42:03 +02:00
Thomas cb5b7274fe Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!10
2020-10-01 16:47:48 +02:00
Thomas db84cac8f0 New Crowdin updates 2020-10-01 16:47:47 +02:00
Thomas b6769ca25f Fix upload 2020-09-29 17:48:12 +02:00
Thomas 70903578d1 upload+actions with retrofit 2020-09-29 17:42:15 +02:00
Thomas 07d8a39681 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!9
2020-09-28 07:18:09 +02:00
Thomas 7410467cd6 New Crowdin updates 2020-09-28 07:18:09 +02:00
Thomas f21732f753 Refresh token 2020-09-27 18:33:51 +02:00
Thomas 9dca5fcd3b Fix authentication 2020-09-27 16:33:43 +02:00
Thomas 1bc99b3c46 Fix Playing 2020-09-27 14:12:06 +02:00
Thomas a8a5028852 Fix OverviewVideo 2020-09-27 11:37:48 +02:00
Thomas f5fa9944ad Change overview management 2020-09-27 11:11:39 +02:00
Thomas 3697917d2b Some fixes 2020-09-26 19:41:21 +02:00
Thomas 9f25405983 Some fixes 2020-09-26 19:36:10 +02:00
Thomas 9c476037ef Some fixes 2020-09-26 19:31:38 +02:00
Thomas 2044a85b58 Fix issue 2020-09-26 16:52:41 +02:00
Thomas d878ac780c some changes 2020-09-26 16:46:51 +02:00
Thomas 55179c6955 some changes 2020-09-26 10:22:11 +02:00
Thomas 618384cccb Change classes 2020-09-25 18:58:04 +02:00
Thomas 0b84823f64 Release notes 2020-09-24 07:36:25 +02:00
Thomas 9361f6ca64 Fix date 2020-09-24 07:31:46 +02:00
Thomas b81257c77c Release 1.1.1 2020-09-24 07:28:36 +02:00
Thomas 75e919adbc Merge remote-tracking branch 'origin/develop' into develop 2020-09-24 07:27:55 +02:00
Thomas d946451b27 Fix issue #3 2020-09-24 07:27:41 +02:00
Thomas 2d960d4c55 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!8
2020-09-23 08:35:18 +02:00
Thomas 6f24030b86 New Crowdin updates 2020-09-23 08:35:17 +02:00
Thomas ce7b0d4d7d Fix typo 2020-09-21 07:33:46 +02:00
Thomas ed34917550 Fix typo 2020-09-21 07:33:26 +02:00
Thomas 18bd328814 Fix typo 2020-09-21 07:30:08 +02:00
Thomas cf35a65edd Fix typo 2020-09-21 07:28:26 +02:00
Thomas fe04f32aa1 Fixes 2020-09-20 18:46:11 +02:00
Thomas 36f5f73a47 Fixes 2020-09-20 18:35:43 +02:00
Thomas cd5e23364d build apk 2020-09-20 18:23:20 +02:00
Thomas 8bd4a3f5d1 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!7
2020-09-20 16:14:41 +02:00
Thomas 4114e4c349 New Crowdin updates 2020-09-20 16:14:41 +02:00
Thomas 3993e4a67e Release 1.1.0 2020-09-20 16:13:50 +02:00
Thomas c78af3ea1a Release 1.1.0 2020-09-20 16:12:20 +02:00
Thomas 132687366c Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!6
2020-09-20 15:32:26 +02:00
Thomas 667469c773 New Crowdin updates 2020-09-20 15:32:26 +02:00
Thomas e78e7a6f97 Small fix 2020-09-20 15:31:56 +02:00
Thomas a1790bf32d Filter languages 2020-09-20 15:14:48 +02:00
Thomas 7a8e2f32b4 Merge remote-tracking branch 'origin/develop' into develop 2020-09-20 12:16:30 +02:00
Thomas 1932913793 Add logic 2020-09-20 12:16:10 +02:00
Thomas 7c40060438 Add logic 2020-09-20 12:06:38 +02:00
Thomas 0c6c5c813f Prepares views 2020-09-20 11:07:28 +02:00
Thomas 786b80e25e Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!5
2020-09-20 09:36:52 +02:00
Thomas 4cc0729d77 New translations strings.xml (Italian) 2020-09-19 21:15:19 +02:00
Thomas 9f444d6d88 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!4
2020-09-19 18:24:26 +02:00
Thomas 700fe6c9e8 New Crowdin updates 2020-09-19 18:24:26 +02:00
Thomas 3c2b8cc699 release 1.1.0-a 2020-09-19 18:22:44 +02:00
Thomas eef6b3d76c release 1.1.0-a 2020-09-19 18:19:59 +02:00
Thomas 0a7fab6883 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!3
2020-09-19 17:23:07 +02:00
Thomas 1f7fe1fc6f New Crowdin updates 2020-09-19 17:23:06 +02:00
Thomas 5bb395f2d3 disable MissingTranslation 2020-09-19 17:22:34 +02:00
Thomas 4d6cb47e6c some fixes 2020-09-19 16:50:20 +02:00
Thomas f7f85a9dbb some fixes 2020-09-19 15:06:24 +02:00
Thomas 118c2175f5 Play Minimized video when app in background 2020-09-19 14:56:10 +02:00
Thomas 645c9fa240 Add crowdin link 2020-09-19 13:07:39 +02:00
Thomas 13baaccd81 allows username when logging in 2020-09-19 13:01:27 +02:00
Thomas aaa8281da8 Merge branch 'l10n_develop' into 'develop'
New Crowdin updates

See merge request tom79/fedilab-tube!2
2020-09-19 11:10:48 +02:00
Thomas 8bcc7e8f58 New Crowdin updates 2020-09-19 11:10:48 +02:00
Thomas 8085ed6a95 crowdin.yml 2020-09-19 10:57:52 +02:00
Thomas 12d24f4a56 crowdin.yml 2020-09-19 10:57:44 +02:00
Thomas fcf2fbdd86 crowdin.yml 2020-09-19 10:48:49 +02:00
Thomas 81a711ee4c Prepare release 1.1.0 2020-09-18 18:16:47 +02:00
Thomas b68cb689ca Multi account 2020-09-18 18:10:04 +02:00
Thomas b2f1bf2817 Some offline fixes 2020-09-18 16:08:52 +02:00
Thomas 7aab6fbba9 Update info via a service 2020-09-18 14:37:34 +02:00
Thomas 015a2f3289 Some fixes 2020-09-18 12:03:35 +02:00
Thomas 647c827ee4 Pickup instance when registering 2020-09-17 19:01:31 +02:00
Thomas e503a5ec95 Small fixes 2020-09-17 18:37:44 +02:00
Thomas 11209a5334 Some fixes 2020-09-17 17:00:12 +02:00
Thomas b23686ab64 picker layout 2020-09-17 07:28:52 +02:00
Thomas 7f4c6faa1d add checkbox for selecting categories 2020-09-16 19:02:04 +02:00
Thomas 33c7f12180 Open dialog 2020-09-16 17:27:07 +02:00
Thomas 106bacb4b1 Add logic 2020-09-16 16:21:03 +02:00
Thomas d6c662434d About page 2020-09-16 15:48:27 +02:00
Thomas 3705657aec About page 2020-09-16 15:47:49 +02:00
Thomas ea810fd61b About page 2020-09-16 14:07:44 +02:00
Thomas 2d32aa9a9b Change icons 2020-09-16 10:12:34 +02:00
Thomas e672b207b6 update README.md 2020-09-16 09:19:40 +02:00
Thomas 68dfb1b980 changes 2020-09-15 18:58:12 +02:00
Thomas 6feedf5c24 changes 2020-09-15 18:47:26 +02:00
Thomas c196d3aebe changes 2020-09-15 18:39:37 +02:00
Thomas a87ec4ffa5 Some fixes 2020-09-15 16:07:05 +02:00
Thomas 3e694b8ac2 Triple-T 2020-09-14 16:45:07 +02:00
Thomas 26af939014 improve flavor 2020-09-14 15:53:31 +02:00
Thomas f0eaceb8a4 apply flavors 2020-09-13 19:20:04 +02:00
Thomas 7827c97bf9 Merge branch 'master' into full_version 2020-09-13 15:25:59 +02:00
Thomas 88514c0669 change build.gradle 2020-09-06 20:41:36 +02:00
498 changed files with 43765 additions and 13753 deletions

10
.github/FUNDING.yml vendored Normal file
View File

@ -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']

17
.github/stale.yml vendored Normal file
View File

@ -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

2
.gitignore vendored
View File

@ -8,3 +8,5 @@
.externalNativeBuild
.cxx
/app/release/
/app/fdroid_full/release/
/frostwire-jlibtorrent/

View File

@ -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

28
CHANGELOG Normal file
View File

@ -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

17
CONTRIBUTING.md Normal file
View File

@ -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.

View File

@ -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)
&nbsp;&nbsp;[<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. Lauthentification se fait par adresse mail, linstance est automatiquement détectée. Il est également possible sur certaines instances de créer son compte depuis lapplication.
[<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)
&nbsp;&nbsp;[<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. Lauthentification se fait par adresse mail, linstance est automatiquement détectée. Il est également possible sur certaines instances de créer son compte depuis lapplication.
### 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)

View File

@ -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'
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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>

View File

@ -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" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 720 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 937 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -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 {
}

View File

@ -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
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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>

View File

@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 720 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 937 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -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>

View File

@ -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>

View File

@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

@ -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>

View File

@ -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>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#000000</color>
</resources>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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() {
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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"}

File diff suppressed because it is too large Load Diff

View File

@ -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"}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@ -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;
}
}
}

View File

@ -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);
}
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}
}

View File

@ -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();
}
}

Some files were not shown because too many files have changed in this diff Show More