Compare commits

...

105 Commits

Author SHA1 Message Date
Ivan Agosto ff995e383d Add view manager helper 2024-05-14 18:39:45 -06:00
Ivan Agosto d3466f9cce Add reponsive views 2024-05-14 18:20:46 -06:00
Ivan Agosto f0fbd02cf4 Fix scroll on player activity 2024-05-11 14:26:13 -06:00
Ivan Agosto 3364f60d32 Update exo player with better UX 2024-05-11 13:51:16 -06:00
Ivan Agosto 0f8c3a7126 Release v0.7.0 2024-04-15 22:18:02 -06:00
Ivan Agosto d6aeadc489 Fix lint errors 2024-04-15 22:07:14 -06:00
Ivan Agosto 826bb79431 Merge branch 'feature/threads' into 'master'
Feature/threads

See merge request agosto182/p2play!16
2024-04-16 03:55:53 +00:00
Ivan Agosto 2484406cc7 Feature/threads 2024-04-16 03:55:53 +00:00
Ivan Agosto 0705d6dd80 Merge branch 'feature/playbackService' into 'master'
Feature/playback service

See merge request agosto182/p2play!15
2024-04-11 03:15:06 +00:00
Ivan Agosto dd54d214ff Feature/playback service 2024-04-11 03:15:06 +00:00
Ivan Agosto 48738f100a fix all lint errors 2024-04-06 18:03:23 -06:00
Ivan Agosto b6e1a979ca Fix lint errors automated 2024-04-06 14:38:04 -06:00
Ivan Agosto 96d8ae19c6 Fix buffer, forward and rewind video 2024-04-05 21:44:56 -06:00
Ivan Agosto 8856984dc3 Fix share and report icons color 2024-04-05 21:30:37 -06:00
Ivan Agosto 2ffb7daede Fix dialogs design 2024-04-05 21:30:22 -06:00
Ivan Agosto f0b5ba10e8 Fix for wrong pagination 2024-04-05 18:47:08 -06:00
Ivan Agosto 4d2644674e Add 2fa login support 2024-04-05 18:46:57 -06:00
Ivan Agosto 6a8d3baccb Update setting view 2024-03-31 16:59:57 -06:00
Ivan Agosto ac191c04d3 Updates of descriptions and screenshots 2024-03-28 19:06:38 -06:00
Ivan Agosto 15aaae2fa1 Fix video preview sizes 2024-03-28 18:41:49 -06:00
Ivan Agosto 42be7c4f77 Merge branch 'feature/add-exo-player' into 'master'
Feature/add exo player

See merge request agosto182/p2play!14
2024-03-28 23:58:25 +00:00
Ivan Agosto e022fe5e96 Add fullscreen to exoplayer 2024-03-28 17:29:32 -06:00
Ivan Agosto 1f90e21f68 Fix: Fullscreen bug 2024-03-27 21:31:41 -06:00
Ivan Agosto c104bf32da Merge branch 'master' into feature/add-exo-player 2024-03-27 20:57:17 -06:00
Ivan Agosto a3cd0b92ed Merge branch 'feature/update-video-view' into 'master'
Feature/update video view

See merge request agosto182/p2play!13
2024-03-28 02:54:14 +00:00
Ivan Agosto 2de1bde4cd Feature/update video view 2024-03-28 02:54:14 +00:00
Ivan Agosto 6f0b97dbc4 Exo player first integration 2024-03-27 20:44:52 -06:00
Ivan Agosto 2fcd3b21f8 Add isLive indicator 2024-03-25 19:57:49 -06:00
Ivan Agosto eeb20f1f9d Update function name to the correct one 2024-03-25 19:57:22 -06:00
Ivan Agosto 0d9bd5410a Update to sdk 32 2024-03-25 18:53:01 -06:00
Ivan Agosto 40b193a816 Update duration data to a floating text 2024-03-22 18:12:14 -06:00
Ivan Agosto c500ba9aa4 Merge branch 'androidx' into 'master'
Androidx

See merge request agosto182/p2play!12
2024-03-22 23:23:16 +00:00
Ivan Agosto 35aa0fcea1 Androidx 2024-03-22 23:23:16 +00:00
Ivan Agosto ba0a298ea9 Add new theme to Channel view 2024-03-22 17:20:42 -06:00
Ivan Agosto 815bafaee1 Update edittext to materialTextview 2024-03-22 16:55:52 -06:00
Ivan Agosto ef5c97dce1 Finish update to androidx 2024-03-22 12:28:39 -06:00
Ivan Agosto b6ef9b8aca Normalize theme 2024-03-21 17:47:54 -06:00
Ivan Agosto bf35a75877 Add material theme 2024-03-21 14:23:36 -06:00
Ivan Agosto 65e061fd25 First changes to androidx 2024-03-20 21:04:16 -06:00
Ivan Agosto ffbc491f4c update metadata 2024-03-19 22:04:26 -06:00
Ivan Agosto da1d3e301e Fix error getting local videos 2024-03-19 21:42:26 -06:00
Ivan Agosto 6784b5ebbe Update fastlane descriptions 2024-03-18 19:24:57 -06:00
Ivan Agosto e70108a7ae Update README 2024-03-18 18:53:06 -06:00
Ivan Agosto 2b7d92ac37 Merge branch 'updateAndroidSDK' into 'master'
Update android sdk

See merge request agosto182/p2play!11
2024-03-19 00:45:04 +00:00
Ivan Agosto 4d337074fb Update android sdk 2024-03-19 00:45:04 +00:00
Ivan Agosto cd27342c74 Merge branch 'master' into 'master'
updated strings

See merge request agosto182/p2play!10
2024-03-18 17:23:49 +00:00
john j ab1bb48dcc updated strings 2024-03-18 17:23:49 +00:00
Ivan Agosto 0a648ef4bb Merge branch 'master' into 'master'
Add Italian translation

See merge request agosto182/p2play!9
2020-06-26 21:00:36 +00:00
Igor Calì 3e41ddd367 Add Italian translation 2020-06-26 21:00:36 +00:00
Ivan Agosto 9c90983ff4 Merge branch 'patch-1' into 'master'
Update README.md

See merge request agosto182/p2play!8
2020-02-17 00:59:25 +00:00
Poussinou dad366eebf Update README.md 2020-01-11 13:42:03 +00:00
Ivan Agosto 14640a825f Merge branch 'development' into 'master'
0.5.1 version

See merge request agosto182/p2play!7
2019-12-13 15:56:33 +00:00
Ivan Agosto 8fbfd57f78 Update new version 2019-12-13 09:55:42 -06:00
Ivan Agosto a66acfbcea Most liked videos 2019-12-13 09:53:10 -06:00
Ivan Agosto d410be7d4e Fastlane spanish lang 2019-11-01 09:13:26 -06:00
Ivan Agosto a26efeba63 Fastlane changes 2019-11-01 08:17:48 -06:00
Ivan Agosto 49b7841a97 Fastlane added 2019-10-30 12:01:48 -06:00
Ivan Agosto 7d6f364223 Merge branch 'development' into 'master'
P2play version 0.5

See merge request agosto182/p2play!6
2019-10-27 17:15:33 +00:00
Ivan Agosto 390b1a7add Warning fixed and upgraded app version 2019-10-24 14:34:14 -05:00
Ivan Agosto 904319674d Readme upgraded 2019-10-24 13:52:17 -05:00
Ivan Agosto c26ab0b8a2 Saving video views in history 2019-10-24 13:46:23 -05:00
Ivan Agosto 9167977c7c Timeout up to 60 sec 2019-10-19 14:02:13 -05:00
Ivan Agosto 8394484eb0 New logo p2play 2019-10-18 12:35:15 -05:00
Ivan Agosto 4946a55215 Reordered menu, added history videos 2019-10-18 11:14:44 -05:00
Ivan Agosto 9638468191 Kotlin core updated 2019-10-17 20:41:32 -05:00
ivan agosto b763ed2088 gradle updated 2019-03-18 20:59:38 -06:00
ivan agosto 5c966fe81c But of profile image on logout fixed 2019-03-18 20:58:42 -06:00
Ivan Agosto 23dfb98a67 Merge branch 'development' into 'master'
Development

See merge request agosto182/p2play!5
2019-02-27 15:22:19 +00:00
ivan agosto 22a2772a3c Prerelease 0.4 2019-02-27 09:21:11 -06:00
ivan agosto abcf2f0e6e Report and share videos works 2019-02-24 20:53:40 -06:00
ivan agosto 398265c6ed Channel view maked and working 2019-02-24 10:34:12 -06:00
ivan agosto 743c3147c1 Models parse funcion added and channel model added 2019-02-23 15:14:56 -06:00
ivan agosto d360a1849e Show more fixed 2019-02-17 18:42:08 -06:00
ivan agosto 90f2ab6e7d Trending videos added 2019-02-17 18:34:38 -06:00
ivan agosto d680eb77b8 Linting ajax files 2019-02-17 17:29:52 -06:00
ivan agosto 90aac608be Option for show full description 2019-02-17 17:13:12 -06:00
ivan agosto 2abdcb8375 Full screen bugs fixed 2019-02-17 14:29:33 -06:00
ivan agosto a6f3a4b6b4 Commentaries with html parsed 2019-02-16 00:33:54 -06:00
Ivan Agosto d15ad1006e Merge branch 'development' into 'master'
Development: 0.3 version

See merge request agosto182/p2play!4
2019-02-14 18:45:52 +00:00
ivan agosto fb98d96f66 Version 0.3 prereleased 2019-02-12 22:40:35 -06:00
ivan agosto c1b746da80 Fixed errors on infinite scroll 2019-02-12 11:45:24 -06:00
ivan agosto 130ece5982 Title videos centered 2019-02-10 16:28:14 -06:00
ivan agosto 999bd4ad9d Colors of nav changed 2019-02-10 13:42:29 -06:00
ivan agosto 4347831907 Count videos added 2019-02-10 12:10:52 -06:00
ivan agosto d783b4887d Fixed bad practices of singleton 2019-02-10 11:41:56 -06:00
ivan agosto 329813d1b3 Videos per page settings added 2019-02-10 10:29:36 -06:00
ivan agosto 700559e28f Autoclose searchView 2019-02-10 00:03:21 -06:00
ivan agosto c07c15c766 Search videos and infinite scroll 2019-02-09 14:56:56 -06:00
ivan agosto 305acc87e7 Nsfw content blocked by default 2019-02-07 08:27:25 -06:00
Ivan Agosto a626bc85bb Merge branch 'development' into 'master'
P2play 0.2

See merge request agosto182/p2play!3
2019-02-01 14:47:17 +00:00
ivan agosto 66428e0c34 Fix subscriptions problems 2019-01-30 13:03:00 -06:00
ivan agosto 76a1d2f4b3 Adding lint skips for releases 2019-01-30 12:40:36 -06:00
ivan agosto e2d1ffdb15 Update for 0.2 2019-01-29 17:17:32 -06:00
ivan agosto 97c85c7bba Version name added +fix screen on reproductor 2019-01-29 16:23:33 -06:00
ivan agosto 7930ffa582 Splash screen fix + description on videos 2019-01-29 14:56:50 -06:00
ivan agosto abec98d172 Splash screen + commentaries changes 2019-01-28 14:54:08 -06:00
ivan agosto e74e39fe28 Color of buttons changed 2019-01-25 12:35:15 -06:00
ivan agosto 176e580f1f Make commentaries on videos 2019-01-25 12:30:48 -06:00
ivan agosto ab69d59f9a Showing commentaries on videos 2019-01-25 11:38:59 -06:00
ivan agosto 5cf806577a Ajax petitions for commentaries 2019-01-25 11:38:37 -06:00
ivan agosto 9bf8ea0483 Adapter and model of commentaries maked 2019-01-24 15:56:20 -06:00
ivan agosto 6413bb078d iml files ignored 2019-01-24 14:46:34 -06:00
ivan agosto d918824d74 gitignore updated 2019-01-24 14:45:08 -06:00
ivan agosto 7d60dc8c0f Updated kotlin + commentaries 2019-01-23 15:40:41 -06:00
ivan agosto 4655d9ed86 Merge branch 'master' into development 2019-01-23 14:10:02 -06:00
159 changed files with 5007 additions and 1512 deletions

2
.editorconfig Normal file
View File

@ -0,0 +1,2 @@
[*.{kt,kts}]
ktlint_code_style = intellij_idea

6
.gitignore vendored
View File

@ -32,3 +32,9 @@ proguard/
captures/
\.idea/
# iml Files
*.iml
app/app.iml
app/release/

View File

@ -1,52 +1,76 @@
# P2Play
P2Play is an Android Application for Peertube.
P2Play is an unoficial Peertube android application.
[What is Peertube?](https://github.com/Chocobozzz/PeerTube/)
## Documentation
Comming soon!
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/packages/org.libre.agosto.p2play/)
## Realeases
## Screenshots
<img src="metadata/en-US/images/phoneScreenshots/1.jpg" alt="Screenshot" width="14%"/>
<img src="metadata/en-US/images/phoneScreenshots/2.jpg" alt="Screenshot" width="14%"/>
<img src="metadata/en-US/images/phoneScreenshots/3.jpg" alt="Screenshot" width="14%"/>
<img src="metadata/en-US/images/phoneScreenshots/4.jpg" alt="Screenshot" width="14%"/>
<img src="metadata/en-US/images/phoneScreenshots/5.jpg" alt="Screenshot" width="14%">/
<img src="metadata/en-US/images/phoneScreenshots/6.jpg" alt="Screenshot" width="14%"/>
## Realeases (apk's)
[All realeases are here](https://gitlab.com/agosto182/p2play/tags)
## Features
- Show recent, popular and local list of videos.
- Reproduce videos (very simple)
- Reproduce videos
- Login and register in your instance
- Pull to refresh
- Show uploaded videos
- Subscribe to accounts
- Show your subscripcion videos
- Show your history
- Rate videos
## What to do? (in next version)
- Search videos
- Show and make commentaries
- Share videos
- View Peertube profiles
- Splash screen
- Search videos
- Infinite scroll
- Share videos
- Report videos
- Peertube profiles
- Day/Night theme
## What to do? (on incomming updates)
- Playlists
- Manage subscriptions
- Better commentaries
- Account channels view
- Notifications
## Demostrations
Demostration P2Play Beta 0.1: [https://peertube.video/videos/watch/2eb7b953-0b1b-4019-9300-817539f5f4e8](https://peertube.video/videos/watch/2eb7b953-0b1b-4019-9300-817539f5f4e8)
[Spanish] Demostracion P2Play Beta 0.1: [https://peertube.video/videos/watch/d6a7da26-d3dd-43aa-ad5c-7d032603c848](https://peertube.video/videos/watch/d6a7da26-d3dd-43aa-ad5c-7d032603c848)
P2play beta 0.6.0: https://fediverse.tv/w/suFPkm9zJstSrQU7WmVARv
**Dead links**
~~Demostration P2play Beta 0.2: https://peertube.video/videos/watch/730fa68e-32c4-4cdb-a7bb-1a819c9d3a46~~
~~Demostration P2Play Beta 0.1: https://peertube.video/videos/watch/2eb7b953-0b1b-4019-9300-817539f5f4e8~~
~~[Spanish] Demostracion P2Play Beta 0.1: https://peertube.video/videos/watch/d6a7da26-d3dd-43aa-ad5c-7d032603c848~~
## Contact
You can follow our accounts for get news and contact with the developers.
You can follow our accounts to get news and contact with the developer(s).
- GNU Social: [https://gnusocial.ml/p2play](https://gnusocial.ml/p2play)
- Peertube Channel: [https://peertube.video/video-channels/90df4e5f-c834-4720-a5d7-c9faa0af0af5/videos](https://peertube.video/video-channels/90df4e5f-c834-4720-a5d7-c9faa0af0af5/videos)
- WriteFreely (ActivityPub): https://personaljournal.ca/p2play/
## About
P2Play is made in Android Studio with Kotlin code.
P2Play is made in Android Studio with Kotlin languaje.
<img src="https://weblizar.com/blog/wp-content/uploads/2017/11/Kotlin-A-New-Programming-Platform-For-Android-Developers.png" width="200px">
![kotlin](https://weblizar.com/blog/wp-content/uploads/2017/11/Kotlin-A-New-Programming-Platform-For-Android-Developers.png)
### Developers
- Ivan Agosto: [https://gnusocial.ml/agosto182](https://gnusocial.ml/agosto182)
- Ivan Agosto: [https://mast.lat/@agosto182](https://mast.lat/@agosto182)
## License
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

View File

@ -1,199 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":app" />
</configuration>
</facet>
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="debug" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
<afterSyncTasks>
<task>generateDebugSources</task>
</afterSyncTasks>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
</configuration>
</facet>
<facet type="kotlin-language" name="Kotlin">
<configuration version="3" platform="JVM 1.8" useProjectSettings="false">
<compilerSettings />
<compilerArguments>
<option name="destination" value="$MODULE_DIR$/build/tmp/kotlin-classes/debug" />
<option name="noStdlib" value="true" />
<option name="noReflect" value="true" />
<option name="moduleName" value="app_debug" />
<option name="jvmTarget" value="1.8" />
<option name="addCompilerBuiltIns" value="true" />
<option name="loadBuiltInsFromDependencies" value="true" />
<option name="languageVersion" value="1.2" />
<option name="apiVersion" value="1.2" />
<option name="pluginOptions">
<array>
<option value="plugin:org.jetbrains.kotlin.android:experimental=false" />
<option value="plugin:org.jetbrains.kotlin.android:enabled=true" />
<option value="plugin:org.jetbrains.kotlin.android:defaultCacheImplementation=hashMap" />
</array>
</option>
<option name="pluginClasspaths">
<array>
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-android-extensions/1.2.51/1755c607e5fabf4ba949ef626c73fc7421d35123/kotlin-android-extensions-1.2.51.jar" />
</array>
</option>
</compilerArguments>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_6">
<output url="file://$MODULE_DIR$/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes" />
<output-test url="file://$MODULE_DIR$/build/intermediates/javac/debugUnitTest/compileDebugUnitTestJavaWithJavac/classes" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/not_namespaced_r_class_sources/debug/processDebugResources/r" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/not_namespaced_r_class_sources/debugAndroidTest/processDebugAndroidTestResources/r" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/test/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/annotation_processor_list" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/apk_list" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/build-info" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/builds" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/check-libraries" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/check-manifest" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/checkDebugClasspath" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/compatible_screen_manifest" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-runtime-classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-verifier" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant-run-apk" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant-run-resources" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant_run_merged_manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant_run_split_apk_resources" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javac" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint_jar" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifest-checker" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/merged_assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/merged_manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/prebuild" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/processed_res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/reload-dex" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/resources" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shader_assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/split-apk" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/split_list" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
<excludeFolder url="file://$MODULE_DIR$/build/kotlin" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content>
<orderEntry type="jdk" jdkName="Android API 27 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Gradle: com.android.support:transition-27.1.0" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: com.android.support.test:runner-1.0.2" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:common:1.1.0@jar" level="project" />
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.51@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: com.android.support:support-annotations:27.1.1@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:animated-vector-drawable-27.1.0" level="project" />
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.2.51@jar" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:viewmodel-1.1.0" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-v4-27.1.0" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-compat-27.1.0" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:recyclerview-v7-27.1.0" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: com.squareup:javawriter:2.1.1@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-media-compat-27.1.0" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-vector-drawable-27.1.0" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-annotations:27.1.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout-1.1.2" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-core-utils-27.1.0" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-core-ui-27.1.0" level="project" />
<orderEntry type="library" name="Gradle: org.jetbrains:annotations:13.0@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: com.google.code.findbugs:jsr305:2.0.1@jar" level="project" />
<orderEntry type="library" name="Gradle: com.squareup.okio:okio:1.14.0@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: com.android.support.test.espresso:espresso-core-3.0.2" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: javax.inject:javax.inject:1@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-fragment-27.1.0" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: junit:junit:4.12@jar" level="project" />
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib:1.2.51@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:design-27.1.0" level="project" />
<orderEntry type="library" name="Gradle: android.arch.core:runtime-1.1.0" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-core:1.3@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: com.android.support.test:monitor-1.0.2" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:appcompat-v7-27.1.0" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: com.android.support.test.espresso:espresso-idling-resource-3.0.2" level="project" />
<orderEntry type="library" name="Gradle: com.squareup.okhttp3:okhttp:3.10.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout-solver:1.1.2@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:exifinterface-27.1.0" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:livedata-core-1.1.0" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-library:1.3@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-integration:1.3@jar" level="project" />
<orderEntry type="library" name="Gradle: com.squareup.picasso:picasso-2.71828" level="project" />
<orderEntry type="library" name="Gradle: android.arch.core:common:1.1.0@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: net.sf.kxml:kxml2:2.3.0@jar" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:runtime-1.1.0" level="project" />
</component>
</module>

View File

@ -1,18 +1,20 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
plugins {
id "com.android.application"
id "kotlin-android"
id "kotlin-android-extensions"
}
android {
compileSdkVersion 27
compileSdkVersion 34
defaultConfig {
applicationId "org.libre.agosto.p2play"
minSdkVersion 21
targetSdkVersion 27
versionCode 2
versionName "0.1.5"
minSdkVersion 26
targetSdkVersion 32
versionCode 10
versionName "0.7.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
}
buildTypes {
release {
@ -20,22 +22,33 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
buildToolsVersion '28.0.3'
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_6
targetCompatibility JavaVersion.VERSION_1_6
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
namespace 'org.libre.agosto.p2play'
lint {
abortOnError false
checkReleaseBuilds false
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:27.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
implementation 'com.android.support:support-v4:27.1.0'
implementation 'com.android.support:design:27.1.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'com.squareup.picasso:picasso:2.71828'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.google.android.material:material:1.6.0'
implementation 'androidx.preference:preference:1.2.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test:runner:1.5.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation 'androidx.media3:media3-exoplayer:1.1.1'
implementation 'androidx.media3:media3-exoplayer-dash:1.1.1'
implementation 'androidx.media3:media3-ui:1.1.1'
implementation 'androidx.media3:media3-exoplayer-hls:1.1.1'
implementation "androidx.media3:media3-session:1.1.1"
}

View File

@ -1,24 +0,0 @@
package org.libre.agosto.p2play
import android.support.test.InstrumentationRegistry
import android.support.test.runner.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getTargetContext()
assertEquals("org.libre.agosto.p2play", appContext.packageName)
}
}

View File

@ -1,35 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.libre.agosto.p2play">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_p2play"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_p2play"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/P2playTheme"
android:hardwareAccelerated="true">
<activity android:name=".HostActivity">
android:theme="@style/Theme.P2play">
<activity
android:name=".SettingsActivity2"
android:exported="false"
android:label="@string/title_activity_settings"
android:theme="@style/Theme.P2play">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity" />
</activity>
<activity
android:name=".ChannelActivity"
android:exported="false"
android:theme="@style/Theme.P2play.NoActionBar" />
<activity
android:name=".SplashActivity"
android:exported="true"
android:theme="@style/Theme.P2play.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".HostActivity"
android:exported="false"
android:theme="@style/Theme.P2play.NoActionBar" />
<activity
android:name=".MainActivity"
android:theme="@style/P2playTheme.NoActionBar" />
<activity android:name=".ReproductorActivity" />
<activity android:name=".LoginActivity" />
<activity android:name=".RegisterActivity" />
<activity android:name=".AboutActivity" />
android:exported="false"
android:theme="@style/Theme.P2play.NoActionBar" />
<activity
android:name=".ReproductorActivity"
android:configChanges="orientation|screenSize"
android:exported="false"
android:hardwareAccelerated="true"
android:theme="@style/Theme.P2play.NoActionBar" />
<activity
android:name=".LoginActivity"
android:exported="false" />
<activity
android:name=".RegisterActivity"
android:exported="false" />
<activity
android:name=".AboutActivity"
android:exported="false" />
<activity
android:name=".SettingsActivity"
android:label="@string/title_activity_settings"></activity>
android:exported="false"
android:label="@string/title_activity_settings"
android:theme="@style/Theme.P2play" />
<service
android:name=".services.PlaybackService"
android:exported="true"
android:foregroundServiceType="mediaPlayback">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService" />
</intent-filter>
</service>
</application>
</manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,8 +1,7 @@
package org.libre.agosto.p2play
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.text.method.LinkMovementMethod
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_about.*
class AboutActivity : AppCompatActivity() {
@ -11,6 +10,8 @@ class AboutActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_about)
aboutUrl.text = "https://"+ManagerSingleton.url+"/about/instance"
aboutUrl.text = "https://" + ManagerSingleton.url + "/about/instance"
aboutLabel.text = aboutLabel.text.toString() + " " + this.packageManager.getPackageInfo(this.packageName, 0).versionName
}
}

View File

@ -3,13 +3,13 @@ package org.libre.agosto.p2play
import android.content.res.Configuration
import android.os.Bundle
import android.preference.PreferenceActivity
import android.support.annotation.LayoutRes
import android.support.v7.app.ActionBar
import android.support.v7.app.AppCompatDelegate
import android.support.v7.widget.Toolbar
import android.view.MenuInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.LayoutRes
import androidx.appcompat.app.ActionBar
import androidx.appcompat.app.AppCompatDelegate
import androidx.appcompat.widget.Toolbar
/**
* A [android.preference.PreferenceActivity] which implements and proxies the necessary calls

View File

@ -0,0 +1,148 @@
package org.libre.agosto.p2play
import android.os.AsyncTask
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.activity_channel.*
import org.libre.agosto.p2play.adapters.VideosAdapter
import org.libre.agosto.p2play.ajax.Actions
import org.libre.agosto.p2play.ajax.Channels
import org.libre.agosto.p2play.ajax.Videos
import org.libre.agosto.p2play.helpers.getViewManager
import org.libre.agosto.p2play.models.ChannelModel
import org.libre.agosto.p2play.models.VideoModel
class ChannelActivity : AppCompatActivity() {
private lateinit var channelId: String
private lateinit var channel: ChannelModel
private var isSubcribed: Boolean = false
private val channelService = Channels()
private val videosService = Videos()
private val actionsService = Actions()
private lateinit var recyclerView: RecyclerView
private lateinit var viewAdapter: RecyclerView.Adapter<VideosAdapter.ViewHolder>
private lateinit var viewManager: RecyclerView.LayoutManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_channel)
channelId = this.intent.extras?.getString("channel")!!
viewManager = getViewManager(this, resources)
subcriptionBtn.setOnClickListener {
subscribeAction()
}
}
override fun onResume() {
super.onResume()
getChannel()
getSubscription()
getVideos()
if (ManagerSingleton.user.status == 1) {
subcriptionBtn.visibility = View.VISIBLE
getSubscription()
}
}
private fun getChannel() {
AsyncTask.execute {
channel = channelService.getChannelInfo(channelId)
runOnUiThread {
usernameProfile.text = channel.name
hostTxt.text = channel.host
subcriptionsTxt.text = channel.followers.toString()
if (channel.channelImg != "") {
Picasso.get().load("https://${ManagerSingleton.url}${channel.channelImg}").into(channelImg)
}
}
}
}
private fun subscribe() {
AsyncTask.execute {
val res = actionsService.subscribe(ManagerSingleton.token.token, channel.getAccount())
runOnUiThread {
if (res == 1) {
subcriptionBtn.text = getString(R.string.unSubscribeBtn)
ManagerSingleton.toast(getString(R.string.subscribeMsg), this)
getSubscription()
} else {
ManagerSingleton.toast(getString(R.string.errorMsg), this)
}
}
}
}
private fun unSubscribe() {
AsyncTask.execute {
val res = actionsService.unSubscribe(ManagerSingleton.token.token, channel.getAccount())
runOnUiThread {
if (res == 1) {
subcriptionBtn.text = getString(R.string.subscribeBtn)
ManagerSingleton.toast(getString(R.string.unSubscribeMsg), this)
getSubscription()
} else {
ManagerSingleton.toast(getString(R.string.errorMsg), this)
}
}
}
}
private fun subscribeAction() {
if (isSubcribed) {
unSubscribe()
} else {
subscribe()
}
}
private fun getSubscription() {
AsyncTask.execute {
isSubcribed = actionsService.getSubscription(ManagerSingleton.token.token, channel.getAccount())
runOnUiThread {
if (isSubcribed) {
subcriptionBtn.text = getText(R.string.unSubscribeBtn)
} else {
subcriptionBtn.text = getText(R.string.subscribeBtn)
}
}
}
}
private fun getVideos() {
AsyncTask.execute {
val videos = videosService.channelVideos(channel.getAccount(), 0)
runOnUiThread {
initRecycler(videos)
}
}
}
// Generic function for set data to RecyclerView
private fun initRecycler(data: ArrayList<VideoModel>) {
// val data = arrayListOf<VideoModel>()
viewAdapter = VideosAdapter(data)
recyclerView = findViewById<RecyclerView>(R.id.listVideosChannel).apply {
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
setHasFixedSize(true)
// use a linear layout manager
layoutManager = viewManager
// specify an viewAdapter (see also next example)
adapter = viewAdapter
}
// swipeContainer.isRefreshing = false
}
}

View File

@ -8,11 +8,11 @@ import android.database.sqlite.SQLiteOpenHelper
import org.libre.agosto.p2play.models.TokenModel
import org.libre.agosto.p2play.models.UserModel
class Database(context:Context): SQLiteOpenHelper(context,"p2play",null,1) {
class Database(context: Context) : SQLiteOpenHelper(context, "p2play", null, 1) {
val dbName = "p2play"
private val dbUsers = "CREATE TABLE users(id INTEGER PRIMARY KEY AUTOINCREMENT, uuid INTEGER, username varchar(30), " +
"nsfw INTEGER, email string, followers INTEGER, avatar string, status integer)"
"nsfw INTEGER, email string, followers INTEGER, avatar string, status integer)"
private val dbTokens = "CREATE TABLE tokens(id INTEGER PRIMARY KEY AUTOINCREMENT, token STRING, refresh_token STRING, status INTEGER)"
override fun onCreate(db: SQLiteDatabase?) {
db?.execSQL(dbUsers)
@ -28,12 +28,12 @@ class Database(context:Context): SQLiteOpenHelper(context,"p2play",null,1) {
fun newToken(token: TokenModel): Boolean {
val db = writableDatabase
this.closeTokens()
val newToken=ContentValues()
val newToken = ContentValues()
newToken.put("token", token.token)
newToken.put("refresh_token", token.refresh_token)
newToken.put("status", token.status)
db.insert("tokens",null,newToken)
db.insert("tokens", null, newToken)
return true
}
@ -41,7 +41,7 @@ class Database(context:Context): SQLiteOpenHelper(context,"p2play",null,1) {
fun newUser(user: UserModel): Boolean {
val db = writableDatabase
this.closeUsers()
val newUser=ContentValues()
val newUser = ContentValues()
newUser.put("uuid", user.uuid)
newUser.put("username", user.username)
newUser.put("email", user.email)
@ -50,76 +50,78 @@ class Database(context:Context): SQLiteOpenHelper(context,"p2play",null,1) {
newUser.put("avatar", user.avatar)
newUser.put("status", user.status)
db.insert("users",null, newUser)
db.insert("users", null, newUser)
return true
}
fun getToken(): TokenModel{
fun getToken(): TokenModel {
val db = writableDatabase
var token = TokenModel()
try {
var cursor= db.rawQuery("SELECT * FROM tokens WHERE status=1 ORDER BY id DESC LIMIT 1",null)
cursor.moveToFirst()
var cursor = db.rawQuery("SELECT * FROM tokens WHERE status=1 ORDER BY id DESC LIMIT 1", null)
token.token = cursor.getString(cursor.getColumnIndex("token")).toString()
token.refresh_token = cursor.getString(cursor.getColumnIndex("refresh_token")).toString()
token.status = cursor.getString(cursor.getColumnIndex("status")).toInt()
if (cursor.count != 0) {
cursor.moveToFirst()
token.token = cursor.getString(cursor.getColumnIndex("token")).toString()
token.refresh_token = cursor.getString(cursor.getColumnIndex("refresh_token")).toString()
token.status = cursor.getString(cursor.getColumnIndex("status")).toInt()
}
cursor.close()
return token
}catch (e:SQLiteException){
} catch (e: SQLiteException) {
db?.execSQL(dbTokens)
}catch (e:Exception){
} catch (e: Exception) {
e.printStackTrace()
}
return token
}
fun getUser(): UserModel{
fun getUser(): UserModel {
val db = writableDatabase
var user = UserModel()
try {
var cursor= db.rawQuery("SELECT * FROM users WHERE status=1 ORDER BY id DESC LIMIT 1",null)
cursor.moveToFirst()
var cursor = db.rawQuery("SELECT * FROM users WHERE status=1 ORDER BY id DESC LIMIT 1", null)
user.uuid = cursor.getString(cursor.getColumnIndex("uuid")).toInt()
user.username = cursor.getString(cursor.getColumnIndex("username")).toString()
user.email = cursor.getString(cursor.getColumnIndex("email")).toString()
user.nsfw = cursor.getString(cursor.getColumnIndex("nsfw")).toBoolean()
user.followers = cursor.getString(cursor.getColumnIndex("followers")).toInt()
user.avatar = cursor.getString(cursor.getColumnIndex("avatar")).toString()
user.status = cursor.getString(cursor.getColumnIndex("status")).toInt()
if (cursor.count != 0) {
cursor.moveToFirst()
user.uuid = cursor.getString(cursor.getColumnIndex("uuid")).toInt()
user.username = cursor.getString(cursor.getColumnIndex("username")).toString()
user.email = cursor.getString(cursor.getColumnIndex("email")).toString()
user.nsfw = cursor.getString(cursor.getColumnIndex("nsfw")).toBoolean()
user.followers = cursor.getString(cursor.getColumnIndex("followers")).toInt()
user.avatar = cursor.getString(cursor.getColumnIndex("avatar")).toString()
user.status = cursor.getString(cursor.getColumnIndex("status")).toInt()
}
cursor.close()
return user
}catch (e:SQLiteException){
} catch (e: SQLiteException) {
db?.execSQL(dbTokens)
}catch (e:Exception){
} catch (e: Exception) {
e.printStackTrace()
}
return user
}
private fun closeTokens(){
private fun closeTokens() {
val db = writableDatabase
db.execSQL("UPDATE tokens SET status=-1 WHERE 1")
}
private fun closeUsers(){
private fun closeUsers() {
val db = writableDatabase
db.execSQL("UPDATE users SET status=-1 WHERE 1")
}
fun logout(){
fun logout() {
closeUsers()
closeTokens()
}
}
}

View File

@ -3,20 +3,18 @@ package org.libre.agosto.p2play
import android.content.Intent
import android.content.SharedPreferences
import android.os.AsyncTask
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Looper
import android.preference.PreferenceManager
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceManager
import kotlinx.android.synthetic.main.activity_host.*
import org.libre.agosto.p2play.ajax.Auth
import org.libre.agosto.p2play.ajax.Client
class HostActivity : AppCompatActivity() {
lateinit var settings: SharedPreferences
lateinit var editor: SharedPreferences.Editor
val client:Auth = Auth()
val _db = Database(this)
val client: Auth = Auth()
private val db = Database(this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -24,94 +22,66 @@ class HostActivity : AppCompatActivity() {
settings = PreferenceManager.getDefaultSharedPreferences(this)
editor = settings.edit()
ManagerSingleton.context = this
button.setOnClickListener {
getKeys(hostText.text.toString())
}
val host = settings.getString("hostP2play","")
val lastHost = settings.getString("last_host","")
if(host!=""){
if(lastHost!=host){
_db.logout()
getKeys(host)
}else{
ManagerSingleton.url=host
checkUser()
}
}
}
fun checkUser(){
val token = _db.getToken()
val user = _db.getUser()
AsyncTask.execute {
if (Looper.myLooper() == null)
Looper.prepare()
startApp()
if (token.status == 1 && user.status == 1) {
val client_id = settings.getString("client_id", "")
val client_secret = settings.getString("client_secret", "")
val newToken = client.refreshToken(token, client_id, client_secret)
when (token.status.toString()) {
"1" -> {
_db.newToken(newToken)
ManagerSingleton.token = newToken
ManagerSingleton.user = user
}
else -> _db.logout()
}
val host = settings.getString("hostP2play", "")
val lastHost = settings.getString("last_host", "")
if (host != "") {
if (lastHost != host) {
db.logout()
ManagerSingleton.logout()
getKeys(host!!)
} else {
_db.logout()
ManagerSingleton.url = host
startApp()
}
this.finish()
}
}
fun saveHost(host: String){
editor.putString("last_host",host)
editor.putString("hostP2play",host)
fun saveHost(host: String) {
editor.putString("last_host", host)
editor.putString("hostP2play", host)
editor.apply()
ManagerSingleton.Toast(getString(R.string.finallyMsg))
ManagerSingleton.url=host
checkUser()
ManagerSingleton.toast(getString(R.string.finallyMsg), this)
ManagerSingleton.url = host
startApp()
}
private fun getKeys(hostText: String){
private fun getKeys(hostText: String) {
button.isEnabled = false
var host = hostText.toString()
host = host.replace("http://","")
host = host.replace("https://","")
host = host.replace("/","")
host = host.replace("http://", "")
host = host.replace("https://", "")
host = host.replace("/", "")
ManagerSingleton.url = host
AsyncTask.execute {
if (Looper.myLooper()==null)
if (Looper.myLooper() == null) {
Looper.prepare()
}
val keys = client.getKeys()
if(keys.client_id!=""){
editor.putString("client_id",keys.client_id)
editor.putString("client_secret",keys.client_secret)
if (keys.client_id != "") {
editor.putString("client_id", keys.client_id)
editor.putString("client_secret", keys.client_secret)
editor.apply()
saveHost(host)
}
else{
} else {
runOnUiThread {
ManagerSingleton.Toast(getString(R.string.errorMsg))
ManagerSingleton.toast(getString(R.string.errorMsg), this)
button.isEnabled = true
}
}
}
}
private fun startApp(){
private fun startApp() {
runOnUiThread {
val intent = Intent(ManagerSingleton.context,MainActivity::class.java)
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
this.finish()
}
}
}

View File

@ -3,86 +3,109 @@ package org.libre.agosto.p2play
import android.content.Intent
import android.content.SharedPreferences
import android.os.AsyncTask
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Looper
import android.preference.PreferenceManager
import android.util.Log
import android.widget.EditText
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceManager
import kotlinx.android.synthetic.main.activity_login.*
import org.libre.agosto.p2play.ajax.Auth
class LoginActivity : AppCompatActivity() {
private val _auth = Auth()
private val auth = Auth()
lateinit var settings: SharedPreferences
lateinit var client_id: String
lateinit var client_secret: String
private lateinit var _db: Database
lateinit var clientId: String
lateinit var clientSecret: String
private lateinit var db: Database
private var optCode: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
setTitle(R.string.action_login)
ManagerSingleton.context = this
_db = Database(this)
db = Database(this)
settings = PreferenceManager.getDefaultSharedPreferences(this)
client_id = settings.getString("client_id", "")
client_secret = settings.getString("client_secret", "")
clientId = settings.getString("client_id", "")!!
clientSecret = settings.getString("client_secret", "")!!
registerActionBtn.setOnClickListener { startActivity(Intent(this, RegisterActivity::class.java)) }
loginBtn.setOnClickListener { tryLogin() }
}
fun tryLogin(){
loginBtn.isEnabled = false;
fun tryLogin() {
loginBtn.isEnabled = false
val username = userText.text.toString()
val password = passwordText.text.toString()
AsyncTask.execute {
if (Looper.myLooper()==null)
if (Looper.myLooper() == null) {
Looper.prepare()
}
val token = _auth.login(username, password, client_id, client_secret)
val token = auth.login(username, password, clientId, clientSecret, optCode)
// Log.d("token", token.token )
// Log.d("status", token.status.toString() )
when(token.status.toString()){
when (token.status.toString()) {
"1" -> {
_db.newToken(token)
db.newToken(token)
ManagerSingleton.token = token
getUser()
}
"0" -> {
runOnUiThread {
ManagerSingleton.Toast(getString(R.string.loginError_msg))
ManagerSingleton.toast(getString(R.string.loginError_msg), this)
}
}
"-1" -> {
runOnUiThread {
loginBtn.isEnabled = true
ManagerSingleton.Toast(getString(R.string.loginFailed_msg))
ManagerSingleton.toast(getString(R.string.loginFailed_msg), this)
}
}
"-2" -> {
// TODO: Start 2FA modal
runOnUiThread {
val builder = AlertDialog.Builder(this, R.style.Widget_Material3_MaterialCalendar_Fullscreen)
val dialog = layoutInflater.inflate(R.layout.two_factor_dialog, null)
val inputTwoFactor = dialog.findViewById<EditText>(R.id.twoFactorText)
builder.setView(dialog)
.setTitle(R.string.twoFactorLabel)
// Add action buttons
.setPositiveButton(R.string.loginBtn) { d, _ ->
this.optCode = inputTwoFactor.text.toString()
this.tryLogin()
d.dismiss()
}
.setNegativeButton("Cancel") { d, _ ->
dialog.run { d.cancel() }
loginBtn.isEnabled = true
}
val alertDialog = builder.create()
alertDialog.show()
}
}
}
}
}
fun getUser(){
val user = _auth.me(ManagerSingleton.token.token)
if(user.status == 1){
_db.newUser(user)
fun getUser() {
val user = auth.me(ManagerSingleton.token.token)
if (user.status == 1) {
db.newUser(user)
ManagerSingleton.user = user
runOnUiThread {
ManagerSingleton.Toast(getString(R.string.loginSuccess_msg))
ManagerSingleton.toast(getString(R.string.loginSuccess_msg), this)
finish()
}
}
else{
} else {
runOnUiThread {
ManagerSingleton.Toast(getString(R.string.loginError_msg))
ManagerSingleton.toast(getString(R.string.loginError_msg), this)
}
}
}

View File

@ -1,73 +1,86 @@
package org.libre.agosto.p2play
import android.content.Intent
import android.content.res.Configuration
import android.os.AsyncTask
import android.os.Bundle
import android.support.design.widget.Snackbar
import android.support.design.widget.NavigationView
import android.support.v4.view.GravityCompat
import android.support.v7.app.ActionBarDrawerToggle
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.os.Handler
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.widget.ImageView
import android.view.View
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SearchView
import androidx.core.view.GravityCompat
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.navigation.NavigationView
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.app_bar_main.*
import kotlinx.android.synthetic.main.content_main.*
import kotlinx.android.synthetic.main.activity_main.drawer_layout
import kotlinx.android.synthetic.main.activity_main.nav_view
import kotlinx.android.synthetic.main.app_bar_main.toolbar
import kotlinx.android.synthetic.main.content_main.mini
import kotlinx.android.synthetic.main.content_main.swipeContainer
import kotlinx.android.synthetic.main.mini_player.mini_play_pause
import kotlinx.android.synthetic.main.mini_player.mini_player_author
import kotlinx.android.synthetic.main.mini_player.mini_player_image
import kotlinx.android.synthetic.main.mini_player.mini_player_title
import kotlinx.android.synthetic.main.nav_header_main.*
import org.libre.agosto.p2play.adapters.VideosAdapter
import org.libre.agosto.p2play.ajax.Videos
import org.libre.agosto.p2play.helpers.getViewManager
import org.libre.agosto.p2play.models.VideoModel
import org.libre.agosto.p2play.singletons.PlaybackSingleton
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
private lateinit var recyclerView: RecyclerView
private lateinit var viewAdapter: RecyclerView.Adapter<*>
private lateinit var viewAdapter: RecyclerView.Adapter<VideosAdapter.ViewHolder>
private lateinit var viewManager: RecyclerView.LayoutManager
val client: Videos = Videos()
private val client: Videos = Videos()
private lateinit var lastItem: MenuItem
private lateinit var subItem: MenuItem
lateinit var myMenu: Menu
val _db = Database(this)
private val db = Database(this)
var section: String = ""
var searchVal: String = ""
var pagination = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
/* fab.setOnClickListener { view ->
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
} */
val toggle = ActionBarDrawerToggle(
this, drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
val toggle = ActionBarDrawerToggle(this, drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
drawer_layout.addDrawerListener(toggle)
toggle.syncState()
// Context for ManagerSingleton
ManagerSingleton.context = this
nav_view.setNavigationItemSelectedListener(this)
viewManager = LinearLayoutManager(this)
// Set data for RecyclerView
this.setData(arrayListOf())
viewManager = getViewManager(this, resources)
this.getLastVideos()
// Init RecyclerView
this.initRecycler()
this.getTrengindVideos()
swipeContainer.setOnRefreshListener {
this.refresh()
}
mini_player_image.setOnClickListener { this.resumeVideo() }
mini_player_title.setOnClickListener { this.resumeVideo() }
mini_player_author.setOnClickListener { this.resumeVideo() }
mini.setOnClickListener { this.resumeVideo() }
mini_play_pause.setOnClickListener { this.playPausePlayer() }
Handler().postDelayed({
// Title for nav_bar
side_emailTxt?.text = getString(R.string.nav_header_subtitle) + " " + this.packageManager.getPackageInfo(this.packageName, 0).versionName
}, 2000)
}
// Generic function for set data to RecyclerView
fun setData(data:ArrayList<VideoModel>){
private fun initRecycler() {
val data = arrayListOf<VideoModel>()
viewAdapter = VideosAdapter(data)
recyclerView = findViewById<RecyclerView>(R.id.list).apply {
@ -80,29 +93,64 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
// specify an viewAdapter (see also next example)
adapter = viewAdapter
this.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
// super.onScrolled(recyclerView!!, dx, dy)
if (!swipeContainer.isRefreshing) {
if (!canScrollVertically(1)) {
loadMore()
}
}
}
})
}
swipeContainer.isRefreshing = false
}
fun refresh(){
private fun addVideos(videos: ArrayList<VideoModel>) {
this.swipeContainer.isRefreshing = true
try {
if (this.pagination == 0) {
(viewAdapter as VideosAdapter).clearData()
recyclerView.scrollToPosition(0)
}
(viewAdapter as VideosAdapter).addData(videos)
} catch (err: Exception) {
err.printStackTrace()
ManagerSingleton.toast(getString(R.string.errorMsg), this)
}
this.swipeContainer.isRefreshing = false
}
private fun refresh() {
swipeContainer.isRefreshing = true
when(section){
this.pagination = 0
when (section) {
"local" -> this.getLocalVideos()
"popular" -> this.getPopularVideos()
"trending" -> this.getTrengindVideos()
"last" -> this.getLastVideos()
"sub" -> this.getSubscriptionVideos()
"search" -> this.searchVideos()
"my_videos" -> {
if(ManagerSingleton.token.token != "")
if (ManagerSingleton.token.token != "") {
this.getMyVideos()
else
} else {
this.getLastVideos()
}
}
}
}
fun getSubscriptionVideos(){
if(ManagerSingleton.user.status != 1){
ManagerSingleton.Toast("Inicia session primero")
private fun getSubscriptionVideos() {
if (ManagerSingleton.user.status != 1) {
ManagerSingleton.toast("Inicia session primero", this)
startActivity(Intent(this, LoginActivity::class.java))
return
}
@ -110,59 +158,100 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
section = "sub"
setTitle(R.string.title_subscriptions)
AsyncTask.execute {
val videos = client.videoSubscriptions(ManagerSingleton.token.token)
val videos = client.videoSubscriptions(ManagerSingleton.token.token, this.pagination)
runOnUiThread {
this.setData(videos)
this.addVideos(videos)
}
}
}
// Last videos
fun getLastVideos(){
private fun getLastVideos() {
swipeContainer.isRefreshing = true
section = "last"
setTitle(R.string.title_recent)
AsyncTask.execute {
val videos = client.getLastVideos()
val videos = client.getLastVideos(this.pagination)
runOnUiThread {
this.setData(videos)
this.addVideos(videos)
}
}
}
//
fun getPopularVideos(){
// Popular videos
private fun getPopularVideos() {
swipeContainer.isRefreshing = true
section = "popular"
setTitle(R.string.title_popular)
AsyncTask.execute {
val videos = client.getPopularVideos()
val videos = client.getPopularVideos(this.pagination)
runOnUiThread {
this.setData(videos)
this.addVideos(videos)
}
}
}
fun getLocalVideos(){
// Trending videos
private fun getTrengindVideos() {
swipeContainer.isRefreshing = true
section = "trending"
setTitle(R.string.title_trending)
AsyncTask.execute {
val videos = client.getTrendingVideos(this.pagination)
runOnUiThread {
this.addVideos(videos)
}
}
}
// Local videos
private fun getLocalVideos() {
swipeContainer.isRefreshing = true
section = "local"
setTitle(R.string.title_local)
AsyncTask.execute {
val videos = client.getLocalVideos()
val videos = client.getLocalVideos(this.pagination)
runOnUiThread {
this.setData(videos)
this.addVideos(videos)
}
}
}
fun getMyVideos(){
// Videos of user
private fun getMyVideos() {
swipeContainer.isRefreshing = true
section = "my_videos"
setTitle(R.string.title_myVideos)
AsyncTask.execute {
val videos = client.myVideos(ManagerSingleton.token.token)
val videos = client.myVideos(ManagerSingleton.token.token, this.pagination)
runOnUiThread {
this.setData(videos)
this.addVideos(videos)
}
}
}
// Videos history of user
private fun getHistory() {
swipeContainer.isRefreshing = true
section = "my_videos"
setTitle(R.string.nav_history)
AsyncTask.execute {
val videos = client.videoHistory(ManagerSingleton.token.token, this.pagination)
runOnUiThread {
this.addVideos(videos)
}
}
}
// Most liked
private fun getMostLiked() {
swipeContainer.isRefreshing = true
section = "liked"
setTitle(R.string.nav_likes)
AsyncTask.execute {
val videos = client.getMostLikedVideos(this.pagination)
runOnUiThread {
this.addVideos(videos)
}
}
}
@ -170,6 +259,10 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
override fun onBackPressed() {
if (drawer_layout.isDrawerOpen(GravityCompat.START)) {
drawer_layout.closeDrawer(GravityCompat.START)
} else if (!section.equals("trending")) {
// Hot fix
pagination = 0
this.getTrengindVideos()
} else {
super.onBackPressed()
}
@ -178,6 +271,26 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.main, menu)
val searchItem = menu.findItem(R.id.app_bar_search)
val searchView = searchItem.actionView as SearchView
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextChange(p0: String?): Boolean {
return true
}
override fun onQueryTextSubmit(p0: String?): Boolean {
if (!p0.isNullOrBlank()) {
searchVal = p0
pagination = 0
searchView.onActionViewCollapsed()
searchVideos()
}
return true
}
})
myMenu = menu
setSideData()
return true
@ -195,7 +308,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
// as you specify a parent activity in AndroidManifest.xml.
when (item.itemId) {
R.id.action_settings -> {
val intent = Intent(this, SettingsActivity::class.java)
val intent = Intent(this, SettingsActivity2::class.java)
startActivity(intent)
return true
}
@ -216,27 +329,25 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
// Handle navigation view item clicks here.
// if(::lastItem.isInitialized){
// lastItem.isChecked = false
// lastItem.isChecked = false
// }
lastItem = item
pagination = 0
// item.isChecked = true
when (item.itemId) {
R.id.nav_subscriptions->{
getSubscriptionVideos()
}
R.id.nav_popular-> {
getPopularVideos()
}
R.id.nav_recent-> {
getLastVideos()
}
R.id.nav_local-> {
getLocalVideos()
}
R.id.nav_about-> {
R.id.nav_subscriptions -> getSubscriptionVideos()
R.id.nav_popular -> getPopularVideos()
R.id.nav_trending -> getTrengindVideos()
R.id.nav_recent -> getLastVideos()
R.id.nav_local -> getLocalVideos()
R.id.nav_about -> {
val intent = Intent(this, AboutActivity::class.java)
startActivity(intent)
}
R.id.nav_history -> getHistory()
R.id.nav_myVideos -> getMyVideos()
R.id.nav_likes -> getMostLiked()
}
drawer_layout.closeDrawer(GravityCompat.START)
@ -245,44 +356,117 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
override fun onResume() {
super.onResume()
ManagerSingleton.context = this
setSideData()
if (PlaybackSingleton.player != null && PlaybackSingleton.player!!.isPlaying) {
PlaybackSingleton.runMediaSession(this)
mini_player_title.text = PlaybackSingleton.video!!.name
mini_player_author.text = PlaybackSingleton.video!!.username
Picasso.get().load("https://${ManagerSingleton.url}${PlaybackSingleton.video!!.thumbUrl}").into(mini_player_image)
mini_play_pause.setImageResource(R.drawable.ic_pause_24)
mini.visibility = View.VISIBLE
} else {
mini.visibility = View.GONE
}
}
private fun setSideData(){
if(ManagerSingleton.user.status == 1){
override fun onDestroy() {
if (PlaybackSingleton.player != null) {
PlaybackSingleton.release()
}
super.onDestroy()
}
private fun setSideData() {
if (ManagerSingleton.user.status == 1) {
nav_view.menu.findItem(R.id.ml).isVisible = true
side_usernameTxt?.text = ManagerSingleton.user.username
side_emailTxt?.text = ManagerSingleton.user.email
if(ManagerSingleton.user.avatar!="" && side_imageView != null)
Picasso.get().load("https://"+ManagerSingleton.url+ManagerSingleton.user.avatar).into(side_imageView)
if (ManagerSingleton.user.avatar != "" && side_imageView != null) {
Picasso.get().load("https://" + ManagerSingleton.url + ManagerSingleton.user.avatar).into(side_imageView)
}
side_imageView?.setOnClickListener {
pagination = 0
getMyVideos()
drawer_layout.closeDrawer(GravityCompat.START)
}
if(::myMenu.isInitialized){
if (::myMenu.isInitialized) {
myMenu.findItem(R.id.action_login).isVisible = false
myMenu.findItem(R.id.action_logout).isVisible = true
}
} else {
nav_view.menu.findItem(R.id.ml).isVisible = false
}
}
private fun logout() {
if (::myMenu.isInitialized) {
myMenu.findItem(R.id.action_login).isVisible = true
myMenu.findItem(R.id.action_logout).isVisible = false
}
// nav_view.menu.findItem(R.id.ml).isVisible = false
side_usernameTxt?.text = getString(R.string.nav_header_title)
side_emailTxt?.text = getString(R.string.nav_header_subtitle) + " " + this.packageManager.getPackageInfo(this.packageName, 0).versionName
side_imageView?.setImageResource(R.drawable.default_avatar)
side_imageView?.setOnClickListener { }
db.logout()
ManagerSingleton.logout()
this.refresh()
ManagerSingleton.toast(getString(R.string.logout_msg), this)
setSideData()
}
private fun loadMore() {
swipeContainer.isRefreshing = true
this.pagination += ManagerSingleton.videosCount
when (section) {
"local" -> this.getLocalVideos()
"popular" -> this.getPopularVideos()
"trending" -> this.getTrengindVideos()
"last" -> this.getLastVideos()
"sub" -> this.getSubscriptionVideos()
"search" -> this.searchVideos()
"my_videos" -> {
if (ManagerSingleton.token.token != "") {
this.getMyVideos()
} else {
this.getLastVideos()
}
}
"liked" -> this.getMostLiked()
}
}
private fun searchVideos() {
swipeContainer.isRefreshing = true
section = "search"
this.title = this.searchVal
AsyncTask.execute {
val videos = client.search(this.searchVal, this.pagination)
runOnUiThread {
this.addVideos(videos)
}
}
}
fun logout(){
if(::myMenu.isInitialized){
myMenu.findItem(R.id.action_login).isVisible = true
myMenu.findItem(R.id.action_logout).isVisible = false
}
side_usernameTxt?.text = getString(R.string.nav_header_title)
side_emailTxt?.text = getString(R.string.nav_header_subtitle)
side_imageView?.setImageResource(R.mipmap.ic_launcher_round)
side_imageView?.setOnClickListener { }
_db.logout()
ManagerSingleton.logout()
this.refresh()
ManagerSingleton.Toast(getString(R.string.logout_msg))
private fun resumeVideo() {
val intent = Intent(this, ReproductorActivity::class.java)
intent.putExtra("resume", true)
startActivity(intent)
}
private fun playPausePlayer() {
PlaybackSingleton.player?.let {
if (it.isPlaying) {
it.pause()
mini_play_pause.setImageResource(R.drawable.ic_play_arrow_24)
} else {
it.play()
mini_play_pause.setImageResource(R.drawable.ic_pause_24)
}
}
}
}

View File

@ -1,23 +1,39 @@
package org.libre.agosto.p2play
import android.content.Context
import android.content.SharedPreferences
import org.libre.agosto.p2play.models.TokenModel
import org.libre.agosto.p2play.models.UserModel
object ManagerSingleton {
var context: Context?= null
var url: String?= null
var url: String? = null
var user: UserModel = UserModel()
var token: TokenModel = TokenModel()
// var keys:
fun Toast(text: String?) {
if(this.context == null) { return }
android.widget.Toast.makeText(this.context, text, android.widget.Toast.LENGTH_SHORT).show()
var nfsw: Boolean = false
var videosCount: Int = 0
lateinit var settings: SharedPreferences
lateinit var db: Database
fun toast(text: String?, context: Context) {
android.widget.Toast.makeText(context, text, android.widget.Toast.LENGTH_SHORT).show()
}
fun logout(){
fun logout() {
db.logout()
user = UserModel()
token = TokenModel()
}
}
fun reloadSettings() {
val host = settings.getString("hostP2play", "")
val lastHost = settings.getString("last_host", "")
if (host != "") {
if (lastHost != host) {
logout()
}
url = host
}
nfsw = settings.getBoolean("show_nsfw", false)
videosCount = settings.getString("videos_count", "15")!!.toInt()
}
}

View File

@ -2,52 +2,52 @@ package org.libre.agosto.p2play
import android.content.SharedPreferences
import android.os.AsyncTask
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Looper
import android.preference.PreferenceManager
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceManager
import kotlinx.android.synthetic.main.activity_register.*
import org.libre.agosto.p2play.ajax.Auth
class RegisterActivity : AppCompatActivity() {
private val _auth = Auth()
private val auth = Auth()
lateinit var settings: SharedPreferences
lateinit var client_id: String
lateinit var client_secret: String
lateinit var clientId: String
lateinit var clientSecret: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_register)
setTitle(R.string.registerActionBtn)
ManagerSingleton.context = this
settings = PreferenceManager.getDefaultSharedPreferences(this)
client_id = settings.getString("client_id", "")
client_secret = settings.getString("client_secret", "")
clientId = settings.getString("client_id", "")!!
clientSecret = settings.getString("client_secret", "")!!
registerBtn.setOnClickListener { registerUser() }
}
fun registerUser(){
private fun registerUser() {
registerBtn.isEnabled = false
val username = userText2.text.toString()
val password = passwordText2.text.toString()
val email = emailText.text.toString()
AsyncTask.execute {
if (Looper.myLooper()==null)
if (Looper.myLooper() == null) {
Looper.prepare()
}
val res = _auth.register(username, password, email)
val res = auth.register(username, password, email)
Log.d("Res register", res.toString())
runOnUiThread {
when (res) {
1 -> {
ManagerSingleton.Toast(getString(R.string.registerSuccess_msg))
ManagerSingleton.toast(getString(R.string.registerSuccess_msg), this)
finish()
}
0 -> ManagerSingleton.Toast(getString(R.string.registerFailed_msg))
-1 -> ManagerSingleton.Toast(getString(R.string.registerError_msg))
0 -> ManagerSingleton.toast(getString(R.string.registerFailed_msg), this)
-1 -> ManagerSingleton.toast(getString(R.string.registerError_msg), this)
}
registerBtn.isEnabled = true
}

View File

@ -1,27 +1,82 @@
package org.libre.agosto.p2play
import android.opengl.Visibility
import android.annotation.SuppressLint
import android.content.Intent
import android.content.pm.ActivityInfo
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.AsyncTask
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Looper
import android.support.v4.content.ContextCompat
import android.util.Log
import android.view.View
import android.view.WindowManager
import android.webkit.WebChromeClient
import android.widget.EditText
import android.widget.FrameLayout
import android.widget.ImageView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.media3.common.MediaItem
import androidx.media3.common.MediaMetadata
import androidx.media3.common.Player
import androidx.media3.exoplayer.DefaultLoadControl
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.upstream.DefaultAllocator
import androidx.media3.session.MediaController
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.activity_reproductor.*
import kotlinx.android.synthetic.main.comment_component.commentaryBtn
import kotlinx.android.synthetic.main.comment_component.commentaryLayout
import kotlinx.android.synthetic.main.comment_component.commentaryText
import kotlinx.android.synthetic.main.comment_component.userImgCom
import kotlinx.android.synthetic.main.custom_player_controls.view.exo_controls
import org.libre.agosto.p2play.adapters.CommentariesAdapter
import org.libre.agosto.p2play.ajax.Actions
import org.libre.agosto.p2play.ajax.Comments
import org.libre.agosto.p2play.ajax.Videos
import org.libre.agosto.p2play.helpers.setFullscreen
import org.libre.agosto.p2play.models.CommentaryModel
import org.libre.agosto.p2play.models.VideoModel
import org.libre.agosto.p2play.singletons.PlaybackSingleton
@Suppress("NAME_SHADOWING")
class ReproductorActivity : AppCompatActivity() {
lateinit var video:VideoModel
private val _actions: Actions = Actions()
private val clientVideo: Videos = Videos()
lateinit var video: VideoModel
lateinit var videoPlayback: VideoModel
private val actions: Actions = Actions()
private val client: Comments = Comments()
private val videos: Videos = Videos()
// Commentaries adapter values
private lateinit var recyclerView: RecyclerView
private lateinit var viewAdapter: RecyclerView.Adapter<*>
private lateinit var viewManager: RecyclerView.LayoutManager
// Exoplayer
private lateinit var player: ExoPlayer
private lateinit var mediaControl: MediaController
// Fullscreen info
private var isFullscreen = false
// Resume info
private var isResume = false
@SuppressLint("SetJavaScriptEnabled", "SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_reproductor)
ManagerSingleton.context = this
val fullscreenButton: ImageView = exoPlayer.findViewById(R.id.exo_fullscreen_custom)
val fullscreenButton2 = fullscreenPlayer.findViewById<ImageView>(R.id.exo_fullscreen_custom)
videoView.webChromeClient = WebClient()
videoView.settings.javaScriptEnabled = true
videoView.settings.allowContentAccess = true
videoView.settings.javaScriptCanOpenWindowsAutomatically = true
@ -31,133 +86,433 @@ class ReproductorActivity : AppCompatActivity() {
videoView.settings.domStorageEnabled = true
try {
this.video = this.intent.extras.getSerializable("video") as VideoModel
val resume = this.intent.extras?.getSerializable("resume")
if (resume == null) {
video = this.intent.extras?.getSerializable("video") as VideoModel
isResume = false
} else {
video = PlaybackSingleton.video!!
isResume = true
}
tittleVideoTxt.text = this.video.name
viewsTxt.text = this.video.views.toString() + ' ' + getString(R.string.view_text)
viewsTxt.text = "${this.video.views} ${getString(R.string.view_text)}"
userTxt.text = this.video.username
descriptionVideoTxt.text = this.video.description
val haveDescription = this.video.description.endsWith("...")
if (haveDescription) {
showMoreBtn.visibility = View.VISIBLE
}
hostTxt.text = this.video.userHost
if(this.video.userImageUrl!="")
Picasso.get().load("https://"+ManagerSingleton.url+this.video.userImageUrl).into(userImg)
videoView.loadUrl("https://"+ManagerSingleton.url+this.video.embedUrl)
Log.d("url", videoView.url)
}
catch (err:Exception){
// Check if user had profile image
if (this.video.userImageUrl != "") {
Picasso.get().load("https://" + ManagerSingleton.url + this.video.userImageUrl).into(userImg)
}
// Load the video
videoView.loadUrl("https://" + ManagerSingleton.url + this.video.embedUrl)
} catch (err: Exception) {
err.printStackTrace()
Log.d("Error", err?.message)
}
// subscribeBtn.setOnClickListener { ManagerSingleton.Toast(getString(R.string.comming)) }
viewManager = LinearLayoutManager(this)
this.setDataComments(arrayListOf())
this.getComments()
subscribeBtn.setOnClickListener { subscribe() }
likeLayout.setOnClickListener { rate("like") }
dislikeLayout.setOnClickListener { rate("dislike") }
commentaryBtn.setOnClickListener { makeComment() }
showMoreBtn.setOnClickListener { getDescription() }
shareLayout.setOnClickListener { shareIntent() }
reportLayout.setOnClickListener { reportIntent() }
fullscreenButton.setOnClickListener { toggleFullscreen() }
fullscreenButton2.setOnClickListener { toggleFullscreen() }
userImg.setOnClickListener {
val intent = Intent(this, ChannelActivity::class.java)
intent.putExtra("channel", video.getChannel())
startActivity(intent)
}
AsyncTask.execute {
videoPlayback = this.clientVideo.getVideo(this.video.uuid)
// TODO: Make this configurable
val bufferSize = 1024 * 1024 // 1mb
val allocator = DefaultAllocator(true, bufferSize)
val loadControl = DefaultLoadControl.Builder()
.setAllocator(allocator)
.build()
runOnUiThread {
try {
if (PlaybackSingleton.player == null || !PlaybackSingleton.player!!.playWhenReady) {
PlaybackSingleton.player = ExoPlayer.Builder(this.baseContext)
.setSeekBackIncrementMs(10000)
.setSeekForwardIncrementMs(10000)
.setLoadControl(loadControl).build()
}
player = PlaybackSingleton.player!!
exoPlayer.player = player
player.addListener(
object : Player.Listener {
override fun onPlaybackStateChanged(playbackState: Int) {
super.onPlaybackStateChanged(playbackState)
if (playbackState == Player.STATE_BUFFERING || playbackState == Player.STATE_IDLE) {
exoPlayer.exo_controls.visibility = View.INVISIBLE
} else if (playbackState == Player.STATE_READY) {
exoPlayer.exo_controls.visibility = View.VISIBLE
}
}
}
)
println("----- video --------")
println(videoPlayback.streamingData?.playlistUrl)
if (!isResume) {
val mediaItem = MediaItem.Builder()
.setUri(videoPlayback.streamingData?.playlistUrl!!)
.setMediaMetadata(
MediaMetadata.Builder()
.setArtist(videoPlayback.username)
.setTitle(videoPlayback.name)
.setArtworkUri(Uri.parse("https://${ManagerSingleton.url}${videoPlayback.thumbUrl}"))
.build(),
).build()
PlaybackSingleton.setData(mediaItem, video)
}
// Start the playback.
// player.play()
} catch (err: Exception) {
err.printStackTrace()
}
}
}
}
fun subscribe(){
val account = this.video.userUuid+"@"+this.video.userHost
private fun subscribe() {
AsyncTask.execute {
if (Looper.myLooper() == null)
if (Looper.myLooper() == null) {
Looper.prepare()
val res = this._actions.subscribe(ManagerSingleton.token.token, account)
}
val res = this.actions.subscribe(ManagerSingleton.token.token, video.getChannel())
if (res == 1) {
runOnUiThread {
ManagerSingleton.Toast(getString(R.string.subscribeMsg))
ManagerSingleton.toast(getString(R.string.subscribeMsg), this)
this.changeSubscribeBtn(true)
}
}
}
}
fun unSubscribe(){
val account = this.video.userUuid+"@"+this.video.userHost
private fun unSubscribe() {
AsyncTask.execute {
if (Looper.myLooper() == null)
if (Looper.myLooper() == null) {
Looper.prepare()
val res = this._actions.unSubscribe(ManagerSingleton.token.token, account)
}
val res = this.actions.unSubscribe(ManagerSingleton.token.token, video.getChannel())
if (res == 1) {
runOnUiThread {
ManagerSingleton.Toast(getString(R.string.unSubscribeMsg))
ManagerSingleton.toast(getString(R.string.unSubscribeMsg), this)
this.changeSubscribeBtn(false)
}
}
}
}
fun rate(rate: String){
private fun rate(rate: String) {
AsyncTask.execute {
if (Looper.myLooper() == null)
if (Looper.myLooper() == null) {
Looper.prepare()
val res = this._actions.rate(ManagerSingleton.token.token, this.video.id, rate)
}
val res = this.actions.rate(ManagerSingleton.token.token, this.video.id, rate)
if (res == 1) {
runOnUiThread {
ManagerSingleton.Toast(getString(R.string.rateMsg))
if(rate=="like"){
likeLayout.setBackgroundColor(ContextCompat.getColor(this, R.color.colorLike))
dislikeLayout.background = null
}
else if(rate=="dislike"){
dislikeLayout.setBackgroundColor(ContextCompat.getColor(this, R.color.colorDislike))
likeLayout.background = null
ManagerSingleton.toast(getString(R.string.rateMsg), this)
if (rate == "like") {
textViewLike.setTextColor(ContextCompat.getColor(this, R.color.colorLike))
textViewDislike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light))
} else if (rate == "dislike") {
textViewDislike.setTextColor(ContextCompat.getColor(this, R.color.colorDislike))
textViewLike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light))
}
}
}
}
}
fun getRate(){
private fun getRate() {
AsyncTask.execute {
if (Looper.myLooper() == null)
if (Looper.myLooper() == null) {
Looper.prepare()
val rate = this._actions.getRate(ManagerSingleton.token.token, this.video.id)
}
val rate = this.actions.getRate(ManagerSingleton.token.token, this.video.id)
runOnUiThread {
when (rate){
when (rate) {
"like" -> {
likeLayout.setBackgroundColor(ContextCompat.getColor(this, R.color.colorLike))
dislikeLayout.background = null
textViewLike.setTextColor(ContextCompat.getColor(this, R.color.colorLike))
textViewDislike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light))
}
"dislike" -> {
dislikeLayout.setBackgroundColor(ContextCompat.getColor(this, R.color.colorDislike))
likeLayout.background = null
textViewDislike.setTextColor(ContextCompat.getColor(this, R.color.colorDislike))
textViewLike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light))
}
else -> {
likeLayout.background = null
dislikeLayout.background = null
textViewLike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light))
textViewDislike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light))
}
}
}
}
}
fun getSubscription(){
val account = this.video.userUuid+"@"+this.video.userHost
private fun getSubscription() {
val account = this.video.nameChannel + "@" + this.video.userHost
AsyncTask.execute {
if (Looper.myLooper() == null)
if (Looper.myLooper() == null) {
Looper.prepare()
val isSubscribed = this._actions.getSubscription(ManagerSingleton.token.token, account)
}
val isSubscribed = this.actions.getSubscription(ManagerSingleton.token.token, account)
runOnUiThread {
this.changeSubscribeBtn(isSubscribed)
}
}
}
fun changeSubscribeBtn(subscribed: Boolean){
if(subscribed){
private fun changeSubscribeBtn(subscribed: Boolean) {
if (subscribed) {
subscribeBtn.text = getText(R.string.unSubscribeBtn)
subscribeBtn.setOnClickListener { this.unSubscribe() }
}
else{
} else {
subscribeBtn.text = getText(R.string.subscribeBtn)
subscribeBtn.setOnClickListener { this.subscribe() }
}
}
private fun setDataComments(data: ArrayList<CommentaryModel>) {
// Set data for RecyclerView
viewAdapter = CommentariesAdapter(data).setFragmentManager(supportFragmentManager)
recyclerView = findViewById<RecyclerView>(R.id.listCommentaries).apply {
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
setHasFixedSize(true)
// use a linear layout manager
layoutManager = viewManager
// specify an viewAdapter (see also next example)
adapter = viewAdapter
}
}
private fun getComments() {
AsyncTask.execute {
val data = this.client.getCommentaries(this.video.id)
runOnUiThread {
this.setDataComments(data)
}
}
}
private fun makeComment() {
if (commentaryText.text.toString() == "") {
ManagerSingleton.toast(getString(R.string.emptyCommentaryMsg), this)
return
}
val text = commentaryText.text.toString()
AsyncTask.execute {
val res = this.client.makeCommentary(ManagerSingleton.token.token, this.video.id, text)
runOnUiThread {
if (res) {
ManagerSingleton.toast(getString(R.string.makedCommentaryMsg), this)
commentaryText.text?.clear()
this.getComments()
} else {
ManagerSingleton.toast(getString(R.string.errorCommentaryMsg), this)
}
}
}
}
override fun onResume() {
super.onResume()
if(ManagerSingleton.user.status == 1) {
if (ManagerSingleton.user.status == 1) {
this.getRate()
this.getSubscription()
actionsLayout.visibility = View.VISIBLE
subscribeBtn.visibility = View.VISIBLE
commentaryLayout.visibility = View.VISIBLE
if (ManagerSingleton.user.avatar != "") {
Picasso.get().load("https://" + ManagerSingleton.url + ManagerSingleton.user.avatar).into(userImgCom)
}
} else {
commentaryLayout.visibility = View.GONE
}
}
private fun getDescription() {
AsyncTask.execute {
val fullDescription = this.videos.fullDescription(this.video.id)
runOnUiThread {
descriptionVideoTxt.text = fullDescription
showMoreBtn.visibility = View.GONE
}
}
}
private fun shareIntent() {
val sendIntent: Intent = Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_TEXT, "${video.name} ${video.getVideoUrl()}")
type = "text/plain"
}
startActivity(Intent.createChooser(sendIntent, resources.getText(R.string.shareBtn)))
}
private fun reportIntent() {
val builder = AlertDialog.Builder(this)
// Get the layout inflater
val dialog = layoutInflater.inflate(R.layout.report_dialog, null)
val inputReason = dialog.findViewById<EditText>(R.id.reportText)
// Inflate and set the layout for the dialog
// Pass null as the parent view because its going in the dialog layout
builder.setView(dialog)
.setTitle(R.string.reportDialog)
// Add action buttons
.setPositiveButton(R.string.reportBtn) { _, _ ->
val reason = inputReason.text.toString()
reportVideo(reason)
}
.setNegativeButton("Cancel") { dialog, _ ->
dialog.run { cancel() }
}
val alertDialog = builder.create()
alertDialog.show()
}
private fun reportVideo(reason: String) {
AsyncTask.execute {
val res = actions.reportVideo(video.id, reason, ManagerSingleton.token.token)
runOnUiThread {
if (res) {
ManagerSingleton.toast(getText(R.string.reportDialogMsg).toString(), this)
} else {
ManagerSingleton.toast(getText(R.string.errorMsg).toString(), this)
}
}
}
}
private fun toggleFullscreen() {
if (isFullscreen) {
nonFullScreen.visibility = View.VISIBLE
fullScreenExo.visibility = View.GONE
exoPlayer.player = player
fullscreenPlayer.player = null
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
val attrs = window.attributes
attrs.flags = attrs.flags and WindowManager.LayoutParams.FLAG_FULLSCREEN.inv()
attrs.flags = attrs.flags and WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON.inv()
window.attributes = attrs
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE
isFullscreen = false
} else {
val matchParent = WindowManager.LayoutParams.MATCH_PARENT
nonFullScreen.visibility = View.GONE
fullScreenExo.visibility = View.VISIBLE
exoPlayer.player = null
fullscreenPlayer.player = player
setFullscreen(window)
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
isFullscreen = true
}
}
override fun onDestroy() {
if (!player.isPlaying) {
PlaybackSingleton.release()
}
super.onDestroy()
}
internal inner class WebClient : WebChromeClient() {
private var mCustomView: View? = null
private var mCustomViewCallback: WebChromeClient.CustomViewCallback? = null
private var mOriginalOrientation: Int = 0
private var mOriginalSystemUiVisibility: Int = 0
override fun getDefaultVideoPoster(): Bitmap? {
AsyncTask.execute {
this@ReproductorActivity.actions.watchVideo(this@ReproductorActivity.video.id, ManagerSingleton.token.token)
}
return if (mCustomView == null) {
null
} else {
BitmapFactory.decodeResource(this@ReproductorActivity.resources, 2130837573)
}
}
override fun onHideCustomView() {
try {
this@ReproductorActivity.nonFullScreen.visibility = View.VISIBLE
this@ReproductorActivity.fullScreen.visibility = View.GONE
this@ReproductorActivity.fullScreen.removeView(this.mCustomView)
this.mCustomView = null
this.mCustomViewCallback!!.onCustomViewHidden()
this.mCustomViewCallback = null
this@ReproductorActivity.requestedOrientation = this.mOriginalOrientation
// this@ReproductorActivity.window.decorView.systemUiVisibility = this.mOriginalSystemUiVisibility
val attrs = this@ReproductorActivity.window.attributes
attrs.flags = attrs.flags and WindowManager.LayoutParams.FLAG_FULLSCREEN.inv()
attrs.flags = attrs.flags and WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON.inv()
window.attributes = attrs
this@ReproductorActivity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE
} catch (err: Exception) {
err.printStackTrace()
}
}
override fun onShowCustomView(paramView: View, paramCustomViewCallback: WebChromeClient.CustomViewCallback) {
if (this.mCustomView != null) {
this.onHideCustomView()
return
}
try {
this.mCustomView = paramView
this.mOriginalSystemUiVisibility = this@ReproductorActivity.window.decorView.systemUiVisibility
this.mOriginalOrientation = this@ReproductorActivity.requestedOrientation
this.mCustomViewCallback = paramCustomViewCallback
val matchParent = WindowManager.LayoutParams.MATCH_PARENT
this@ReproductorActivity.nonFullScreen.visibility = View.GONE
this@ReproductorActivity.fullScreen.visibility = View.VISIBLE
this@ReproductorActivity.fullScreen.addView(paramView, FrameLayout.LayoutParams(matchParent, matchParent))
setFullscreen(this@ReproductorActivity.window)
this@ReproductorActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
} catch (err: Exception) {
err.printStackTrace()
}
}
}
}

View File

@ -4,8 +4,6 @@ import android.annotation.TargetApi
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
import android.media.RingtoneManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.preference.ListPreference
@ -13,9 +11,6 @@ import android.preference.Preference
import android.preference.PreferenceActivity
import android.preference.PreferenceFragment
import android.preference.PreferenceManager
import android.preference.RingtonePreference
import android.text.TextUtils
import android.util.Log
import android.view.MenuItem
/**
@ -32,13 +27,12 @@ class SettingsActivity : AppCompatPreferenceActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ManagerSingleton.context = this
setupActionBar()
}
override fun onBackPressed() {
super.onBackPressed()
ManagerSingleton.Toast(getString(R.string.pref_message_exit))
ManagerSingleton.toast(getString(R.string.pref_message_exit), this)
}
/**
@ -68,8 +62,8 @@ class SettingsActivity : AppCompatPreferenceActivity() {
* Make sure to deny any unknown fragments here.
*/
override fun isValidFragment(fragmentName: String): Boolean {
return PreferenceFragment::class.java.name == fragmentName
|| GeneralPreferenceFragment::class.java.name == fragmentName
return PreferenceFragment::class.java.name == fragmentName ||
GeneralPreferenceFragment::class.java.name == fragmentName
}
/**
@ -117,11 +111,12 @@ class SettingsActivity : AppCompatPreferenceActivity() {
// Set the summary to reflect the new value.
preference.setSummary(
if (index >= 0)
listPreference.entries[index]
else
null)
if (index >= 0) {
listPreference.entries[index]
} else {
null
},
)
} else {
// For all other preferences, set the summary to the value's
// simple string representation.
@ -153,10 +148,12 @@ class SettingsActivity : AppCompatPreferenceActivity() {
// Trigger the listener immediately with the preference's
// current value.
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
PreferenceManager
.getDefaultSharedPreferences(preference.context)
.getString(preference.key, ""))
sBindPreferenceSummaryToValueListener.onPreferenceChange(
preference,
PreferenceManager
.getDefaultSharedPreferences(preference.context)
.getString(preference.key, ""),
)
}
}
}

View File

@ -0,0 +1,31 @@
package org.libre.agosto.p2play
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceFragmentCompat
class SettingsActivity2 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.settings_activity)
if (savedInstanceState == null) {
supportFragmentManager
.beginTransaction()
.replace(R.id.settings, SettingsFragment())
.commit()
}
supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
override fun onDestroy() {
super.onDestroy()
ManagerSingleton.reloadSettings()
}
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
}
}
}

View File

@ -0,0 +1,101 @@
package org.libre.agosto.p2play
import android.content.Intent
import android.content.SharedPreferences
import android.os.AsyncTask
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceManager
import org.libre.agosto.p2play.ajax.Auth
import java.lang.Exception
class SplashActivity : AppCompatActivity() {
lateinit var settings: SharedPreferences
val client: Auth = Auth()
val db = Database(this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)
settings = PreferenceManager.getDefaultSharedPreferences(this)
ManagerSingleton.settings = settings
ManagerSingleton.db = db
ManagerSingleton.reloadSettings()
val host = settings.getString("hostP2play", "")
val lastHost = settings.getString("last_host", "")
if (host != "") {
if (lastHost != host) {
Handler().postDelayed({
startHostActivity()
}, 2000)
} else {
ManagerSingleton.url = host
checkUser()
}
} else {
Handler().postDelayed({
startHostActivity()
}, 2000)
}
}
private fun checkUser() {
Log.d("was", "Checked")
try {
val token = db.getToken()
val user = db.getUser()
AsyncTask.execute {
if (Looper.myLooper() == null) {
Looper.prepare()
}
if (token.status == 1 && user.status == 1) {
val clientId = settings.getString("client_id", "")!!
val clientSecret = settings.getString("client_secret", "")!!
val newToken = client.refreshToken(token, clientId, clientSecret)
when (token.status.toString()) {
"1" -> {
db.newToken(newToken)
ManagerSingleton.token = newToken
ManagerSingleton.user = user
}
else -> ManagerSingleton.logout()
}
} else {
ManagerSingleton.logout()
}
startApp()
}
} catch (err: Exception) {
err.printStackTrace()
Handler().postDelayed({
startApp()
}, 2000)
}
}
private fun startApp() {
runOnUiThread {
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
this.finish()
}
}
private fun startHostActivity() {
runOnUiThread {
val intent = Intent(this, HostActivity::class.java)
startActivity(intent)
this.finish()
}
}
}

View File

@ -0,0 +1,116 @@
package org.libre.agosto.p2play.adapters
import android.content.Context
import android.os.Bundle
import android.text.Html
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
import androidx.recyclerview.widget.RecyclerView
import com.squareup.picasso.Picasso
import org.libre.agosto.p2play.ManagerSingleton
import org.libre.agosto.p2play.R
import org.libre.agosto.p2play.dialogs.ThreadDialog
import org.libre.agosto.p2play.models.CommentaryModel
import java.io.Serializable
class CommentariesAdapter(private val myDataset: ArrayList<CommentaryModel>) :
RecyclerView.Adapter<CommentariesAdapter.ViewHolder>() {
private lateinit var fragmentManager: FragmentManager
fun setFragmentManager(manager: FragmentManager): CommentariesAdapter {
this.fragmentManager = manager
return this
}
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder.
// Each data item is just a string in this case that is shown in a TextView.
class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
val userImg: ImageView
val username: TextView
val commentary: TextView
val replyBtn: TextView
val context: Context
init {
// Define click listener for the ViewHolder's View
username = view.findViewById(R.id.userTxt)
commentary = view.findViewById(R.id.userCommentary)
userImg = view.findViewById(R.id.userCommentImg)
replyBtn = view.findViewById(R.id.replyBtn)
context = view.context
}
}
// Create new views (invoked by the layout manager)
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int,
): ViewHolder {
// create a new view
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.view_commentary, parent, false) as View
// set the view's size, margins, paddings and layout parameters
return ViewHolder(view)
}
// Replace the contents of a view (invoked by the layout manager)
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
holder.username.text = myDataset[position].username
// holder.userImg.setOnClickListener {
// val intent = Intent(holder.context, ChannelActivity::class.java)
// intent.putExtra("channel", myDataset[position])
// holder.context.startActivity(intent)
// }
if (myDataset[position].userImageUrl != "") {
Picasso.get().load("https://" + ManagerSingleton.url + myDataset[position].userImageUrl).into(holder.userImg)
}
holder.commentary.text = Html.fromHtml(myDataset[position].commentary)
holder.replyBtn.setOnClickListener { this.initRepliesDialog(myDataset[position]) }
if (myDataset[position].replies > 0) {
holder.replyBtn.text = holder.itemView.context.getString(R.string.see_replies, myDataset[position].replies)
}
// TODO: Support for view and account (is different than a video channel)
// holder.userImg.setOnClickListener {
// val intent = Intent(holder.context, ChannelActivity::class.java)
// intent.putExtra("channel", myDataset[position].getAccount())
// holder.context.startActivity(intent)
// }
}
// Return the size of your dataset (invoked by the layout manager)
override fun getItemCount() = myDataset.size
private fun initRepliesDialog(commentData: CommentaryModel) {
val dialog = ThreadDialog()
val bundle = Bundle()
bundle.putSerializable("comment", commentData as Serializable)
dialog.arguments = bundle
dialog.fragmentManager2 = this.fragmentManager
val transaction = fragmentManager.beginTransaction()
// For a polished look, specify a transition animation.
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
// To make it fullscreen, use the 'content' root view as the container
// for the fragment, which is always the root view for the activity.
transaction
.add(android.R.id.content, dialog)
.addToBackStack("comments")
.commit()
}
}

View File

@ -1,55 +1,44 @@
package org.libre.agosto.p2play.adapters
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.graphics.drawable.Drawable
import android.os.AsyncTask
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.squareup.picasso.Picasso
import org.libre.agosto.p2play.MainActivity
import org.libre.agosto.p2play.ChannelActivity
import org.libre.agosto.p2play.ManagerSingleton
import org.libre.agosto.p2play.R
import org.libre.agosto.p2play.ReproductorActivity
import org.libre.agosto.p2play.helpers.mapSeconds
import org.libre.agosto.p2play.models.VideoModel
import java.io.InputStream
import java.io.Serializable
import java.net.URL
class VideosAdapter(private val myDataset: ArrayList<VideoModel>) :
RecyclerView.Adapter<VideosAdapter.ViewHolder>() {
RecyclerView.Adapter<VideosAdapter.ViewHolder>() {
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder.
// Each data item is just a string in this case that is shown in a TextView.
class ViewHolder(val view: View) : RecyclerView.ViewHolder(view){
val thumb: ImageView
val userImg: ImageView
val tittle: TextView
val description: TextView
init {
// Define click listener for the ViewHolder's View
tittle = view.findViewById(R.id.tittleTxt)
description = view.findViewById(R.id.descriptionTxt)
thumb = view.findViewById(R.id.thumb)
userImg = view.findViewById(R.id.userImg)
}
class ViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
val thumb: ImageView = view.findViewById(R.id.thumb)
val userImg: ImageView = view.findViewById(R.id.userImg)
val title: TextView = view.findViewById(R.id.tittleTxt)
val description: TextView = view.findViewById(R.id.descriptionTxt)
val context: Context = view.context
val duration: TextView = view.findViewById(R.id.duration)
val isLive: TextView = view.findViewById(R.id.isLive)
}
// Create new views (invoked by the layout manager)
override fun onCreateViewHolder(parent: ViewGroup,
viewType: Int): VideosAdapter.ViewHolder {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
// create a new view
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.view_video, parent, false) as View
.inflate(R.layout.view_video, parent, false) as View
// set the view's size, margins, paddings and layout parameters
return ViewHolder(view)
}
@ -58,22 +47,57 @@ class VideosAdapter(private val myDataset: ArrayList<VideoModel>) :
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
holder.tittle.text = myDataset[position].name
Picasso.get().load("https://"+ManagerSingleton.url+myDataset[position].thumbUrl).into(holder.thumb)
holder.thumb.setOnClickListener {
val intent = Intent(ManagerSingleton.context, ReproductorActivity::class.java)
intent.putExtra("video", myDataset[position] as Serializable)
ManagerSingleton.context!!.startActivity(intent)
holder.title.text = myDataset[position].name
holder.title.setOnClickListener {
this.launchChannelActivity(myDataset[position] as Serializable, holder.context)
}
Picasso.get().load("https://" + ManagerSingleton.url + myDataset[position].thumbUrl).into(holder.thumb)
holder.thumb.setOnClickListener {
this.launchChannelActivity(myDataset[position] as Serializable, holder.context)
}
if(myDataset[position].userImageUrl!="")
Picasso.get().load("https://"+ManagerSingleton.url+myDataset[position].userImageUrl).into(holder.userImg);
val viewsText = ManagerSingleton.context!!.getString(R.string.view_text)
val timeText = ManagerSingleton.context!!.getString(R.string.time_text)
holder.description.text = myDataset[position].username+" - "+myDataset[position].views+" "+viewsText+" - "+myDataset[position].duration+" "+timeText
holder.userImg.setOnClickListener {
val intent = Intent(holder.context, ChannelActivity::class.java)
intent.putExtra("channel", myDataset[position].getChannel())
holder.context.startActivity(intent)
}
if (myDataset[position].userImageUrl != "") {
Picasso.get().load("https://" + ManagerSingleton.url + myDataset[position].userImageUrl).into(holder.userImg)
} else {
Picasso.get().load(R.drawable.default_avatar).into(holder.userImg)
}
val viewsText = holder.context.getString(R.string.view_text)
val seconds = myDataset[position].duration.toInt()
val timeString = mapSeconds(seconds)
holder.duration.text = timeString
holder.description.text = myDataset[position].username + " - " + myDataset[position].views + " " + viewsText
if (myDataset[position].isLive) {
holder.isLive.visibility = View.VISIBLE
}
}
// Return the size of your dataset (invoked by the layout manager)
override fun getItemCount() = myDataset.size
}
fun clearData() {
myDataset.clear()
notifyDataSetChanged()
}
fun addData(newItems: ArrayList<VideoModel>) {
val lastPos = myDataset.size
myDataset.addAll(newItems)
notifyItemRangeInserted(lastPos, newItems.size)
}
private fun launchChannelActivity(data: Serializable, context: Context) {
val intent = Intent(context, ReproductorActivity::class.java)
intent.putExtra("video", data)
context.startActivity(intent)
}
}

View File

@ -3,11 +3,11 @@ package org.libre.agosto.p2play.ajax
import android.util.JsonReader
import java.io.InputStreamReader
class Actions: Client() {
class Actions : Client() {
fun subscribe(token: String, account: String):Int{
var con=this._newCon("users/me/subscriptions","POST", token)
val params:String= "uri=$account"
fun subscribe(token: String, account: String): Int {
val con = this.newCon("users/me/subscriptions", "POST", token)
val params: String = "uri=$account"
con.outputStream.write(params.toByteArray())
var response = 0
@ -15,65 +15,66 @@ class Actions: Client() {
if (con.responseCode == 204) {
response = 1
}
}
catch (err: Exception){
} catch (err: Exception) {
err.printStackTrace()
response = -1
}
con.disconnect()
return response
}
fun unSubscribe(token: String, account: String):Int{
var con=this._newCon("users/me/subscriptions/$account","DELETE", token)
fun unSubscribe(token: String, account: String): Int {
val con = this.newCon("users/me/subscriptions/$account", "DELETE", token)
var response = 0
try {
if (con.responseCode == 204) {
response = 1
}
}
catch (err: Exception){
} catch (err: Exception) {
err.printStackTrace()
response = -1
}
con.disconnect()
return response
}
fun getSubscription(token: String, account: String): Boolean{
var con=this._newCon("users/me/subscriptions/exist?uris=$account","GET", token)
fun getSubscription(token: String, account: String): Boolean {
val con = this.newCon("users/me/subscriptions/exist?uris=$account", "GET", token)
var isSubscribed = false
try {
if (con.responseCode == 200) {
var response = InputStreamReader(con.inputStream)
var data = JsonReader(response)
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
data.beginObject()
while (data.hasNext()){
while (data.hasNext()) {
val key = data.nextName()
when (key.toString()) {
account->{
account -> {
isSubscribed = data.nextBoolean()
}
else->{
else -> {
data.skipValue()
}
}
}
data.close()
}
}
catch (err: Exception){
} catch (err: Exception) {
err.printStackTrace()
isSubscribed = false
}
con.disconnect()
return isSubscribed
}
fun rate(token: String, id_video: Int, rate: String):Int{
var con=this._newCon("videos/$id_video/rate","PUT", token)
val params:String= "rating=$rate"
fun rate(token: String, id_video: Int, rate: String): Int {
val con = this.newCon("videos/$id_video/rate", "PUT", token)
val params = "rating=$rate"
con.outputStream.write(params.toByteArray())
var response = 0
@ -81,43 +82,79 @@ class Actions: Client() {
if (con.responseCode == 204) {
response = 1
}
}
catch (err: Exception){
} catch (err: Exception) {
err.printStackTrace()
response = -1
}
con.disconnect()
return response
}
fun getRate(token: String, id_video: Int): String {
val con = this.newCon("users/me/videos/$id_video/rating", "GET", token)
var rating = "none"
try {
if (con.responseCode == 200) {
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
data.beginObject()
while (data.hasNext()) {
val key = data.nextName()
when (key.toString()) {
"rating" -> {
rating = data.nextString()
}
else -> {
data.skipValue()
}
}
}
con.disconnect()
}
} catch (err: Exception) {
err.printStackTrace()
rating = "none"
}
con.disconnect()
return rating
}
fun reportVideo(videoId: Int, reason: String, token: String): Boolean {
val con = this.newCon("videos/$videoId/abuse", "POST", token)
val params = "reason=$reason"
con.outputStream.write(params.toByteArray())
var response = false
try {
if (con.responseCode == 200) {
response = true
}
} catch (err: Exception) {
err.printStackTrace()
response = false
}
return response
}
fun getRate(token: String, id_video: Int):String{
var con=this._newCon("users/me/videos/$id_video/rating","GET", token)
var rating = "none"
fun watchVideo(videoId: Int, token: String): Boolean {
val con = this.newCon("videos/$videoId/watching", "PUT", token)
val params = "currentTime=1"
con.outputStream.write(params.toByteArray())
var response = false
try {
if (con.responseCode == 200) {
var response = InputStreamReader(con.inputStream)
var data = JsonReader(response)
data.beginObject()
while (data.hasNext()){
val key = data.nextName()
when (key.toString()) {
"rating"->{
rating = data.nextString()
}
else->{
data.skipValue()
}
}
}
if (con.responseCode == 204) {
response = true
}
}
catch (err: Exception){
} catch (err: Exception) {
err.printStackTrace()
rating = "none"
response = false
}
return rating
return response
}
}
}

View File

@ -4,55 +4,64 @@ package org.libre.agosto.p2play.ajax
import android.util.JsonReader
import android.util.JsonToken
import android.util.Log
import org.libre.agosto.p2play.ManagerSingleton
import org.libre.agosto.p2play.models.TokenModel
import org.libre.agosto.p2play.models.UserModel
import java.io.InputStreamReader
class Auth: Client() {
val stockParams = "grant_type=password"
class Auth : Client() {
private val stockParams = "grant_type=password"
fun login(username: String, password: String, client_id: String, client_secret: String, twoFactorCode: String? = null): TokenModel {
val con = this.newCon("users/token", "POST")
val params = "$stockParams&username=$username&password=$password&client_id=$client_id&client_secret=$client_secret"
if (twoFactorCode !== null) {
con.setRequestProperty("x-peertube-otp", twoFactorCode)
}
fun login(username: String, password: String, client_id: String, client_secret: String): TokenModel{
var con = this._newCon("users/token","POST")
val params:String= "$stockParams&username=$username&password=$password&client_id=$client_id&client_secret=$client_secret"
con.outputStream.write(params.toByteArray())
var token = TokenModel()
val token = TokenModel()
try {
when (con.responseCode) {
200 -> {
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
data.beginObject()
if(con.responseCode==200){
var response = InputStreamReader(con.inputStream)
var data = JsonReader(response)
data.beginObject()
while(data.hasNext()){
val k = data.nextName()
when(k.toString()){
"access_token" -> token.token = data.nextString()
"refresh_token" -> token.refresh_token = data.nextString()
else -> data.skipValue()
while (data.hasNext()) {
val k = data.nextName()
when (k.toString()) {
"access_token" -> token.token = data.nextString()
"refresh_token" -> token.refresh_token = data.nextString()
else -> data.skipValue()
}
}
data.endObject()
data.close()
token.status = 1
}
401 -> {
// User require 2FA code
token.status = -2
}
else -> {
Log.d("Status", con.responseMessage)
}
data.endObject()
token.status = 1
}
else{
Log.d("Status", con.responseMessage)
}
}
catch (err: Exception){
} catch (err: Exception) {
err.printStackTrace()
token.status = 0
}
con.disconnect()
return token
}
fun register(username: String, password: String, email: String): Int{
var con = this._newCon("users/register","POST")
val params:String= "username=$username&password=$password&email=$email"
fun register(username: String, password: String, email: String): Int {
val con = this.newCon("users/register", "POST")
val params = "username=$username&password=$password&email=$email"
con.outputStream.write(params.toByteArray())
var response = 0
@ -61,31 +70,30 @@ class Auth: Client() {
if (con.responseCode == 204) {
response = 1
}
}
catch (err: Exception){
} catch (err: Exception) {
err.printStackTrace()
response = -1
}
con.disconnect()
return response
}
fun refreshToken(token: TokenModel, client_id: String, client_secret: String): TokenModel{
var con = this._newCon("users/token", "POST", token.token)
val params:String = "refresh_token=${token.refresh_token}&response_type=code&grant_type=refresh_token&client_id=$client_id&client_secret=$client_secret"
fun refreshToken(token: TokenModel, client_id: String, client_secret: String): TokenModel {
val con = this.newCon("users/token", "POST", token.token)
val params = "refresh_token=${token.refresh_token}&response_type=code&grant_type=refresh_token&client_id=$client_id&client_secret=$client_secret"
con.outputStream.write(params.toByteArray())
var token = TokenModel()
// val token = TokenModel()
try {
if(con.responseCode==200){
var response = InputStreamReader(con.inputStream)
var data = JsonReader(response)
if (con.responseCode == 200) {
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
data.beginObject()
while(data.hasNext()){
while (data.hasNext()) {
val k = data.nextName()
when(k.toString()){
when (k.toString()) {
"access_token" -> token.token = data.nextString()
"refresh_token" -> token.refresh_token = data.nextString()
else -> data.skipValue()
@ -93,48 +101,45 @@ class Auth: Client() {
}
data.endObject()
data.close()
token.status = 1
}
else{
} else {
Log.d("Status", con.responseMessage)
}
}
catch (err: Exception){
} catch (err: Exception) {
err.printStackTrace()
token.status = 0
}
con.disconnect()
return token
}
fun me(token: String): UserModel{
var con = this._newCon("users/me","GET", token)
var user = UserModel()
fun me(token: String): UserModel {
val con = this.newCon("users/me", "GET", token)
val user = UserModel()
try {
if(con.responseCode==200){
var response = InputStreamReader(con.inputStream)
var data = JsonReader(response)
if (con.responseCode == 200) {
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
data.beginObject()
while(data.hasNext()){
while (data.hasNext()) {
val k = data.nextName()
when(k.toString()){
when (k.toString()) {
"id" -> user.uuid = data.nextInt()
"username" -> user.username = data.nextString()
"email" -> user.email = data.nextString()
"displayNSFW" -> user.nsfw = data.nextBoolean()
"account" -> {
data.beginObject()
while (data.hasNext()){
while (data.hasNext()) {
val l = data.nextName()
when(l.toString()){
when (l.toString()) {
"followersCount" -> user.followers = data.nextInt()
"avatar" -> {
if(data.peek() == JsonToken.BEGIN_OBJECT) {
if (data.peek() == JsonToken.BEGIN_OBJECT) {
data.beginObject()
while (data.hasNext()) {
val m = data.nextName()
@ -144,8 +149,7 @@ class Auth: Client() {
}
}
data.endObject()
}
else{
} else {
data.skipValue()
}
}
@ -159,19 +163,17 @@ class Auth: Client() {
}
data.endObject()
data.close()
user.status = 1
}
else{
} else {
Log.d("Status", con.responseMessage)
}
}
catch (err: Exception){
} catch (err: Exception) {
err.printStackTrace()
user.status = 0
}
con.disconnect()
return user
}
}
}

View File

@ -0,0 +1,33 @@
package org.libre.agosto.p2play.ajax
import android.util.JsonReader
import org.libre.agosto.p2play.models.ChannelModel
import java.io.InputStreamReader
class Channels : Client() {
private fun parseChannel(data: JsonReader): ChannelModel {
val channel = ChannelModel()
data.close()
return channel
}
fun getChannelInfo(account: String): ChannelModel {
val con = this.newCon("video-channels/$account", "GET")
var channel = ChannelModel()
try {
if (con.responseCode == 200) {
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
channel.parseChannel(data)
data.close()
}
} catch (err: Exception) {
err.printStackTrace()
}
return channel
}
}

View File

@ -1,6 +1,5 @@
package org.libre.agosto.p2play.ajax
import android.content.SharedPreferences
import android.util.JsonReader
import android.util.Log
import org.libre.agosto.p2play.ManagerSingleton
@ -10,61 +9,59 @@ import java.net.HttpURLConnection
import java.net.URL
open class Client {
protected fun newCon(uri: String, method: String, token: String = ""): HttpURLConnection {
val url = URL("https://${ManagerSingleton.url}/api/v1/$uri")
val con = url.openConnection() as HttpURLConnection
protected fun _newCon(uri: String, method: String, token: String = ""): HttpURLConnection {
var url = URL("https://"+ManagerSingleton.url+"/api/v1/"+uri)
var con = url.openConnection() as HttpURLConnection
con.setRequestProperty("User-Agent", "P2play/0.1")
con.setRequestProperty("User-Agent", "P2play/0.5.3")
con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded")
con.setRequestProperty("Accept", "*/*")
if(token != ""){
con.setRequestProperty("Authorization", "Bearer ${token}")
if (token != "") {
con.setRequestProperty("Authorization", "Bearer $token")
}
con.requestMethod=method
con.connectTimeout=10000
con.readTimeout=10000
con.requestMethod = method
con.connectTimeout = 60000
con.readTimeout = 60000
if(method.equals("POST"))
con.doOutput=true
if (method == "POST") {
con.doOutput = true
}
Log.d("Petition", url.toString())
return con
}
fun getKeys():HostModel{
var con=this._newCon("oauth-clients/local","GET")
var keys = HostModel("","")
fun getKeys(): HostModel {
val con = this.newCon("oauth-clients/local", "GET")
val keys = HostModel("", "")
try {
if (con.responseCode == 200) {
var response = InputStreamReader(con.inputStream)
var data = JsonReader(response)
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
data.beginObject()
while (data.hasNext()) {
val key = data.nextName()
when (key.toString()) {
"client_id"->{
"client_id" -> {
keys.client_id = data.nextString()
}
"client_secret"->{
"client_secret" -> {
keys.client_secret = data.nextString()
}
else->{
else -> {
data.skipValue()
}
}
}
data.close()
}
Log.d("Key",keys.client_id)
return keys
} catch(err:Exception){
Log.d("Error",err.message)
return keys
} catch (err: Exception) {
err.printStackTrace()
}
con.disconnect()
return keys
}
}
}

View File

@ -0,0 +1,136 @@
package org.libre.agosto.p2play.ajax
import android.util.JsonReader
import android.util.Log
import org.libre.agosto.p2play.models.CommentaryModel
import java.io.InputStreamReader
class Comments : Client() {
private fun parseCommentaries(data: JsonReader): ArrayList<CommentaryModel> {
val commentaries = arrayListOf<CommentaryModel>()
data.beginObject()
while (data.hasNext()) {
when (data.nextName()) {
"data" -> {
data.beginArray()
while (data.hasNext()) {
val comment = CommentaryModel()
comment.parseCommentary(data)
commentaries.add(comment)
}
data.endArray()
}
else -> data.skipValue()
}
}
data.endObject()
return commentaries
}
fun getCommentaries(videoId: Int): ArrayList<CommentaryModel> {
var commentaries = arrayListOf<CommentaryModel>()
val con = this.newCon("videos/$videoId/comment-threads", "GET")
try {
if (con.responseCode == 200) {
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
commentaries = parseCommentaries(data)
data.close()
}
} catch (err: Exception) {
err.printStackTrace()
}
con.disconnect()
return commentaries
}
fun makeCommentary(token: String, videoId: Int, text: String): Boolean {
val con = this.newCon("videos/$videoId/comment-threads", "POST", token)
val params = "text=$text"
con.outputStream.write(params.toByteArray())
var response: Boolean
try {
if (con.responseCode == 200) {
con.disconnect()
response = true
} else {
Log.d("Status", con.responseMessage)
response = false
}
} catch (err: Exception) {
err.printStackTrace()
response = false
}
con.disconnect()
return response
}
fun getCommentariesThread(videoId: Int, threadId: Int): ArrayList<CommentaryModel> {
var commentaries = arrayListOf<CommentaryModel>()
val con = this.newCon("videos/$videoId/comment-threads/$threadId", "GET")
try {
if (con.responseCode == 200) {
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
data.beginObject()
while (data.hasNext()) {
when (data.nextName()) {
"children" -> {
data.beginArray()
while (data.hasNext()) {
data.beginObject()
while (data.hasNext()) {
when (data.nextName()) {
"comment" -> {
val comment = CommentaryModel()
comment.parseCommentary(data)
commentaries.add(comment)
}
else -> data.skipValue()
}
}
data.endObject()
}
data.endArray()
}
else -> data.skipValue()
}
}
data.endObject()
data.close()
}
} catch (err: Exception) {
err.printStackTrace()
}
con.disconnect()
return commentaries
}
fun replyThread(token: String, videoId: Int, threadId: Int, text: String): Boolean {
val con = this.newCon("videos/$videoId/comments/$threadId", "POST", token)
val params = "text=$text"
con.outputStream.write(params.toByteArray())
val response: Boolean = try {
if (con.responseCode == 200) {
con.disconnect()
true
} else {
Log.d("Status", con.responseMessage)
false
}
} catch (err: Exception) {
err.printStackTrace()
false
}
con.disconnect()
return response
}
}

View File

@ -1,88 +1,27 @@
package org.libre.agosto.p2play.ajax
import android.util.JsonReader
import android.util.JsonToken
import android.util.Log
import org.libre.agosto.p2play.ManagerSingleton
import org.libre.agosto.p2play.models.VideoModel
import java.io.InputStreamReader
class Videos: Client() {
class Videos : Client() {
fun parseVideos(data: JsonReader): ArrayList<VideoModel>{
var videos = arrayListOf<VideoModel>()
private fun parseVideos(data: JsonReader): ArrayList<VideoModel> {
val videos = arrayListOf<VideoModel>()
data.beginObject()
while (data.hasNext()){
when(data.nextName()){
"data"->{
while (data.hasNext()) {
when (data.nextName()) {
"data" -> {
data.beginArray()
while (data.hasNext()) {
val video = VideoModel()
data.beginObject()
while (data.hasNext()){
val key = data.nextName()
when (key.toString()) {
"id"-> video.id = data.nextInt()
"name"->{
video.name= data.nextString()
}
"description"->{
if(data.peek() == JsonToken.STRING)
video.description = data.nextString()
else
data.skipValue()
}
"duration"->{
video.duration = data.nextInt()
}
"thumbnailPath"->{
video.thumbUrl = data.nextString()
}
"embedPath"->{
video.embedUrl = data.nextString()
}
"views"->{
video.views = data.nextInt()
}
"channel"->{
data.beginObject()
while (data.hasNext()){
val acKey = data.nextName()
when(acKey.toString()){
"displayName"-> video.username=data.nextString()
"avatar"-> {
if(data.peek() == JsonToken.BEGIN_OBJECT){
data.beginObject()
while (data.hasNext()){
val avKey = data.nextName()
when(avKey){
"path"-> video.userImageUrl = data.nextString()
else-> data.skipValue()
}
}
data.endObject()
}
else
data.skipValue()
}
"uuid" -> video.userUuid = data.nextString()
"host" -> video.userHost = data.nextString()
else-> data.skipValue()
}
}
data.endObject()
}
else->{
data.skipValue()
}
}
}
data.endObject()
video.parseVideo(data)
videos.add(video)
}
data.endArray()
}
else-> data.skipValue()
else -> data.skipValue()
}
}
data.endObject()
@ -90,69 +29,193 @@ class Videos: Client() {
return videos
}
private fun getVideos(start:Int, count:Int, sort:String = "-publishedAt", filter:String = ""):ArrayList<VideoModel>{
var params = "start=$start&count=$count&sort=$sort"
if(filter != "")
params+="&filter=$filter"
var con=this._newCon("videos?$params","GET")
private fun getVideos(start: Int, sort: String = "-publishedAt", isLocal: Boolean = false): ArrayList<VideoModel> {
val nsfw = ManagerSingleton.nfsw
val count = ManagerSingleton.videosCount
var params = "start=$start&count=$count&sort=$sort&nsfw=$nsfw&isLocal=$isLocal"
val con = this.newCon("videos?$params", "GET")
var videos = arrayListOf<VideoModel>()
try {
if (con.responseCode == 200) {
var response = InputStreamReader(con.inputStream)
var data = JsonReader(response)
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
videos = parseVideos(data)
data.close()
}
} catch(err:Exception){
err?.printStackTrace()
Log.d("TypeErr",err?.message ,err.cause)
Log.d("Error","fallo la coneccion")
} catch (err: Exception) {
err.printStackTrace()
}
con.disconnect()
return videos
}
fun getLastVideos(start:Int = 0, count:Int = 30): ArrayList<VideoModel>{
return this.getVideos(start, count)
fun getLastVideos(start: Int = 0): ArrayList<VideoModel> {
return this.getVideos(start)
}
fun getPopularVideos(start:Int = 0, count:Int = 30): ArrayList<VideoModel>{
return this.getVideos(start, count,"-views")
fun getPopularVideos(start: Int = 0): ArrayList<VideoModel> {
return this.getVideos(start, "-views")
}
fun getLocalVideos(start:Int = 0, count:Int = 30): ArrayList<VideoModel>{
return this.getVideos(start, count,"-publishedAt", "local")
fun getTrendingVideos(start: Int = 0): ArrayList<VideoModel> {
return this.getVideos(start, "-trending")
}
fun myVideos(token: String): ArrayList<VideoModel>{
var con=this._newCon("users/me/videos","GET", token)
fun getLocalVideos(start: Int = 0): ArrayList<VideoModel> {
return this.getVideos(start, "-publishedAt", true)
}
fun myVideos(token: String, start: Int = 0): ArrayList<VideoModel> {
val count = ManagerSingleton.videosCount
val params = "start=$start&count=$count"
val con = this.newCon("users/me/videos?$params", "GET", token)
var videos = arrayListOf<VideoModel>()
try {
if (con.responseCode == 200) {
var response = InputStreamReader(con.inputStream)
var data = JsonReader(response)
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
videos = parseVideos(data)
data.close()
}
} catch(err:Exception){
err?.printStackTrace()
Log.d("TypeErr",err?.message ,err.cause)
Log.d("Error","fallo la coneccion")
} catch (err: Exception) {
err.printStackTrace()
}
con.disconnect()
return videos
}
fun videoSubscriptions(token: String): ArrayList<VideoModel>{
var con=this._newCon("users/me/subscriptions/videos","GET", token)
fun videoSubscriptions(token: String, start: Int = 0): ArrayList<VideoModel> {
val count = ManagerSingleton.videosCount
val params = "start=$start&count=$count"
val con = this.newCon("users/me/subscriptions/videos?$params", "GET", token)
var videos = arrayListOf<VideoModel>()
try {
if (con.responseCode == 200) {
var response = InputStreamReader(con.inputStream)
var data = JsonReader(response)
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
videos = parseVideos(data)
data.close()
} else {
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
print(data)
}
} catch(err:Exception){
err?.printStackTrace()
Log.d("TypeErr",err?.message ,err.cause)
Log.d("Error","fallo la coneccion")
} catch (err: Exception) {
err.printStackTrace()
}
con.disconnect()
return videos
}
}
fun videoHistory(token: String, start: Int = 0): ArrayList<VideoModel> {
val count = ManagerSingleton.videosCount
val params = "start=$start&count=$count"
val con = this.newCon("users/me/history/videos?$params", "GET", token)
var videos = arrayListOf<VideoModel>()
try {
if (con.responseCode == 200) {
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
videos = parseVideos(data)
data.close()
}
} catch (err: Exception) {
err.printStackTrace()
}
con.disconnect()
return videos
}
fun search(text: String, start: Int = 0): ArrayList<VideoModel> {
val count = ManagerSingleton.videosCount
val nsfw = ManagerSingleton.nfsw
val params = "search=$text&start=$start&count=$count&nsfw=$nsfw"
val con = this.newCon("search/videos?$params", "GET")
var videos = arrayListOf<VideoModel>()
try {
if (con.responseCode == 200) {
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
videos = parseVideos(data)
data.close()
}
} catch (err: Exception) {
err.printStackTrace()
}
con.disconnect()
return videos
}
fun fullDescription(videoId: Int): String {
val con = this.newCon("videos/$videoId/description", "GET")
var description = ""
try {
if (con.responseCode == 200) {
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
data.beginObject()
while (data.hasNext()) {
val name = data.nextName()
when (name) {
"description" -> description = data.nextString()
else -> data.skipValue()
}
}
data.endObject()
data.close()
}
} catch (err: Exception) {
err.printStackTrace()
description = "Error!"
}
con.disconnect()
return description
}
fun channelVideos(account: String, start: Int): ArrayList<VideoModel> {
val count = ManagerSingleton.videosCount
val params = "start=$start&count=$count"
val con = this.newCon("video-channels/$account/videos?$params", "GET")
var videos = arrayListOf<VideoModel>()
try {
if (con.responseCode == 200) {
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
videos = parseVideos(data)
data.close()
}
} catch (err: Exception) {
err.printStackTrace()
}
con.disconnect()
return videos
}
fun getMostLikedVideos(start: Int = 0): ArrayList<VideoModel> {
return this.getVideos(start, "-likes")
}
fun getVideo(uuid: String): VideoModel {
val con = this.newCon("videos/$uuid", "GET")
val video = VideoModel()
try {
if (con.responseCode == 200) {
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
video.parseVideo(data)
data.close()
}
} catch (err: Exception) {
err.printStackTrace()
}
con.disconnect()
return video
}
}

View File

@ -0,0 +1,132 @@
package org.libre.agosto.p2play.dialogs
import android.app.Dialog
import android.os.AsyncTask
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.Window
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.comment_component.commentaryLayout
import kotlinx.android.synthetic.main.comment_component.commentaryText
import kotlinx.android.synthetic.main.comment_component.userImgCom
import kotlinx.android.synthetic.main.comment_component.view.commentaryBtn
import kotlinx.android.synthetic.main.comment_component.view.commentaryLayout
import kotlinx.android.synthetic.main.comment_component.view.commentaryText
import kotlinx.android.synthetic.main.comment_component.view.userImgCom
import kotlinx.android.synthetic.main.dialog_thread.view.materialToolbar
import kotlinx.android.synthetic.main.view_commentary.view.replyBtn
import kotlinx.android.synthetic.main.view_commentary.view.userCommentImg
import kotlinx.android.synthetic.main.view_commentary.view.userCommentary
import kotlinx.android.synthetic.main.view_commentary.view.userTxt
import org.libre.agosto.p2play.ManagerSingleton
import org.libre.agosto.p2play.R
import org.libre.agosto.p2play.adapters.CommentariesAdapter
import org.libre.agosto.p2play.ajax.Comments
import org.libre.agosto.p2play.models.CommentaryModel
class ThreadDialog : DialogFragment() {
private lateinit var comment: CommentaryModel
lateinit var fragmentManager2: FragmentManager
private val client: Comments = Comments()
// The system calls this to get the DialogFragment's layout, regardless of
// whether it's being displayed as a dialog or an embedded fragment.
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
// Inflate the layout to use as a dialog or embedded fragment.
val view = inflater.inflate(R.layout.dialog_thread, container, false)
comment = arguments?.getSerializable("comment") as CommentaryModel
view.userTxt.text = comment.username
view.userCommentary.text = comment.commentary
Picasso.get().load("https://${ManagerSingleton.url}${comment.userImageUrl}").into(view.userCommentImg)
view.replyBtn.visibility = View.GONE
if (ManagerSingleton.user.status == 1) {
view.commentaryText.setText("${comment.username}@${comment.userHost} ")
if (ManagerSingleton.user.avatar != "") {
Picasso.get().load("https://${ManagerSingleton.url}${ManagerSingleton.user.avatar}").into(view.userImgCom)
}
view.commentaryText.requestFocus()
view.commentaryBtn.setOnClickListener { this.replyThread() }
} else {
view.commentaryLayout.visibility = View.GONE
}
view.materialToolbar.setTitle("Thread")
view.materialToolbar.setNavigationIcon(R.drawable.baseline_arrow_back_24)
view.materialToolbar.setNavigationOnClickListener {
dismiss()
this.fragmentManager2.popBackStack()
}
this.getComments()
return view
}
// The system calls this only when creating the layout in a dialog.
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState)
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
return dialog
}
private fun getComments() {
AsyncTask.execute {
val data =
this.client.getCommentariesThread(this.comment.videoId, this.comment.id)
activity?.runOnUiThread {
this.setDataComments(data)
}
}
}
private fun setDataComments(data: ArrayList<CommentaryModel>) {
// Set data for RecyclerView
val viewAdapter = CommentariesAdapter(data).setFragmentManager(this.fragmentManager2)
view?.findViewById<RecyclerView>(R.id.listCommentaries)?.let {
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
it.setHasFixedSize(true)
// use a linear layout manager
it.layoutManager = LinearLayoutManager(activity)
// specify an viewAdapter (see also next example)
it.adapter = viewAdapter
}
}
private fun replyThread() {
val commentary = view?.commentaryText?.text.toString()
if (commentary == "") {
ManagerSingleton.toast(getString(R.string.emptyCommentaryMsg), requireActivity())
return
}
AsyncTask.execute {
val res = this.client.replyThread(ManagerSingleton.token.token, this.comment.videoId, this.comment.id, commentary)
activity?.runOnUiThread {
if (res) {
ManagerSingleton.toast(getString(R.string.makedCommentaryMsg), requireActivity())
commentaryText.text?.clear()
this.getComments()
} else {
ManagerSingleton.toast(getString(R.string.errorCommentaryMsg), requireActivity())
}
}
}
}
}

View File

@ -0,0 +1,24 @@
package org.libre.agosto.p2play.helpers
import android.content.Context
import android.content.res.Configuration
import android.content.res.Resources
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView.LayoutManager
fun getViewManager (context: Context, resources: Resources): LayoutManager {
val screenSize = resources.configuration.screenLayout and Configuration.SCREENLAYOUT_SIZE_MASK
val manager = if (screenSize > Configuration.SCREENLAYOUT_SIZE_LARGE) {
val orientation = resources.configuration.orientation
val gridItems = when (orientation) {
Configuration.ORIENTATION_LANDSCAPE -> 4
else -> 3
}
GridLayoutManager(context, gridItems)
} else {
LinearLayoutManager(context)
}
return manager
}

View File

@ -0,0 +1,20 @@
package org.libre.agosto.p2play.helpers
fun mapSeconds(inputSeconds: Int): String {
val seconds = (inputSeconds % 60)
var minutes = inputSeconds / 60
var hours = 0
if (minutes > 60) {
hours = minutes / 60
minutes %= 60
}
var result = minutes.toString().padStart(2, '0') + ":" + seconds.toString().padStart(2, '0')
if (hours > 0) {
result = hours.toString().padStart(2, '0') + ":" + result
}
return result
}

View File

@ -0,0 +1,13 @@
package org.libre.agosto.p2play.helpers
import android.view.View
import android.view.Window
import android.view.WindowManager
fun setFullscreen(window: Window) {
val attrs = window.attributes
attrs.flags = attrs.flags or WindowManager.LayoutParams.FLAG_FULLSCREEN
attrs.flags = attrs.flags or WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
window.attributes = attrs
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
}

View File

@ -0,0 +1,65 @@
package org.libre.agosto.p2play.models
import android.util.JsonReader
import android.util.JsonToken
class ChannelModel(
var id: Int = 0,
var url: String = "",
var nameChannel: String = "",
var followers: Int = 0,
var host: String = "",
var name: String = "",
var description: String = "",
var support: String = "",
var channelImg: String = "",
) {
fun getAccount(): String {
return "$nameChannel@$host"
}
fun parseChannel(data: JsonReader) {
data.beginObject()
while (data.hasNext()) {
when (data.nextName()) {
"id" -> this.id = data.nextInt()
"url" -> this.url = data.nextString()
"name" -> this.nameChannel = data.nextString()
"host" -> this.host = data.nextString()
"followersCount" -> this.followers = data.nextInt()
"displayName" -> this.name = data.nextString()
"description" -> {
if (data.peek() == JsonToken.STRING) {
this.description = data.nextString()
} else {
data.skipValue()
}
}
"support" -> {
if (data.peek() == JsonToken.STRING) {
this.support = data.nextString()
} else {
data.skipValue()
}
}
"avatar" -> {
if (data.peek() == JsonToken.BEGIN_OBJECT) {
data.beginObject()
while (data.hasNext()) {
when (data.nextName()) {
"path" -> this.channelImg = data.nextString()
else -> data.skipValue()
}
}
data.endObject()
} else {
data.skipValue()
}
}
else -> data.skipValue()
}
}
data.endObject()
}
}

View File

@ -0,0 +1,67 @@
package org.libre.agosto.p2play.models
import android.util.JsonReader
import android.util.JsonToken
import java.io.Serializable
class CommentaryModel(
var id: Int = 0,
var threadId: Int = 0,
var userUuid: String = "",
var username: String = "",
var userImageUrl: String = "",
var commentary: String = "",
var userHost: String = "",
var replies: Int = 0,
var nameChannel: String = "",
var videoId: Int = 0,
) : Serializable {
fun parseCommentary(data: JsonReader) {
data.beginObject()
while (data.hasNext()) {
val key = data.nextName()
when (key.toString()) {
"id" -> this.id = data.nextInt()
"threadId" -> this.threadId = data.nextInt()
"text" -> this.commentary = data.nextString()
"totalReplies" -> this.replies = data.nextInt()
"videoId" -> this.videoId = data.nextInt()
"account" -> {
data.beginObject()
while (data.hasNext()) {
val acKey = data.nextName()
when (acKey.toString()) {
"displayName" -> this.username = data.nextString()
"avatar" -> {
if (data.peek() == JsonToken.BEGIN_OBJECT) {
data.beginObject()
while (data.hasNext()) {
val avKey = data.nextName()
when (avKey) {
"path" -> this.userImageUrl = data.nextString()
else -> data.skipValue()
}
}
data.endObject()
} else {
data.skipValue()
}
}
"uuid" -> this.userUuid = data.nextString()
"host" -> this.userHost = data.nextString()
"name" -> this.nameChannel = data.nextString()
else -> data.skipValue()
}
}
data.endObject()
}
else -> data.skipValue()
}
}
data.endObject()
}
fun getAccount(): String {
return "$nameChannel@$userHost"
}
}

View File

@ -1,3 +1,3 @@
package org.libre.agosto.p2play.models
class HostModel (var client_id:String, var client_secret:String)
class HostModel(var client_id: String, var client_secret: String)

View File

@ -0,0 +1,26 @@
package org.libre.agosto.p2play.models
import android.util.JsonReader
class StreamingModel(
var playlistUrl: String = "",
var segmentsSha256Url: String = "",
// TODO: Download Files
) {
fun parse(data: JsonReader) {
data.beginObject()
while (data.hasNext()) {
val key = data.nextName()
when (key.toString()) {
"playlistUrl" -> {
this.playlistUrl = data.nextString()
}
"segmentsSha256Url" -> {
this.segmentsSha256Url = data.nextString()
}
else -> data.skipValue()
}
}
data.endObject()
}
}

View File

@ -1,7 +1,7 @@
package org.libre.agosto.p2play.models
class TokenModel (
var token: String = "",
var refresh_token: String = "",
var status: Int = -1
)
class TokenModel(
var token: String = "",
var refresh_token: String = "",
var status: Int = -1,
)

View File

@ -1,12 +1,12 @@
package org.libre.agosto.p2play.models
class UserModel (
var id: Int = 0,
var uuid: Int = 0,
var username: String = "",
var email: String = "",
var nsfw: Boolean = true,
var followers: Int = 0,
var avatar: String = "",
var status: Int = -1
)
class UserModel(
var id: Int = 0,
var uuid: Int = 0,
var username: String = "",
var email: String = "",
var nsfw: Boolean = true,
var followers: Int = 0,
var avatar: String = "",
var status: Int = -1,
)

View File

@ -1,17 +1,132 @@
package org.libre.agosto.p2play.models
import android.util.JsonReader
import android.util.JsonToken
import java.io.Serializable
class VideoModel(
var id: Int = 0,
var name: String = "",
var description: String = "",
var thumbUrl: String = "",
var userImageUrl: String = "",
var embedUrl: String = "",
var duration: Number = 0,
var username: String = "",
var views: Number = 0,
var userUuid: String = "",
var userHost: String = ""
):Serializable
var id: Int = 0,
var uuid: String = "",
var name: String = "",
var description: String = "",
var thumbUrl: String = "",
var userImageUrl: String = "",
var embedUrl: String = "",
var duration: Number = 0,
var username: String = "",
var views: Number = 0,
var userUuid: String = "",
var userHost: String = "",
var nameChannel: String = "",
var isLive: Boolean = false,
var streamingData: StreamingModel? = null,
) : Serializable {
fun getChannel(): String {
return "$nameChannel@$userHost"
}
fun getVideoUrl(): String {
return "https://$userHost/videos/watch/$uuid"
}
fun parseVideo(data: JsonReader) {
data.beginObject()
while (data.hasNext()) {
val key = data.nextName()
when (key.toString()) {
"id" -> this.id = data.nextInt()
"uuid" -> this.uuid = data.nextString()
"name" -> {
this.name = data.nextString()
}
"description" -> {
if (data.peek() == JsonToken.STRING) {
this.description = data.nextString()
} else {
data.skipValue()
}
}
"duration" -> {
this.duration = data.nextInt()
}
"thumbnailPath" -> {
this.thumbUrl = data.nextString()
}
"embedPath" -> {
this.embedUrl = data.nextString()
}
"views" -> {
this.views = data.nextInt()
}
"isLive" -> {
this.isLive = data.nextBoolean()
}
"streamingPlaylists" -> {
data.beginArray()
if (data.hasNext()) {
val streamingData = StreamingModel()
streamingData.parse(data)
this.streamingData = streamingData
}
data.endArray()
}
"files" -> {
data.beginArray()
if (streamingData === null) {
if (data.hasNext()) {
data.beginObject()
while (data.hasNext()) {
val key2 = data.nextName()
when (key2.toString()) {
"fileUrl" -> {
streamingData = StreamingModel()
streamingData!!.playlistUrl = data.nextString()
}
else -> data.skipValue()
}
}
data.endObject()
}
while (data.hasNext()) {
data.skipValue()
}
}
data.endArray()
}
"channel" -> {
data.beginObject()
while (data.hasNext()) {
val acKey = data.nextName()
when (acKey.toString()) {
"displayName" -> this.username = data.nextString()
"avatar" -> {
if (data.peek() == JsonToken.BEGIN_OBJECT) {
data.beginObject()
while (data.hasNext()) {
val avKey = data.nextName()
when (avKey) {
"path" -> this.userImageUrl = data.nextString()
else -> data.skipValue()
}
}
data.endObject()
} else {
data.skipValue()
}
}
"uuid" -> this.userUuid = data.nextString()
"host" -> this.userHost = data.nextString()
"name" -> this.nameChannel = data.nextString()
else -> data.skipValue()
}
}
data.endObject()
}
else -> {
data.skipValue()
}
}
}
data.endObject()
}
}

View File

@ -0,0 +1,47 @@
package org.libre.agosto.p2play.services
import android.app.PendingIntent
import android.content.Intent
import androidx.media3.session.MediaSession
import androidx.media3.session.MediaSessionService
import org.libre.agosto.p2play.ReproductorActivity
import org.libre.agosto.p2play.singletons.PlaybackSingleton
class PlaybackService : MediaSessionService() {
private var mediaSession: MediaSession? = null
// Create your Player and MediaSession in the onCreate lifecycle event
override fun onCreate() {
super.onCreate()
val player = PlaybackSingleton.player!!
mediaSession = MediaSession.Builder(this, player)
.build()
val contentIntent = Intent(this, ReproductorActivity::class.java)
contentIntent.putExtra("resume", true)
val pendingIntent = PendingIntent.getActivity(
this,
0,
contentIntent,
PendingIntent.FLAG_MUTABLE,
)
mediaSession!!.setSessionActivity(pendingIntent)
}
// Remember to release the player and media session in onDestroy
override fun onDestroy() {
mediaSession?.run {
release()
mediaSession = null
}
super.onDestroy()
}
override fun onTaskRemoved(rootIntent: Intent?) {
this.mediaSession!!.player.stop()
super.onTaskRemoved(rootIntent)
}
override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? {
return mediaSession
}
}

View File

@ -0,0 +1,51 @@
package org.libre.agosto.p2play.singletons
import android.content.ComponentName
import android.content.Context
import androidx.media3.common.MediaItem
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.session.MediaController
import androidx.media3.session.SessionToken
import com.google.common.util.concurrent.MoreExecutors
import org.libre.agosto.p2play.models.VideoModel
import org.libre.agosto.p2play.services.PlaybackService
object PlaybackSingleton {
var player: ExoPlayer? = null
var video: VideoModel? = null
private var withMediaSession = false
fun setData(mediaItem: MediaItem, video: VideoModel): ExoPlayer? {
player?.let {
if (it.isPlaying) {
it.pause()
}
it.setMediaItem(mediaItem)
it.prepare()
this.video = video
return it
}
return null
}
fun release() {
player?.release()
}
fun runMediaSession(context: Context) {
if (!this.withMediaSession) {
val sessionToken = SessionToken(context, ComponentName(context, PlaybackService::class.java))
val controllerFuture = MediaController.Builder(context, sessionToken).buildAsync()
controllerFuture.addListener(
{
val med = controllerFuture.get()
},
MoreExecutors.directExecutor(),
)
this.withMediaSession = true
}
}
}

View File

@ -1,34 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeColor="#00000000"
android:strokeWidth="1">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeColor="#00000000"
android:strokeWidth="1" />
</vector>

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
</vector>

View File

@ -0,0 +1,25 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12.8716,3.5097L12,1.9603L11.1284,3.5097L2.1284,19.5097L1.2902,21L3,21L21,21L22.7098,21L21.8716,19.5097L12.8716,3.5097Z"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#585858"
android:fillType="evenOdd"/>
<path
android:pathData="M12,17.75C12.6904,17.75 13.25,17.1904 13.25,16.5C13.25,15.8096 12.6904,15.25 12,15.25C11.3096,15.25 10.75,15.8096 10.75,16.5C10.75,17.1904 11.3096,17.75 12,17.75Z"
android:strokeWidth="1"
android:fillColor="#585858"
android:strokeColor="#585858"
android:fillType="evenOdd" />
<path
android:pathData="M12,9L12,9A1,1 0,0 1,13 10L13,13A1,1 0,0 1,12 14L12,14A1,1 0,0 1,11 13L11,10A1,1 0,0 1,12 9z"
android:strokeWidth="1"
android:fillColor="#585858"
android:strokeColor="#585858"
android:fillType="evenOdd" />
</vector>

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#88ffffff" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#fff" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M18,13c0,3.31 -2.69,6 -6,6s-6,-2.69 -6,-6s2.69,-6 6,-6v4l5,-5l-5,-5v4c-4.42,0 -8,3.58 -8,8c0,4.42 3.58,8 8,8s8,-3.58 8,-8H18z"/>
<path android:fillColor="@android:color/white" android:pathData="M10.86,15.94l0,-4.27l-0.09,0l-1.77,0.63l0,0.69l1.01,-0.31l0,3.26z"/>
<path android:fillColor="@android:color/white" android:pathData="M12.25,13.44v0.74c0,1.9 1.31,1.82 1.44,1.82c0.14,0 1.44,0.09 1.44,-1.82v-0.74c0,-1.9 -1.31,-1.82 -1.44,-1.82C13.55,11.62 12.25,11.53 12.25,13.44zM14.29,13.32v0.97c0,0.77 -0.21,1.03 -0.59,1.03c-0.38,0 -0.6,-0.26 -0.6,-1.03v-0.97c0,-0.75 0.22,-1.01 0.59,-1.01C14.07,12.3 14.29,12.57 14.29,13.32z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#fff" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M7,14L5,14v5h5v-2L7,17v-3zM5,10h2L7,7h3L10,5L5,5v5zM17,17h-3v2h5v-5h-2v3zM14,5v2h3v3h2L19,5h-5z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M13,3c-4.97,0 -9,4.03 -9,9L1,12l3.89,3.89 0.07,0.14L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.28,2.54 0.72,-1.21 -3.5,-2.08L13.5,8L12,8z"/>
</vector>

View File

@ -1,170 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillColor="#26A69A"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M21,6h-7.59l3.29,-3.29L16,2l-4,4 -4,-4 -0.71,0.71L10.59,6L3,6c-1.1,0 -2,0.89 -2,2v12c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,8c0,-1.11 -0.9,-2 -2,-2zM21,20L3,20L3,8h18v12zM9,10v8l7,-4z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#fff" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#fff" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M8,5v14l11,-7z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#fff" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M11.99,5V1l-5,5l5,5V7c3.31,0 6,2.69 6,6s-2.69,6 -6,6s-6,-2.69 -6,-6h-2c0,4.42 3.58,8 8,8s8,-3.58 8,-8S16.41,5 11.99,5z"/>
<path android:fillColor="@android:color/white" android:pathData="M10.89,16h-0.85v-3.26l-1.01,0.31v-0.69l1.77,-0.63h0.09V16z"/>
<path android:fillColor="@android:color/white" android:pathData="M15.17,14.24c0,0.32 -0.03,0.6 -0.1,0.82s-0.17,0.42 -0.29,0.57s-0.28,0.26 -0.45,0.33s-0.37,0.1 -0.59,0.1s-0.41,-0.03 -0.59,-0.1s-0.33,-0.18 -0.46,-0.33s-0.23,-0.34 -0.3,-0.57s-0.11,-0.5 -0.11,-0.82V13.5c0,-0.32 0.03,-0.6 0.1,-0.82s0.17,-0.42 0.29,-0.57s0.28,-0.26 0.45,-0.33s0.37,-0.1 0.59,-0.1s0.41,0.03 0.59,0.1c0.18,0.07 0.33,0.18 0.46,0.33s0.23,0.34 0.3,0.57s0.11,0.5 0.11,0.82V14.24zM14.32,13.38c0,-0.19 -0.01,-0.35 -0.04,-0.48s-0.07,-0.23 -0.12,-0.31s-0.11,-0.14 -0.19,-0.17s-0.16,-0.05 -0.25,-0.05s-0.18,0.02 -0.25,0.05s-0.14,0.09 -0.19,0.17s-0.09,0.18 -0.12,0.31s-0.04,0.29 -0.04,0.48v0.97c0,0.19 0.01,0.35 0.04,0.48s0.07,0.24 0.12,0.32s0.11,0.14 0.19,0.17s0.16,0.05 0.25,0.05s0.18,-0.02 0.25,-0.05s0.14,-0.09 0.19,-0.17s0.09,-0.19 0.11,-0.32s0.04,-0.29 0.04,-0.48V13.38z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
</vector>

View File

@ -0,0 +1,29 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M20,15L20,18.0026C20,19.1057 19.1074,20 18.0049,20L5.9951,20C4.8932,20 4,19.1074 4,18.0049L4,5.9951C4,4.8932 4.8959,4 5.9974,4L9,4"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#585858"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
<path
android:pathData="M13,4l7.0208,0l0,7.0191"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#585858"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
<path
android:pathData="M19,5L12,12"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#585858"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M1,21h4L5,9L1,9v12zM23,10c0,-1.1 -0.9,-2 -2,-2h-6.31l0.95,-4.57 0.03,-0.32c0,-0.41 -0.17,-0.79 -0.44,-1.06L14.17,1 7.59,7.59C7.22,7.95 7,8.45 7,9v10c0,1.1 0.9,2 2,2h9c0.83,0 1.54,-0.5 1.84,-1.22l3.02,-7.05c0.09,-0.23 0.14,-0.47 0.14,-0.73v-1.91l-0.01,-0.01L23,10z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M16,6l2.29,2.29 -4.88,4.88 -4,-4L2,16.59 3.41,18l6,-6 4,4 6.3,-6.29L22,12V6z"/>
</vector>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="5dp" />
<!-- This is the border color -->
<!--- This is the background color -->
<solid android:color="@color/colorDislike" />
</shape>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="5dp" />
<!-- This is the border color -->
<!--- This is the background color -->
<solid android:color="?attr/colorSecondary" />
</shape>

View File

@ -0,0 +1,361 @@
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ReproductorActivity">
<RelativeLayout
android:id="@+id/fullScreen"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
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" />
<RelativeLayout
android:id="@+id/fullScreenExo"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
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.media3.ui.PlayerView
android:id="@+id/fullscreenPlayer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000"
app:use_controller="true"
app:show_buffering="always"
app:controller_layout_id="@layout/custom_player_controls"
app:player_layout_id="@layout/exo_player_view"/>
</RelativeLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/nonFullScreen"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<WebView
android:id="@+id/videoView"
android:layout_width="match_parent"
android:layout_height="205dp"
android:layout_weight="1"
android:visibility="gone" />
<androidx.media3.ui.PlayerView
android:id="@+id/exoPlayer"
android:layout_width="match_parent"
android:layout_height="500dp"
app:auto_show="true"
app:controller_layout_id="@layout/custom_player_controls"
app:repeat_toggle_modes="none"
app:show_buffering="always"
app:surface_type="surface_view"
app:use_controller="true" />
<TextView
android:id="@+id/tittleVideoTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="5dp"
android:textAppearance="@android:style/TextAppearance.Material.Display1"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/viewsTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:textSize="12sp" />
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/actionsLayout"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="top"
android:orientation="horizontal"
android:visibility="gone">
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/likeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:visibility="visible">
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:adjustViewBounds="false"
android:contentDescription="@string/likeBtn"
android:cropToPadding="false"
android:scaleType="center"
android:visibility="visible"
app:srcCompat="@drawable/ic_like" />
<TextView
android:id="@+id/textViewLike"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/likeBtn"
android:textAlignment="center" />
</androidx.appcompat.widget.LinearLayoutCompat>
<LinearLayout
android:id="@+id/dislikeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:visibility="visible">
<ImageView
android:id="@+id/imageView2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:adjustViewBounds="false"
android:contentDescription="@string/dislikeBtn"
android:cropToPadding="false"
android:visibility="visible"
app:srcCompat="@drawable/ic_dislike" />
<TextView
android:id="@+id/textViewDislike"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/dislikeBtn"
android:textAlignment="center" />
</LinearLayout>
<LinearLayout
android:id="@+id/reportLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:visibility="visible">
<ImageView
android:id="@+id/imageViewAlert"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:adjustViewBounds="false"
android:contentDescription="@string/dislikeBtn"
android:cropToPadding="false"
android:visibility="visible"
app:srcCompat="@drawable/ic_alert" />
<TextView
android:id="@+id/textViewAlert"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/reportBtn"
android:textAlignment="center" />
</LinearLayout>
<LinearLayout
android:id="@+id/shareLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:visibility="visible">
<ImageView
android:id="@+id/imageViewShare"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:adjustViewBounds="false"
android:contentDescription="@string/shareBtn"
android:cropToPadding="false"
android:visibility="visible"
app:srcCompat="@drawable/ic_share" />
<TextView
android:id="@+id/textViewShare"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/shareBtn"
android:textAlignment="center" />
</LinearLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center|center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/userImg"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="0dp"
android:layout_weight="1"
android:adjustViewBounds="true"
android:cropToPadding="false"
android:padding="5dp"
android:scaleType="fitCenter"
app:srcCompat="@drawable/default_avatar" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:orientation="vertical">
<TextView
android:id="@+id/userTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxWidth="300dp"
android:textAppearance="@android:style/TextAppearance.Material.Large"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/hostTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="10sp"
android:textStyle="italic" />
</LinearLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/subscribeBtn"
style="@style/Widget.MaterialComponents.Button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/subscribeBtn"
android:textSize="12sp"
android:visibility="invisible" />
</LinearLayout>
<TextView
android:id="@+id/descriptionTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLength="1000"
android:maxLines="100"
android:paddingLeft="5dp"
android:text="@string/descriptionTxt"
android:textStyle="bold" />
<TextView
android:id="@+id/descriptionVideoTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:layout_marginBottom="2dp"
android:autoLink="web"
android:linksClickable="true"
android:maxLength="10000"
android:maxLines="100"
android:paddingLeft="10dp"
android:paddingRight="10dp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/showMoreBtn"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/showMore"
android:visibility="gone" />
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="20dp" />
</LinearLayout>
<androidx.constraintlayout.widget.Barrier
android:layout_width="match_parent"
android:layout_height="match_parent"
app:barrierDirection="left" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_weight="1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<include layout="@layout/comment_component" />
<TextView
android:id="@+id/commentariesTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:text="@string/commentariesTxt"
android:textStyle="bold" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/listCommentaries"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,110 @@
<?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/exo_controls"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#44000000">
<ImageView
android:id="@+id/exo_settings"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_weight="0"
android:alpha="0.5"
android:src="@drawable/ic_baseline_settings_24"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/exo_rew"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@drawable/ic_replay_10_24" />
<ImageView
android:id="@+id/exo_play_pause"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginHorizontal="30dp" />
<ImageView
android:id="@+id/exo_ffwd"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@drawable/ic_forward_10_24" />
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<androidx.media3.ui.DefaultTimeBar
android:id="@+id/exo_progress"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="@+id/exo_position"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#fff"
android:textSize="20sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="4dp"
android:text="/"
android:textColor="#CBCDC8"
android:textSize="20sp" />
<TextView
android:id="@+id/exo_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="#CBCDC8"
android:textSize="20sp" />
<ImageView
android:id="@+id/exo_fullscreen_custom"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:layout_weight="0"
android:src="@drawable/ic_fullscreen_24" />
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,51 @@
<?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="match_parent"
android:background="#44000000">
<LinearLayout
android:id="@+id/linearLayout3"
android:layout_width="800dp"
android:layout_height="0dp"
android:background="?attr/colorSurface"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/materialToolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize" />
<include
layout="@layout/view_commentary"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/listDivider" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/listCommentaries"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp" />
</LinearLayout>
<include
layout="@layout/comment_component"
android:layout_width="700dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout 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"
@ -27,9 +27,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="Logo"
app:srcCompat="@drawable/icon" />
app:srcCompat="@mipmap/ic_launcher" />
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
@ -39,11 +39,10 @@
android:layout_height="wrap_content"
android:text="@string/aboutLabel"
android:textAlignment="center"
android:textAppearance="@android:style/TextAppearance.Material.Medium.Inverse"
android:textColor="@android:color/black"
android:textAppearance="@android:style/TextAppearance.Material.Medium"
android:textStyle="bold" />
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
@ -55,7 +54,7 @@
android:textAlignment="textStart"
android:textSize="16sp" />
<TextView
<com.google.android.material.textview.MaterialTextView
android:id="@+id/gitlabUrl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -66,7 +65,7 @@
android:textSize="16sp"
android:textStyle="bold" />
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="20dp" />
@ -88,7 +87,7 @@
android:textSize="16sp"
android:textStyle="bold" />
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
@ -98,11 +97,10 @@
android:layout_height="wrap_content"
android:text="@string/aboutInstance"
android:textAlignment="center"
android:textAppearance="@android:style/TextAppearance.Material.Medium.Inverse"
android:textColor="@android:color/black"
android:textAppearance="@android:style/TextAppearance.Material.Medium"
android:textStyle="bold" />
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="20dp" />
@ -124,7 +122,7 @@
android:textSize="16sp"
android:textStyle="bold" />
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
@ -135,7 +133,11 @@
android:text="@string/aboutLicense"
android:textAlignment="textStart"
android:textSize="16sp" />
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,153 @@
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context=".ChannelActivity">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/linearLayout2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorProfile"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingTop="20dp"
android:paddingBottom="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageButton
android:id="@+id/channelImg"
android:layout_width="match_parent"
android:layout_height="70dp"
android:adjustViewBounds="false"
android:background="@android:color/transparent"
android:contentDescription="@string/app_name"
android:cropToPadding="false"
android:scaleType="fitCenter"
app:srcCompat="@drawable/default_avatar" />
<TextView
android:id="@+id/usernameProfile"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textColor="@android:color/white" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/followersIndicator"
android:textAlignment="center"
android:textColor="@android:color/white"
android:textStyle="bold" />
<TextView
android:id="@+id/subcriptionsTxt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAlignment="textStart"
android:textColor="@android:color/white" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="horizontal">
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/hostIndicator"
android:textAlignment="center"
android:textColor="@android:color/white"
android:textStyle="bold" />
<TextView
android:id="@+id/hostTxt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAlignment="textStart"
android:textColor="@android:color/white" />
</LinearLayout>
</LinearLayout>
<Button
android:id="@+id/subcriptionBtn"
style="@style/Widget.AppCompat.Button.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/subscribeBtn"
android:textAlignment="center"
android:visibility="invisible" />
</LinearLayout>
<FrameLayout
android:id="@+id/frameLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:paddingRight="5dp"
app:layout_constraintTop_toBottomOf="@+id/linearLayout2"
tools:layout_editor_absoluteX="0dp">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Videos:"
android:textStyle="bold"
tools:layout_editor_absoluteX="176dp"
tools:layout_editor_absoluteY="214dp" />
</FrameLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/listVideosChannel"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout 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"
@ -29,32 +29,41 @@
android:contentDescription="Logo"
app:srcCompat="@drawable/icon" />
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
<TextView
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/hostInfoText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hostInfoText"
android:textAlignment="center"
android:textAppearance="@android:style/TextAppearance.Material.Medium.Inverse"
android:textColor="@android:color/black" />
/>
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
<EditText
android:id="@+id/hostText"
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/hostText"
android:inputType="text" />
android:layout_margin="4dp"
android:hint="@string/instance"
app:expandedHintEnabled="false">
<Button
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/hostText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/hostText"
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -62,4 +71,4 @@
</LinearLayout>
</FrameLayout>
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,98 +1,97 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context=".LoginActivity">
<FrameLayout
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="32dp"
app:layout_constraintBottom_toBottomOf="parent"
android:gravity="center"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
app:layout_constraintWidth_max="500dp">
<LinearLayout
<ImageView
android:id="@+id/imageView2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
android:layout_height="wrap_content"
android:contentDescription="Logo"
app:srcCompat="@drawable/icon" />
<ImageView
android:id="@+id/imageView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="Logo"
app:srcCompat="@drawable/icon" />
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
<Space
android:layout_width="match_parent"
android:layout_height="30dp" />
<TextView
android:id="@+id/loginInfo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/loginInfo"
android:textAlignment="center"
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium" />
<TextView
android:id="@+id/loginInfo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/loginInfo"
android:textAlignment="center"
android:textAppearance="@android:style/TextAppearance.Material.Medium.Inverse"
android:textColor="@android:color/black" />
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
<Space
android:layout_width="match_parent"
android:layout_height="30dp" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/userTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:hint="@string/userTxt"
android:maxWidth="600dp">
<TextView
android:id="@+id/userTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/userTxt" />
<EditText
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/userText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/userText"
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
<TextView
android:id="@+id/passwordTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/passwordTxt" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/passwordTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:hint="@string/passwordTxt"
android:maxWidth="600dp"
android:maxEms="10"
app:endIconMode="password_toggle">
<EditText
android:id="@+id/passwordText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/passwordText"
android:inputType="text|textPassword" />
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/loginBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/loginBtn"
android:textAlignment="center" />
<com.google.android.material.button.MaterialButton
android:id="@+id/loginBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/loginBtn"
android:textAlignment="center" />
<Space
android:layout_width="match_parent"
android:layout_height="30dp" />
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
<Button
android:id="@+id/registerActionBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/registerActionBtn"
android:visibility="visible" />
<com.google.android.material.button.MaterialButton
android:id="@+id/registerActionBtn"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/registerActionBtn"
android:visibility="invisible" />
</LinearLayout>
</LinearLayout>
</FrameLayout>
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.drawerlayout.widget.DrawerLayout 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:id="@+id/drawer_layout"
@ -13,13 +13,17 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.NavigationView
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="@color/colorMenu"
app:itemTextColor="@color/colorBody"
app:itemIconTint="@android:color/darker_gray"
android:theme="@style/ThemeOverlay.AppCompat.Dark"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer" />
</android.support.v4.widget.DrawerLayout>
</androidx.drawerlayout.widget.DrawerLayout>

View File

@ -90,6 +90,7 @@
<Button
android:id="@+id/registerBtn"
style="@style/Widget.AppCompat.Button.Colored"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/registerBtn"

View File

@ -1,14 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context=".ReproductorActivity">
<ScrollView
<RelativeLayout
android:id="@+id/fullScreen"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
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" />
<RelativeLayout
android:id="@+id/fullScreenExo"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
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.media3.ui.PlayerView
android:id="@+id/fullscreenPlayer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000"
app:use_controller="true"
app:show_buffering="always"
app:controller_layout_id="@layout/custom_player_controls"
app:player_layout_id="@layout/exo_player_view"/>
</RelativeLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/nonFullScreen"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
@ -25,16 +66,28 @@
<WebView
android:id="@+id/videoView"
android:layout_width="match_parent"
android:layout_height="220dp">
android:layout_height="205dp"
android:layout_weight="1"
android:visibility="gone" />
</WebView>
<androidx.media3.ui.PlayerView
android:id="@+id/exoPlayer"
android:layout_width="match_parent"
android:layout_height="205dp"
app:auto_show="true"
app:show_buffering="always"
app:controller_layout_id="@layout/custom_player_controls"
app:surface_type="surface_view"
app:use_controller="true"
app:repeat_toggle_modes="none"/>
<TextView
android:id="@+id/tittleVideoTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:textAppearance="@android:style/TextAppearance.Material.Large"
android:paddingStart="5dp"
android:textAppearance="@android:style/TextAppearance.Material.Display1"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
@ -42,140 +95,216 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:textSize="12sp" />
<LinearLayout
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/actionsLayout"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_height="50dp"
android:gravity="top"
android:orientation="horizontal"
android:visibility="gone">
<LinearLayout
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/likeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical">
android:orientation="vertical"
android:visibility="visible">
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:adjustViewBounds="false"
android:contentDescription="@string/likeBtn"
android:cropToPadding="false"
android:scaleType="center"
android:visibility="visible"
app:srcCompat="@drawable/ic_like" />
<TextView
android:id="@+id/textView"
android:id="@+id/textViewLike"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/likeBtn"
android:textAlignment="center" />
</LinearLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
<LinearLayout
android:id="@+id/dislikeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical">
android:orientation="vertical"
android:visibility="visible">
<ImageView
android:id="@+id/imageView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:adjustViewBounds="false"
android:contentDescription="@string/dislikeBtn"
android:cropToPadding="false"
android:visibility="visible"
app:srcCompat="@drawable/ic_dislike" />
<TextView
android:id="@+id/textView"
android:id="@+id/textViewDislike"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/dislikeBtn"
android:textAlignment="center" />
</LinearLayout>
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
<LinearLayout
android:id="@+id/reportLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/shareBtn"
android:visibility="gone" />
android:orientation="vertical"
android:visibility="visible">
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
<ImageView
android:id="@+id/imageViewAlert"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:adjustViewBounds="false"
android:contentDescription="@string/dislikeBtn"
android:cropToPadding="false"
android:visibility="visible"
app:srcCompat="@drawable/ic_alert" />
<TextView
android:id="@+id/textViewAlert"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/reportBtn"
android:textAlignment="center" />
</LinearLayout>
<LinearLayout
android:id="@+id/shareLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/reportBtn"
android:visibility="gone" />
</LinearLayout>
android:orientation="vertical"
android:visibility="visible">
<ImageView
android:id="@+id/imageViewShare"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:adjustViewBounds="false"
android:contentDescription="@string/shareBtn"
android:cropToPadding="false"
android:visibility="visible"
app:srcCompat="@drawable/ic_share" />
<TextView
android:id="@+id/textViewShare"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/shareBtn"
android:textAlignment="center" />
</LinearLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="60dp"
android:layout_weight="1"
android:gravity="center|center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/userImg"
android:layout_width="40dp"
android:layout_height="50dp"
android:layout_width="35dp"
android:layout_height="wrap_content"
android:layout_margin="0dp"
android:layout_weight="1"
android:adjustViewBounds="false"
android:adjustViewBounds="true"
android:cropToPadding="false"
android:padding="5dp"
android:scaleType="centerInside"
android:scaleType="fitCenter"
app:srcCompat="@drawable/default_avatar" />
<TextView
android:id="@+id/userTxt"
android:layout_width="70dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:textAppearance="@android:style/TextAppearance.Material.Large"
android:textColor="@android:color/black" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="3"
android:orientation="vertical">
<Button
<TextView
android:id="@+id/userTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxWidth="300dp"
android:textAppearance="@android:style/TextAppearance.Material.Large"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/hostTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="10sp"
android:textStyle="italic" />
</LinearLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/subscribeBtn"
style="@android:style/Widget.Holo.Button.Small"
style="@style/Widget.MaterialComponents.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/subscribeBtn"
android:visibility="gone" />
android:textSize="12sp"
android:visibility="invisible" />
</LinearLayout>
<TextView
android:id="@+id/descriptionTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLength="1000"
android:maxLines="100"
android:paddingLeft="5dp"
android:text="@string/descriptionTxt" />
android:text="@string/descriptionTxt"
android:textStyle="bold" />
<ScrollView
<TextView
android:id="@+id/descriptionVideoTxt"
android:layout_width="match_parent"
android:layout_height="80dp">
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:layout_marginBottom="2dp"
android:autoLink="web"
android:linksClickable="true"
android:maxLength="10000"
android:maxLines="100"
android:paddingLeft="10dp"
android:paddingRight="10dp" />
<TextView
android:id="@+id/descriptionVideoTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLength="1000"
android:maxLines="1000"
android:paddingLeft="5dp"
android:text="TextView"
android:textStyle="italic" />
</ScrollView>
<com.google.android.material.button.MaterialButton
android:id="@+id/showMoreBtn"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/showMore"
android:visibility="gone" />
<View
android:id="@+id/divider"
@ -183,7 +312,35 @@
android:layout_height="1dp"
android:background="?android:attr/listDivider" />
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="10dp"
android:layout_weight="1" />
<TextView
android:id="@+id/commentariesTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:text="@string/commentariesTxt"
android:textStyle="bold" />
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="20dp" />
<include layout="@layout/comment_component" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/listCommentaries"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
</ScrollView>
</android.support.constraint.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,57 @@
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SplashActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="32dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="@+id/imageView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@string/app_name"
app:srcCompat="@mipmap/ic_launcher" />
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
<TextView
android:id="@+id/hostInfoText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/charging"
android:textAlignment="center"
android:textAppearance="@android:style/TextAppearance.Material.Medium" />
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="?attr/colorAccent"
android:indeterminate="true" />
</LinearLayout>
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,25 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
<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"
tools:context=".MainActivity">
<android.support.design.widget.AppBarLayout
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/P2playTheme.AppBarOverlay">
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/P2playTheme.PopupOverlay" />
android:layout_height="?attr/actionBarSize"/>
</android.support.design.widget.AppBarLayout>
</com.google.android.material.appbar.AppBarLayout>
<include layout="@layout/content_main" />
</android.support.design.widget.CoordinatorLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/commentaryLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/userImgCom"
android:layout_width="5dp"
android:layout_height="57dp"
android:layout_weight="1"
app:srcCompat="@drawable/default_avatar" />
<com.google.android.material.textfield.TextInputLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_weight="3"
android:hint="@string/commentHolder">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/commentaryText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:ems="10"
android:inputType="textMultiLine" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/commentaryBtn"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/commentaryText" />
</androidx.appcompat.widget.LinearLayoutCompat>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout 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"
@ -8,7 +8,7 @@
tools:context=".MainActivity"
tools:showIn="@layout/app_bar_main">
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -16,7 +16,7 @@
android:visibility="visible"
app:layout_constraintTop_toTopOf="parent">
<android.support.v7.widget.RecyclerView
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -24,5 +24,17 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.v4.widget.SwipeRefreshLayout>
</android.support.constraint.ConstraintLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<include
android:id="@+id/mini"
layout="@layout/mini_player"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,107 @@
<?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/exo_controls"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#44000000">
<ImageView
android:id="@+id/exo_settings"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_weight="0"
android:alpha="0.5"
android:src="@drawable/ic_baseline_settings_24"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/exo_rew"
android:layout_width="35dp"
android:layout_height="35dp"
android:src="@drawable/ic_replay_10_24" />
<ImageView
android:id="@+id/exo_play_pause"
android:layout_width="43dp"
android:layout_height="43dp"
android:layout_marginHorizontal="30dp" />
<ImageView
android:id="@+id/exo_ffwd"
android:layout_width="35dp"
android:layout_height="35dp"
android:src="@drawable/ic_forward_10_24" />
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<androidx.media3.ui.DefaultTimeBar
android:id="@+id/exo_progress"
android:layout_width="wrap_content"
android:layout_height="10dp"
android:layout_weight="1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="@+id/exo_position"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#fff" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="4dp"
android:text="/"
android:textColor="#CBCDC8" />
<TextView
android:id="@+id/exo_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="#CBCDC8" />
<ImageView
android:id="@+id/exo_fullscreen_custom"
android:layout_width="35dp"
android:layout_height="42dp"
android:layout_gravity="center"
android:layout_weight="0"
android:src="@drawable/ic_fullscreen_24" />
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,50 @@
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:background="?attr/colorSurface"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/linearLayout3"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="130dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/materialToolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize" />
<include
layout="@layout/view_commentary"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/listDivider" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/listCommentaries"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="10dp"/>
</LinearLayout>
<include
layout="@layout/comment_component"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,66 @@
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/androidBackgroundSecondary"
android:elevation="5dp"
android:clickable="true"
android:id="@+id/mini_player">
<ImageView
android:id="@+id/mini_player_image"
android:layout_width="wrap_content"
android:layout_height="60dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/default_avatar"
tools:srcCompat="@drawable/default_avatar" />
<TextView
android:id="@+id/mini_player_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="8dp"
android:maxWidth="180dp"
android:text="Video"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
app:layout_constraintStart_toEndOf="@+id/mini_player_image"
app:layout_constraintTop_toTopOf="parent"
android:maxLines="1"
android:ellipsize="end"
android:textColor="?attr/androidOnBackgroundSecondary"/>
<TextView
android:id="@+id/mini_player_author"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginBottom="8dp"
android:maxWidth="180dp"
android:text="Author"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/mini_player_image"
android:maxLines="1"
android:ellipsize="end" />
<ImageView
android:id="@+id/mini_play_pause"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginEnd="16dp"
android:layout_weight="1"
android:adjustViewBounds="false"
android:contentDescription="@string/likeBtn"
android:cropToPadding="false"
android:scaleType="center"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_pause_24"
app:tint="@color/colorAccent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -3,22 +3,21 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="@dimen/nav_header_height"
android:background="@android:color/darker_gray"
android:background="@color/colorProfile"
android:gravity="bottom"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:theme="@style/ThemeOverlay.AppCompat.Dark">
<ImageView
android:id="@+id/side_imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="50dp"
android:layout_height="50dp"
android:contentDescription="@string/nav_header_desc"
android:paddingTop="@dimen/nav_header_vertical_spacing"
app:srcCompat="@mipmap/ic_launcher_round" />
app:srcCompat="@drawable/default_avatar" />
<TextView
android:id="@+id/side_usernameTxt"
@ -26,12 +25,15 @@
android:layout_height="wrap_content"
android:paddingTop="@dimen/nav_header_vertical_spacing"
android:text="@string/nav_header_title"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:textColor="@android:color/white"
android:textSize="18sp" />
<TextView
android:id="@+id/side_emailTxt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nav_header_subtitle" />
android:text="@string/nav_header_subtitle"
android:textColor="@android:color/darker_gray" />
</LinearLayout>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp" >
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/reportText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textMultiLine" >
<requestFocus />
</com.google.android.material.textfield.TextInputEditText>
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>

View File

@ -0,0 +1,9 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/settings"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
android:padding="10dp" >
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="0dp"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/twoFactorText"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<requestFocus />
</com.google.android.material.textfield.TextInputEditText>
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>

View File

@ -0,0 +1,60 @@
<?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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:orientation="horizontal"
android:paddingLeft="10dp"
android:paddingRight="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/userCommentImg"
android:layout_width="100dp"
android:layout_height="60dp"
android:layout_weight="1"
android:contentDescription="@string/app_name"
android:scaleType="fitCenter"
app:srcCompat="@drawable/default_avatar" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical"
android:paddingLeft="10dp"
android:paddingRight="10dp">
<TextView
android:id="@+id/userTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/darker_gray"
android:textStyle="italic" />
<TextView
android:id="@+id/userCommentary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autoLink="web"
android:linksClickable="true"
android:maxLength="1000"
android:maxLines="10" />
<TextView
android:id="@+id/replyBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/reply"
android:textColor="?attr/colorSecondary"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout 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"
@ -14,33 +14,77 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/thumb"
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="230dp"
app:srcCompat="@android:drawable/ic_menu_gallery" />
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/thumb"
android:layout_width="match_parent"
android:layout_height="205dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@android:drawable/ic_menu_gallery" />
<TextView
android:id="@+id/isLive"
android:layout_width="65dp"
android:layout_height="19dp"
android:layout_marginStart="8dp"
android:layout_marginBottom="16dp"
android:background="@drawable/live_shape"
android:ems="10"
android:paddingHorizontal="3dp"
android:text="@string/is_live_video"
android:textAlignment="center"
android:textColor="@color/durationColor"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:visibility="invisible" />
<TextView
android:id="@+id/duration"
android:layout_width="65dp"
android:layout_height="19dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="16dp"
android:background="@drawable/round_text"
android:ems="10"
android:paddingHorizontal="3dp"
android:text="00:00"
android:textAlignment="center"
android:textColor="?attr/colorOnSecondary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="63dp"
android:layout_height="55dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/userImg"
android:layout_width="140dp"
android:layout_width="120dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:adjustViewBounds="false"
android:adjustViewBounds="true"
android:clickable="false"
android:cropToPadding="false"
android:padding="5dp"
android:scaleType="centerInside"
android:scaleType="fitCenter"
app:srcCompat="@drawable/default_avatar" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
@ -48,26 +92,26 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLength="70"
android:text="TextView"
android:textSize="18sp"
android:textStyle="bold" />
android:textSize="14sp"
android:textStyle="bold"
android:theme="@style/MaterialAlertDialog.MaterialComponents.Title.Text" />
<TextView
android:id="@+id/descriptionTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:textColor="@android:color/darker_gray" />
android:textColor="@android:color/darker_gray"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="15dp"
android:layout_height="5dp"
android:layout_weight="1"
app:layout_constraintTop_toBottomOf="@+id/linearLayout" />
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -3,16 +3,43 @@
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="navigation_view">
<item android:title="Videos">
<item
android:id="@+id/ml"
android:icon="@android:color/darker_gray"
android:title="@string/nav_menu_myLibrary"
android:visible="false">
<menu>
<item
android:id="@+id/nav_subscriptions"
android:id="@+id/nav_myVideos"
android:icon="@drawable/ic_video_library_black_24dp"
android:title="@string/title_myVideos" />
<item
android:id="@+id/nav_subscriptions"
android:icon="@drawable/ic_live_tv_black_24dp"
android:title="@string/nav_subscriptions" />
<item
android:id="@+id/nav_history"
android:icon="@drawable/ic_history_black_24dp"
android:title="@string/nav_history" />
</menu>
</item>
<item
android:id="@+id/ai"
android:icon="@android:color/darker_gray"
android:title="@string/nav_menu_videos">
<menu>
<item
android:id="@+id/nav_popular"
android:icon="@android:drawable/btn_star"
android:title="@string/nav_popular" />
<item
android:id="@+id/nav_trending"
android:icon="@drawable/ic_trending_up_black_24dp"
android:title="@string/nav_trending" />
<item
android:id="@+id/nav_likes"
android:icon="@drawable/ic_thumb_up_black_24dp"
android:title="@string/nav_likes" />
<item
android:id="@+id/nav_recent"
android:icon="@drawable/ic_add_circle_black_24dp"
@ -24,7 +51,10 @@
</menu>
</item>
<item android:title="More">
<item
android:id="@+id/aiao"
android:icon="@android:color/white"
android:title="@string/nav_menu_more">
<menu>
<item
android:id="@+id/nav_about"

View File

@ -2,6 +2,13 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/app_bar_search"
android:icon="@drawable/ic_search_black_24dp"
app:actionViewClass="androidx.appcompat.widget.SearchView"
android:title="@string/action_login"
app:showAsAction="always"/>
<item
android:id="@+id/action_login"
android:title="@string/action_login"

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 947 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 694 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

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