diff --git a/README.md b/README.md
index 43cbd87..61e7b40 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ The other app is **[TubeLab](#TubeLab)** a Peertube Android app working for all
## TubeLab
-Tubelab is an Android app for Peertube (GNU GPLv3).
+Tubelab is an Android app for Peertube (GNU GPLv3).
[](https://play.google.com/store/apps/details?id=app.fedilab.tubelab)
[](https://f-droid.org/packages/app.fedilab.tubelab/)
diff --git a/app/build.gradle b/app/build.gradle
index d3ab720..41714f2 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,18 +1,16 @@
apply plugin: 'com.android.application'
-
apply plugin: "androidx.navigation.safeargs"
android {
compileSdkVersion 30
buildToolsVersion "30.0.2"
-
defaultConfig {
minSdkVersion 21
targetSdkVersion 30
- versionCode 25
- versionName "1.7.0"
+ versionCode 31
+ versionName "1.10.1"
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -43,27 +41,70 @@ android {
productFlavors {
fdroid_acad {
applicationId "app.fedilab.fedilabtube"
+ resValue "string", "app_name", "TubeAcad"
+ resValue "string", "app_id", "app.fedilab.fedilabtube"
buildConfigField "String", "version", "\"fdroid_acad\""
buildConfigField "boolean", "full_instances", "false"
buildConfigField "boolean", "google_restriction", "false"
+ buildConfigField "boolean", "surfing_mode", "false"
+ buildConfigField "boolean", "sepia_search", "false"
+ buildConfigField "boolean", "instance_switcher", "true"
}
google_acad {
applicationId "app.fedilab.fedilabtube"
+ resValue "string", "app_name", "TubeAcad"
+ resValue "string", "app_id", "app.fedilab.fedilabtube"
buildConfigField "String", "version", "\"google_acad\""
buildConfigField "boolean", "full_instances", "false"
buildConfigField "boolean", "google_restriction", "true"
+ buildConfigField "boolean", "surfing_mode", "false"
+ buildConfigField "boolean", "sepia_search", "false"
+ buildConfigField "boolean", "instance_switcher", "true"
}
fdroid_full {
applicationId "app.fedilab.tubelab"
+ resValue "string", "app_name", "TubeLab"
+ resValue "string", "app_id", "app.fedilab.tubelab"
buildConfigField "String", "version", "\"fdroid_full\""
buildConfigField "boolean", "full_instances", "true"
buildConfigField "boolean", "google_restriction", "false"
+ buildConfigField "boolean", "surfing_mode", "true"
+ buildConfigField "boolean", "sepia_search", "true"
+ buildConfigField "boolean", "instance_switcher", "true"
}
google_full {
applicationId "app.fedilab.tubelab"
+ resValue "string", "app_name", "TubeLab"
+ resValue "string", "app_id", "app.fedilab.tubelab"
buildConfigField "String", "version", "\"google_full\""
buildConfigField "boolean", "full_instances", "true"
buildConfigField "boolean", "google_restriction", "true"
+ buildConfigField "boolean", "surfing_mode", "true"
+ buildConfigField "boolean", "sepia_search", "true"
+ buildConfigField "boolean", "instance_switcher", "true"
+ }
+ queermotion {
+ applicationId "org.queermotion.peertube"
+ resValue "string", "app_name", "QueerMotion"
+ resValue "string", "app_id", "org.queermotion.peertube"
+ buildConfigField "String", "version", "\"queermotion\""
+ buildConfigField "boolean", "full_instances", "true"
+ buildConfigField "boolean", "google_restriction", "false"
+ buildConfigField "boolean", "surfing_mode", "false"
+ buildConfigField "boolean", "sepia_search", "false"
+ buildConfigField "boolean", "instance_switcher", "false"
+ }
+ bittube {
+ applicationId "app.fedilab.bittube"
+ resValue "string", "app_name", "Bittube"
+ resValue "string", "app_id", "app.fedilab.bittube"
+ buildConfigField "String", "version", "\"bittube\""
+ buildConfigField "boolean", "full_instances", "true"
+ buildConfigField "boolean", "google_restriction", "true"
+ buildConfigField "boolean", "surfing_mode", "false"
+ buildConfigField "boolean", "sepia_search", "false"
+ buildConfigField "boolean", "instance_switcher", "true"
+
}
}
@@ -80,6 +121,12 @@ android {
google_full {
res.srcDirs = ['src/main/res', 'src/full/res']
}
+ queermotion {
+ res.srcDirs = ['src/main/res', 'src/queermotion/res']
+ }
+ bittube {
+ res.srcDirs = ['src/main/res', 'src/bittube/res']
+ }
}
}
@@ -99,14 +146,14 @@ dependencies {
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
- implementation 'androidx.navigation:navigation-fragment:2.3.1'
+ implementation 'androidx.navigation:navigation-fragment:2.3.2'
implementation "androidx.fragment:fragment:1.2.5"
- implementation 'androidx.navigation:navigation-ui:2.3.1'
- implementation ("androidx.navigation:navigation-dynamic-features-fragment:2.3.1")
+ implementation 'androidx.navigation:navigation-ui:2.3.2'
+ implementation ("androidx.navigation:navigation-dynamic-features-fragment:2.3.2")
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
- implementation 'androidx.browser:browser:1.2.0'
+ implementation 'androidx.browser:browser:1.3.0'
implementation 'androidx.documentfile:documentfile:1.0.1'
- testImplementation 'junit:junit:4.13'
+ testImplementation 'junit:junit:4.13.1'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
@@ -118,10 +165,10 @@ dependencies {
implementation "com.github.bumptech.glide:glide:4.11.0"
annotationProcessor "com.github.bumptech.glide:compiler:4.11.0"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
- implementation "net.gotev:uploadservice:3.5.2"
- implementation "net.gotev:uploadservice-okhttp:3.5.2"
+ implementation "net.gotev:uploadservice:4.5.1"
+ implementation "net.gotev:uploadservice-okhttp:4.5.1"
implementation "com.google.code.gson:gson:2.8.6"
- implementation 'androidx.media:media:1.2.0'
+ implementation 'androidx.media:media:1.2.1'
implementation 'com.github.ybq:Android-SpinKit:1.4.0'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
@@ -134,6 +181,12 @@ dependencies {
implementation "androidx.work:work-runtime:2.4.0"
implementation "androidx.work:work-runtime-ktx:2.4.0"
+
+ //custom cast feature
implementation 'jp.wasabeef:glide-transformations:4.0.0'
+ implementation 'su.litvak.chromecast:api-v2:0.11.3'
+ implementation 'com.fasterxml.jackson.core:jackson-core:2.12.0'
+ implementation 'org.slf4j:slf4j-simple:1.7.30'
+
}
\ No newline at end of file
diff --git a/app/src/main/res/drawable-anydpi-v24/ic_notification_tubelab.xml b/app/src/acad/res/drawable-anydpi-v24/ic_notification_tubelab.xml
similarity index 100%
rename from app/src/main/res/drawable-anydpi-v24/ic_notification_tubelab.xml
rename to app/src/acad/res/drawable-anydpi-v24/ic_notification_tubelab.xml
diff --git a/app/src/main/res/drawable-hdpi/ic_notification_tubelab.png b/app/src/acad/res/drawable-hdpi/ic_notification_tubelab.png
similarity index 100%
rename from app/src/main/res/drawable-hdpi/ic_notification_tubelab.png
rename to app/src/acad/res/drawable-hdpi/ic_notification_tubelab.png
diff --git a/app/src/main/res/drawable-mdpi/ic_notification_tubelab.png b/app/src/acad/res/drawable-mdpi/ic_notification_tubelab.png
similarity index 100%
rename from app/src/main/res/drawable-mdpi/ic_notification_tubelab.png
rename to app/src/acad/res/drawable-mdpi/ic_notification_tubelab.png
diff --git a/app/src/main/res/drawable-xhdpi/ic_notification_tubelab.png b/app/src/acad/res/drawable-xhdpi/ic_notification_tubelab.png
similarity index 100%
rename from app/src/main/res/drawable-xhdpi/ic_notification_tubelab.png
rename to app/src/acad/res/drawable-xhdpi/ic_notification_tubelab.png
diff --git a/app/src/main/res/drawable-xxhdpi/ic_notification_tubelab.png b/app/src/acad/res/drawable-xxhdpi/ic_notification_tubelab.png
similarity index 100%
rename from app/src/main/res/drawable-xxhdpi/ic_notification_tubelab.png
rename to app/src/acad/res/drawable-xxhdpi/ic_notification_tubelab.png
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_notification_tubelab.png b/app/src/acad/res/drawable-xxxhdpi/ic_notification_tubelab.png
similarity index 100%
rename from app/src/main/res/drawable-xxxhdpi/ic_notification_tubelab.png
rename to app/src/acad/res/drawable-xxxhdpi/ic_notification_tubelab.png
diff --git a/app/src/acad/res/values/colors.xml b/app/src/acad/res/values/colors.xml
index 9fd2099..41d179b 100644
--- a/app/src/acad/res/values/colors.xml
+++ b/app/src/acad/res/values/colors.xml
@@ -8,6 +8,7 @@
#FAFAFA
#2b90d9
#F44336
-
+ #DD000000
#F44336
+ #80808080
\ No newline at end of file
diff --git a/app/src/bittube/ic_launcher-playstore.png b/app/src/bittube/ic_launcher-playstore.png
new file mode 100644
index 0000000..96e3d80
Binary files /dev/null and b/app/src/bittube/ic_launcher-playstore.png differ
diff --git a/app/src/bittube/res/color/bottom_nav_color.xml b/app/src/bittube/res/color/bottom_nav_color.xml
new file mode 100644
index 0000000..662d3b2
--- /dev/null
+++ b/app/src/bittube/res/color/bottom_nav_color.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/bittube/res/drawable-anydpi-v24/ic_notification_tubelab.xml b/app/src/bittube/res/drawable-anydpi-v24/ic_notification_tubelab.xml
new file mode 100644
index 0000000..26878af
--- /dev/null
+++ b/app/src/bittube/res/drawable-anydpi-v24/ic_notification_tubelab.xml
@@ -0,0 +1,864 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/bittube/res/drawable-hdpi/ic_notification_tubelab.png b/app/src/bittube/res/drawable-hdpi/ic_notification_tubelab.png
new file mode 100644
index 0000000..064c676
Binary files /dev/null and b/app/src/bittube/res/drawable-hdpi/ic_notification_tubelab.png differ
diff --git a/app/src/bittube/res/drawable-mdpi/ic_notification_tubelab.png b/app/src/bittube/res/drawable-mdpi/ic_notification_tubelab.png
new file mode 100644
index 0000000..cd4f8bb
Binary files /dev/null and b/app/src/bittube/res/drawable-mdpi/ic_notification_tubelab.png differ
diff --git a/app/src/bittube/res/drawable-v24/ic_launcher_foreground.xml b/app/src/bittube/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..3494e3e
--- /dev/null
+++ b/app/src/bittube/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,862 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/bittube/res/drawable-xhdpi/ic_notification_tubelab.png b/app/src/bittube/res/drawable-xhdpi/ic_notification_tubelab.png
new file mode 100644
index 0000000..4d6d6d2
Binary files /dev/null and b/app/src/bittube/res/drawable-xhdpi/ic_notification_tubelab.png differ
diff --git a/app/src/bittube/res/drawable-xxhdpi/ic_notification_tubelab.png b/app/src/bittube/res/drawable-xxhdpi/ic_notification_tubelab.png
new file mode 100644
index 0000000..eaa5022
Binary files /dev/null and b/app/src/bittube/res/drawable-xxhdpi/ic_notification_tubelab.png differ
diff --git a/app/src/bittube/res/drawable-xxxhdpi/ic_notification_tubelab.png b/app/src/bittube/res/drawable-xxxhdpi/ic_notification_tubelab.png
new file mode 100644
index 0000000..169866f
Binary files /dev/null and b/app/src/bittube/res/drawable-xxxhdpi/ic_notification_tubelab.png differ
diff --git a/app/src/bittube/res/drawable/bittube.xml b/app/src/bittube/res/drawable/bittube.xml
new file mode 100644
index 0000000..7bca606
--- /dev/null
+++ b/app/src/bittube/res/drawable/bittube.xml
@@ -0,0 +1,856 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/bittube/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/bittube/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..ac94b34
--- /dev/null
+++ b/app/src/bittube/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/bittube/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/bittube/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..ac94b34
--- /dev/null
+++ b/app/src/bittube/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/bittube/res/mipmap-hdpi/ic_launcher.png b/app/src/bittube/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..440ad47
Binary files /dev/null and b/app/src/bittube/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/bittube/res/mipmap-hdpi/ic_launcher_round.png b/app/src/bittube/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..98441c9
Binary files /dev/null and b/app/src/bittube/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/app/src/bittube/res/mipmap-mdpi/ic_launcher.png b/app/src/bittube/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..118b9e8
Binary files /dev/null and b/app/src/bittube/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/bittube/res/mipmap-mdpi/ic_launcher_round.png b/app/src/bittube/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..d0754f8
Binary files /dev/null and b/app/src/bittube/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/app/src/bittube/res/mipmap-xhdpi/ic_launcher.png b/app/src/bittube/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..5621131
Binary files /dev/null and b/app/src/bittube/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/bittube/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/bittube/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..4859fc7
Binary files /dev/null and b/app/src/bittube/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/app/src/bittube/res/mipmap-xxhdpi/ic_launcher.png b/app/src/bittube/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..55890cd
Binary files /dev/null and b/app/src/bittube/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/bittube/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/bittube/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..99059ce
Binary files /dev/null and b/app/src/bittube/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/app/src/bittube/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/bittube/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..75a224b
Binary files /dev/null and b/app/src/bittube/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/bittube/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/bittube/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9b92291
Binary files /dev/null and b/app/src/bittube/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/app/src/bittube/res/values/colors.xml b/app/src/bittube/res/values/colors.xml
new file mode 100644
index 0000000..e40a9ba
--- /dev/null
+++ b/app/src/bittube/res/values/colors.xml
@@ -0,0 +1,14 @@
+
+
+ #343434
+ #343434
+ #00abff
+
+ #bbF2690D
+ #FAFAFA
+ #2b90d9
+ #F44336
+ #DD000000
+ #F44336
+ #80808080
+
\ No newline at end of file
diff --git a/app/src/bittube/res/values/ic_launcher_background.xml b/app/src/bittube/res/values/ic_launcher_background.xml
new file mode 100644
index 0000000..c5d5899
--- /dev/null
+++ b/app/src/bittube/res/values/ic_launcher_background.xml
@@ -0,0 +1,4 @@
+
+
+ #FFFFFF
+
\ No newline at end of file
diff --git a/app/src/bittube/res/xml/file_paths.xml b/app/src/bittube/res/xml/file_paths.xml
new file mode 100644
index 0000000..63687c5
--- /dev/null
+++ b/app/src/bittube/res/xml/file_paths.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/fdroid_acad/contact-website.txt b/app/src/fdroid_acad/contact-website.txt
deleted file mode 100644
index ff945d0..0000000
--- a/app/src/fdroid_acad/contact-website.txt
+++ /dev/null
@@ -1 +0,0 @@
-https://fedilab.app
\ No newline at end of file
diff --git a/app/src/fdroid_acad/fastlane/metadata/android/en-US/changelogs/30.txt b/app/src/fdroid_acad/fastlane/metadata/android/en-US/changelogs/30.txt
new file mode 100644
index 0000000..78ac812
--- /dev/null
+++ b/app/src/fdroid_acad/fastlane/metadata/android/en-US/changelogs/30.txt
@@ -0,0 +1,11 @@
+Added:
+- Chromecast support (default disabled)
+- Detect start time in URLs
+
+Fixed:
+- Typo
+- Comment feature when logged out
+- Full-screen breaks
+- Crashes with the download button on live streams
+- Jumps with full-screen and vertical videos
+- Abuse report notifications clickable
\ No newline at end of file
diff --git a/app/src/fdroid_acad/fastlane/metadata/android/en-US/changelogs/31.txt b/app/src/fdroid_acad/fastlane/metadata/android/en-US/changelogs/31.txt
new file mode 100644
index 0000000..3a1639e
--- /dev/null
+++ b/app/src/fdroid_acad/fastlane/metadata/android/en-US/changelogs/31.txt
@@ -0,0 +1,13 @@
+Fixes some issues on 1.10.0 (Crashes when adding a playlist + bad behavior when subscribing to remote accounts)
+
+Added:
+- Chromecast support (default disabled)
+- Detect start time in URLs
+
+Fixed:
+- Typo
+- Comment feature when logged out
+- Full-screen breaks
+- Crashes with the download button on live streams
+- Jumps with full-screen and vertical videos
+- Abuse report notifications clickable
\ No newline at end of file
diff --git a/app/src/fdroid_acad/play/listings/en-US/full-description.txt b/app/src/fdroid_acad/fastlane/metadata/android/en-US/full_description.txt
similarity index 100%
rename from app/src/fdroid_acad/play/listings/en-US/full-description.txt
rename to app/src/fdroid_acad/fastlane/metadata/android/en-US/full_description.txt
diff --git a/app/src/fdroid_acad/play/listings/en-US/graphics/icon/icon.png b/app/src/fdroid_acad/fastlane/metadata/android/en-US/images/icon.png
similarity index 100%
rename from app/src/fdroid_acad/play/listings/en-US/graphics/icon/icon.png
rename to app/src/fdroid_acad/fastlane/metadata/android/en-US/images/icon.png
diff --git a/app/src/fdroid_acad/play/listings/en-US/graphics/phone-screenshots/img1.png b/app/src/fdroid_acad/fastlane/metadata/android/en-US/images/phoneScreenshots/img1.png
similarity index 100%
rename from app/src/fdroid_acad/play/listings/en-US/graphics/phone-screenshots/img1.png
rename to app/src/fdroid_acad/fastlane/metadata/android/en-US/images/phoneScreenshots/img1.png
diff --git a/app/src/fdroid_acad/play/listings/en-US/graphics/phone-screenshots/img2.png b/app/src/fdroid_acad/fastlane/metadata/android/en-US/images/phoneScreenshots/img2.png
similarity index 100%
rename from app/src/fdroid_acad/play/listings/en-US/graphics/phone-screenshots/img2.png
rename to app/src/fdroid_acad/fastlane/metadata/android/en-US/images/phoneScreenshots/img2.png
diff --git a/app/src/fdroid_acad/play/listings/en-US/graphics/phone-screenshots/img3.png b/app/src/fdroid_acad/fastlane/metadata/android/en-US/images/phoneScreenshots/img3.png
similarity index 100%
rename from app/src/fdroid_acad/play/listings/en-US/graphics/phone-screenshots/img3.png
rename to app/src/fdroid_acad/fastlane/metadata/android/en-US/images/phoneScreenshots/img3.png
diff --git a/app/src/fdroid_acad/play/listings/en-US/graphics/phone-screenshots/img4.png b/app/src/fdroid_acad/fastlane/metadata/android/en-US/images/phoneScreenshots/img4.png
similarity index 100%
rename from app/src/fdroid_acad/play/listings/en-US/graphics/phone-screenshots/img4.png
rename to app/src/fdroid_acad/fastlane/metadata/android/en-US/images/phoneScreenshots/img4.png
diff --git a/app/src/fdroid_acad/play/listings/en-US/graphics/phone-screenshots/img5.png b/app/src/fdroid_acad/fastlane/metadata/android/en-US/images/phoneScreenshots/img5.png
similarity index 100%
rename from app/src/fdroid_acad/play/listings/en-US/graphics/phone-screenshots/img5.png
rename to app/src/fdroid_acad/fastlane/metadata/android/en-US/images/phoneScreenshots/img5.png
diff --git a/app/src/fdroid_acad/fastlane/metadata/android/en-US/short_description.txt b/app/src/fdroid_acad/fastlane/metadata/android/en-US/short_description.txt
new file mode 100644
index 0000000..6592b98
--- /dev/null
+++ b/app/src/fdroid_acad/fastlane/metadata/android/en-US/short_description.txt
@@ -0,0 +1 @@
+TubeAcad est une application Peertube pour les instances académiques.
\ No newline at end of file
diff --git a/app/src/fdroid_acad/play/listings/en-US/title.txt b/app/src/fdroid_acad/fastlane/metadata/android/en-US/title.txt
similarity index 100%
rename from app/src/fdroid_acad/play/listings/en-US/title.txt
rename to app/src/fdroid_acad/fastlane/metadata/android/en-US/title.txt
diff --git a/app/src/fdroid_acad/play/listings/en-US/short-description.txt b/app/src/fdroid_acad/play/listings/en-US/short-description.txt
deleted file mode 100644
index 1f0744b..0000000
--- a/app/src/fdroid_acad/play/listings/en-US/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-TubeLab est une application Peertube pour les instances académiques.
\ No newline at end of file
diff --git a/app/src/fdroid_acad/play/release-notes/en-US/default.txt b/app/src/fdroid_acad/play/release-notes/en-US/default.txt
deleted file mode 100644
index ed45711..0000000
--- a/app/src/fdroid_acad/play/release-notes/en-US/default.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-- Nouvelles options :
- - Mode plein écran automatique
- - Désactiver la lecture automatique des vidéos
-
-- Quelques corrections de bugs
\ No newline at end of file
diff --git a/app/src/fdroid_full/contact-website.txt b/app/src/fdroid_full/contact-website.txt
deleted file mode 100644
index ff945d0..0000000
--- a/app/src/fdroid_full/contact-website.txt
+++ /dev/null
@@ -1 +0,0 @@
-https://fedilab.app
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/af/full-description.txt b/app/src/fdroid_full/fastlane/metadata/android/ar/full_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/af/full-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/ar/full_description.txt
diff --git a/app/src/fdroid_full/play/listings/ar/short-description.txt b/app/src/fdroid_full/fastlane/metadata/android/ar/short_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/ar/short-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/ar/short_description.txt
diff --git a/app/src/fdroid_full/play/listings/de/full-description.txt b/app/src/fdroid_full/fastlane/metadata/android/de/full_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/de/full-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/de/full_description.txt
diff --git a/app/src/fdroid_full/play/listings/de/short-description.txt b/app/src/fdroid_full/fastlane/metadata/android/de/short_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/de/short-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/de/short_description.txt
diff --git a/app/src/fdroid_full/play/listings/el/full-description.txt b/app/src/fdroid_full/fastlane/metadata/android/el/full_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/el/full-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/el/full_description.txt
diff --git a/app/src/fdroid_full/play/listings/el/short-description.txt b/app/src/fdroid_full/fastlane/metadata/android/el/short_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/el/short-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/el/short_description.txt
diff --git a/app/src/fdroid_full/fastlane/metadata/android/en-US/changelogs/30.txt b/app/src/fdroid_full/fastlane/metadata/android/en-US/changelogs/30.txt
new file mode 100644
index 0000000..5feb62c
--- /dev/null
+++ b/app/src/fdroid_full/fastlane/metadata/android/en-US/changelogs/30.txt
@@ -0,0 +1,15 @@
+Added:
+- Chromecast support (default disabled)
+- Detect start time in URLs
+
+Changed:
+- Instance picker supports URLs
+
+Fixed:
+- Typo
+- Comment feature when logged out
+- Full-screen breaks
+- Crashes with the download button on live streams
+- Jumps with full-screen and vertical videos
+- Abuse report notifications clickable
+- Remote channel subscriptions need twice clicks
\ No newline at end of file
diff --git a/app/src/fdroid_full/fastlane/metadata/android/en-US/changelogs/31.txt b/app/src/fdroid_full/fastlane/metadata/android/en-US/changelogs/31.txt
new file mode 100644
index 0000000..0e49659
--- /dev/null
+++ b/app/src/fdroid_full/fastlane/metadata/android/en-US/changelogs/31.txt
@@ -0,0 +1,16 @@
+Fixes some issues on 1.10.0 (Crashes when adding a playlist + bad behavior when subscribing to remote accounts)
+Added:
+- Chromecast support (default disabled)
+- Detect start time in URLs
+
+Changed:
+- Instance picker supports URLs
+
+Fixed:
+- Typo
+- Comment feature when logged out
+- Full-screen breaks
+- Crashes with the download button on live streams
+- Jumps with full-screen and vertical videos
+- Abuse report notifications clickable
+- Remote channel subscriptions need twice clicks
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/ar/full-description.txt b/app/src/fdroid_full/fastlane/metadata/android/en-US/full_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/ar/full-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/en-US/full_description.txt
diff --git a/app/src/fdroid_full/play/listings/en-US/graphics/icon/icon.png b/app/src/fdroid_full/fastlane/metadata/android/en-US/images/icon.png
similarity index 100%
rename from app/src/fdroid_full/play/listings/en-US/graphics/icon/icon.png
rename to app/src/fdroid_full/fastlane/metadata/android/en-US/images/icon.png
diff --git a/app/src/fdroid_full/play/listings/en-US/graphics/phone-screenshots/img1.png b/app/src/fdroid_full/fastlane/metadata/android/en-US/images/phoneScreenshots/img1.png
similarity index 100%
rename from app/src/fdroid_full/play/listings/en-US/graphics/phone-screenshots/img1.png
rename to app/src/fdroid_full/fastlane/metadata/android/en-US/images/phoneScreenshots/img1.png
diff --git a/app/src/fdroid_full/play/listings/en-US/graphics/phone-screenshots/img2.png b/app/src/fdroid_full/fastlane/metadata/android/en-US/images/phoneScreenshots/img2.png
similarity index 100%
rename from app/src/fdroid_full/play/listings/en-US/graphics/phone-screenshots/img2.png
rename to app/src/fdroid_full/fastlane/metadata/android/en-US/images/phoneScreenshots/img2.png
diff --git a/app/src/fdroid_full/play/listings/en-US/graphics/phone-screenshots/img3.png b/app/src/fdroid_full/fastlane/metadata/android/en-US/images/phoneScreenshots/img3.png
similarity index 100%
rename from app/src/fdroid_full/play/listings/en-US/graphics/phone-screenshots/img3.png
rename to app/src/fdroid_full/fastlane/metadata/android/en-US/images/phoneScreenshots/img3.png
diff --git a/app/src/fdroid_full/play/listings/en-US/graphics/phone-screenshots/img4.png b/app/src/fdroid_full/fastlane/metadata/android/en-US/images/phoneScreenshots/img4.png
similarity index 100%
rename from app/src/fdroid_full/play/listings/en-US/graphics/phone-screenshots/img4.png
rename to app/src/fdroid_full/fastlane/metadata/android/en-US/images/phoneScreenshots/img4.png
diff --git a/app/src/fdroid_full/play/listings/en-US/short-description.txt b/app/src/fdroid_full/fastlane/metadata/android/en-US/short_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/en-US/short-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/en-US/short_description.txt
diff --git a/app/src/fdroid_full/play/listings/en-US/title.txt b/app/src/fdroid_full/fastlane/metadata/android/en-US/title.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/en-US/title.txt
rename to app/src/fdroid_full/fastlane/metadata/android/en-US/title.txt
diff --git a/app/src/fdroid_full/play/listings/es/full-description.txt b/app/src/fdroid_full/fastlane/metadata/android/es/full_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/es/full-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/es/full_description.txt
diff --git a/app/src/fdroid_full/play/listings/es/short-description.txt b/app/src/fdroid_full/fastlane/metadata/android/es/short_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/es/short-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/es/short_description.txt
diff --git a/app/src/fdroid_full/play/listings/fr/full-description.txt b/app/src/fdroid_full/fastlane/metadata/android/fr/full_description.txt
similarity index 87%
rename from app/src/fdroid_full/play/listings/fr/full-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/fr/full_description.txt
index 5c74acd..efb3dbe 100644
--- a/app/src/fdroid_full/play/listings/fr/full-description.txt
+++ b/app/src/fdroid_full/fastlane/metadata/android/fr/full_description.txt
@@ -12,7 +12,7 @@ C'est un mode limité où vous pouvez faire certaines actions:
De nombreuses fonctionnalités sont disponibles avec ce mode:
- Rédiger/supprimer des commentaires
-- Télécharger/supprimer/modifier des vidéos
+- Téléverser/supprimer/modifier des vidéos
- Gérer (créer/modifier/supprimer) les chaînes et les listes de lecture
- Suivre/ne pas suivre les canaux
- Pouces vers le haut/vers le bas
diff --git a/app/src/fdroid_full/play/listings/fr/short-description.txt b/app/src/fdroid_full/fastlane/metadata/android/fr/short_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/fr/short-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/fr/short_description.txt
diff --git a/app/src/fdroid_full/play/listings/it/full-description.txt b/app/src/fdroid_full/fastlane/metadata/android/it/full_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/it/full-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/it/full_description.txt
diff --git a/app/src/fdroid_full/play/listings/it/short-description.txt b/app/src/fdroid_full/fastlane/metadata/android/it/short_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/it/short-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/it/short_description.txt
diff --git a/app/src/fdroid_full/play/listings/ca/full-description.txt b/app/src/fdroid_full/fastlane/metadata/android/ja/full_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/ca/full-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/ja/full_description.txt
diff --git a/app/src/fdroid_full/play/listings/ja/short-description.txt b/app/src/fdroid_full/fastlane/metadata/android/ja/short_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/ja/short-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/ja/short_description.txt
diff --git a/app/src/fdroid_full/play/listings/cs/full-description.txt b/app/src/fdroid_full/fastlane/metadata/android/ko/full_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/cs/full-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/ko/full_description.txt
diff --git a/app/src/fdroid_full/play/listings/ko/short-description.txt b/app/src/fdroid_full/fastlane/metadata/android/ko/short_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/ko/short-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/ko/short_description.txt
diff --git a/app/src/fdroid_full/play/listings/nl/full-description.txt b/app/src/fdroid_full/fastlane/metadata/android/nl/full_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/nl/full-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/nl/full_description.txt
diff --git a/app/src/fdroid_full/play/listings/nl/short-description.txt b/app/src/fdroid_full/fastlane/metadata/android/nl/short_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/nl/short-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/nl/short_description.txt
diff --git a/app/src/fdroid_full/play/listings/pl/full-description.txt b/app/src/fdroid_full/fastlane/metadata/android/pl/full_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/pl/full-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/pl/full_description.txt
diff --git a/app/src/fdroid_full/play/listings/pl/short-description.txt b/app/src/fdroid_full/fastlane/metadata/android/pl/short_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/pl/short-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/pl/short_description.txt
diff --git a/app/src/fdroid_full/play/listings/pt/full-description.txt b/app/src/fdroid_full/fastlane/metadata/android/pt/full_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/pt/full-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/pt/full_description.txt
diff --git a/app/src/fdroid_full/play/listings/pt/short-description.txt b/app/src/fdroid_full/fastlane/metadata/android/pt/short_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/pt/short-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/pt/short_description.txt
diff --git a/app/src/fdroid_full/play/listings/da/full-description.txt b/app/src/fdroid_full/fastlane/metadata/android/ro/full_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/da/full-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/ro/full_description.txt
diff --git a/app/src/fdroid_full/play/listings/ro/short-description.txt b/app/src/fdroid_full/fastlane/metadata/android/ro/short_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/ro/short-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/ro/short_description.txt
diff --git a/app/src/fdroid_full/play/listings/ru/full-description.txt b/app/src/fdroid_full/fastlane/metadata/android/ru/full_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/ru/full-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/ru/full_description.txt
diff --git a/app/src/fdroid_full/play/listings/ru/short-description.txt b/app/src/fdroid_full/fastlane/metadata/android/ru/short_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/ru/short-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/ru/short_description.txt
diff --git a/app/src/fdroid_full/play/listings/en-US/full-description.txt b/app/src/fdroid_full/fastlane/metadata/android/sv/full_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/en-US/full-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/sv/full_description.txt
diff --git a/app/src/fdroid_full/play/listings/sv/short-description.txt b/app/src/fdroid_full/fastlane/metadata/android/sv/short_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/sv/short-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/sv/short_description.txt
diff --git a/app/src/fdroid_full/play/listings/zh-rCN/full-description.txt b/app/src/fdroid_full/fastlane/metadata/android/zh-rCN/full_description.txt
similarity index 81%
rename from app/src/fdroid_full/play/listings/zh-rCN/full-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/zh-rCN/full_description.txt
index 96d1795..38553d9 100644
--- a/app/src/fdroid_full/play/listings/zh-rCN/full-description.txt
+++ b/app/src/fdroid_full/fastlane/metadata/android/zh-rCN/full_description.txt
@@ -1,6 +1,6 @@
*游客模式*
-此种受限模式下,您只能进行进行部分操作:
+在该模式下, 功能受到限制
• 切换实例
• 分享视频
diff --git a/app/src/fdroid_full/play/listings/zh-rCN/short-description.txt b/app/src/fdroid_full/fastlane/metadata/android/zh-rCN/short_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/zh-rCN/short-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/zh-rCN/short_description.txt
diff --git a/app/src/fdroid_full/play/listings/en/full-description.txt b/app/src/fdroid_full/fastlane/metadata/android/zh-rTW/full_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/en/full-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/zh-rTW/full_description.txt
diff --git a/app/src/fdroid_full/play/listings/zh-rTW/short-description.txt b/app/src/fdroid_full/fastlane/metadata/android/zh-rTW/short_description.txt
similarity index 100%
rename from app/src/fdroid_full/play/listings/zh-rTW/short-description.txt
rename to app/src/fdroid_full/fastlane/metadata/android/zh-rTW/short_description.txt
diff --git a/app/src/fdroid_full/play/listings/af/short-description.txt b/app/src/fdroid_full/play/listings/af/short-description.txt
deleted file mode 100644
index 1f0744b..0000000
--- a/app/src/fdroid_full/play/listings/af/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-TubeLab est une application Peertube pour les instances académiques.
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/ca/short-description.txt b/app/src/fdroid_full/play/listings/ca/short-description.txt
deleted file mode 100644
index 1f0744b..0000000
--- a/app/src/fdroid_full/play/listings/ca/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-TubeLab est une application Peertube pour les instances académiques.
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/cs/short-description.txt b/app/src/fdroid_full/play/listings/cs/short-description.txt
deleted file mode 100644
index 1f0744b..0000000
--- a/app/src/fdroid_full/play/listings/cs/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-TubeLab est une application Peertube pour les instances académiques.
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/da/short-description.txt b/app/src/fdroid_full/play/listings/da/short-description.txt
deleted file mode 100644
index 1f0744b..0000000
--- a/app/src/fdroid_full/play/listings/da/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-TubeLab est une application Peertube pour les instances académiques.
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/en/short-description.txt b/app/src/fdroid_full/play/listings/en/short-description.txt
deleted file mode 100644
index 1f0744b..0000000
--- a/app/src/fdroid_full/play/listings/en/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-TubeLab est une application Peertube pour les instances académiques.
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/fi/full-description.txt b/app/src/fdroid_full/play/listings/fi/full-description.txt
deleted file mode 100644
index fd254e1..0000000
--- a/app/src/fdroid_full/play/listings/fi/full-description.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-*Not authenticated mode*
-
-It's a limited mode where you can do some actions:
-
-- Switch instance,
-- Share videos,
-- Download videos.
-
-
-*Authenticated mode*
-
-Many features are available with this mode:
-
-- Write/delete comments
-- Upload/remove/edit videos
-- Manage (create/edit/remove) channels and playlists
-- Follow/unfollow channels
-- Thumbs-up/down
-- Check notifications
-- Mute/unmute channels
-- Report videos/accounts
-- Check your history
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/fi/short-description.txt b/app/src/fdroid_full/play/listings/fi/short-description.txt
deleted file mode 100644
index 1f0744b..0000000
--- a/app/src/fdroid_full/play/listings/fi/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-TubeLab est une application Peertube pour les instances académiques.
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/he/full-description.txt b/app/src/fdroid_full/play/listings/he/full-description.txt
deleted file mode 100644
index fd254e1..0000000
--- a/app/src/fdroid_full/play/listings/he/full-description.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-*Not authenticated mode*
-
-It's a limited mode where you can do some actions:
-
-- Switch instance,
-- Share videos,
-- Download videos.
-
-
-*Authenticated mode*
-
-Many features are available with this mode:
-
-- Write/delete comments
-- Upload/remove/edit videos
-- Manage (create/edit/remove) channels and playlists
-- Follow/unfollow channels
-- Thumbs-up/down
-- Check notifications
-- Mute/unmute channels
-- Report videos/accounts
-- Check your history
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/he/short-description.txt b/app/src/fdroid_full/play/listings/he/short-description.txt
deleted file mode 100644
index 1f0744b..0000000
--- a/app/src/fdroid_full/play/listings/he/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-TubeLab est une application Peertube pour les instances académiques.
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/hu/full-description.txt b/app/src/fdroid_full/play/listings/hu/full-description.txt
deleted file mode 100644
index fd254e1..0000000
--- a/app/src/fdroid_full/play/listings/hu/full-description.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-*Not authenticated mode*
-
-It's a limited mode where you can do some actions:
-
-- Switch instance,
-- Share videos,
-- Download videos.
-
-
-*Authenticated mode*
-
-Many features are available with this mode:
-
-- Write/delete comments
-- Upload/remove/edit videos
-- Manage (create/edit/remove) channels and playlists
-- Follow/unfollow channels
-- Thumbs-up/down
-- Check notifications
-- Mute/unmute channels
-- Report videos/accounts
-- Check your history
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/hu/short-description.txt b/app/src/fdroid_full/play/listings/hu/short-description.txt
deleted file mode 100644
index 1f0744b..0000000
--- a/app/src/fdroid_full/play/listings/hu/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-TubeLab est une application Peertube pour les instances académiques.
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/ja/full-description.txt b/app/src/fdroid_full/play/listings/ja/full-description.txt
deleted file mode 100644
index fd254e1..0000000
--- a/app/src/fdroid_full/play/listings/ja/full-description.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-*Not authenticated mode*
-
-It's a limited mode where you can do some actions:
-
-- Switch instance,
-- Share videos,
-- Download videos.
-
-
-*Authenticated mode*
-
-Many features are available with this mode:
-
-- Write/delete comments
-- Upload/remove/edit videos
-- Manage (create/edit/remove) channels and playlists
-- Follow/unfollow channels
-- Thumbs-up/down
-- Check notifications
-- Mute/unmute channels
-- Report videos/accounts
-- Check your history
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/ko/full-description.txt b/app/src/fdroid_full/play/listings/ko/full-description.txt
deleted file mode 100644
index fd254e1..0000000
--- a/app/src/fdroid_full/play/listings/ko/full-description.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-*Not authenticated mode*
-
-It's a limited mode where you can do some actions:
-
-- Switch instance,
-- Share videos,
-- Download videos.
-
-
-*Authenticated mode*
-
-Many features are available with this mode:
-
-- Write/delete comments
-- Upload/remove/edit videos
-- Manage (create/edit/remove) channels and playlists
-- Follow/unfollow channels
-- Thumbs-up/down
-- Check notifications
-- Mute/unmute channels
-- Report videos/accounts
-- Check your history
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/no/full-description.txt b/app/src/fdroid_full/play/listings/no/full-description.txt
deleted file mode 100644
index fd254e1..0000000
--- a/app/src/fdroid_full/play/listings/no/full-description.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-*Not authenticated mode*
-
-It's a limited mode where you can do some actions:
-
-- Switch instance,
-- Share videos,
-- Download videos.
-
-
-*Authenticated mode*
-
-Many features are available with this mode:
-
-- Write/delete comments
-- Upload/remove/edit videos
-- Manage (create/edit/remove) channels and playlists
-- Follow/unfollow channels
-- Thumbs-up/down
-- Check notifications
-- Mute/unmute channels
-- Report videos/accounts
-- Check your history
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/no/short-description.txt b/app/src/fdroid_full/play/listings/no/short-description.txt
deleted file mode 100644
index 1f0744b..0000000
--- a/app/src/fdroid_full/play/listings/no/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-TubeLab est une application Peertube pour les instances académiques.
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/ro/full-description.txt b/app/src/fdroid_full/play/listings/ro/full-description.txt
deleted file mode 100644
index fd254e1..0000000
--- a/app/src/fdroid_full/play/listings/ro/full-description.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-*Not authenticated mode*
-
-It's a limited mode where you can do some actions:
-
-- Switch instance,
-- Share videos,
-- Download videos.
-
-
-*Authenticated mode*
-
-Many features are available with this mode:
-
-- Write/delete comments
-- Upload/remove/edit videos
-- Manage (create/edit/remove) channels and playlists
-- Follow/unfollow channels
-- Thumbs-up/down
-- Check notifications
-- Mute/unmute channels
-- Report videos/accounts
-- Check your history
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/sr/full-description.txt b/app/src/fdroid_full/play/listings/sr/full-description.txt
deleted file mode 100644
index fd254e1..0000000
--- a/app/src/fdroid_full/play/listings/sr/full-description.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-*Not authenticated mode*
-
-It's a limited mode where you can do some actions:
-
-- Switch instance,
-- Share videos,
-- Download videos.
-
-
-*Authenticated mode*
-
-Many features are available with this mode:
-
-- Write/delete comments
-- Upload/remove/edit videos
-- Manage (create/edit/remove) channels and playlists
-- Follow/unfollow channels
-- Thumbs-up/down
-- Check notifications
-- Mute/unmute channels
-- Report videos/accounts
-- Check your history
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/sr/short-description.txt b/app/src/fdroid_full/play/listings/sr/short-description.txt
deleted file mode 100644
index 1f0744b..0000000
--- a/app/src/fdroid_full/play/listings/sr/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-TubeLab est une application Peertube pour les instances académiques.
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/sv/full-description.txt b/app/src/fdroid_full/play/listings/sv/full-description.txt
deleted file mode 100644
index fd254e1..0000000
--- a/app/src/fdroid_full/play/listings/sv/full-description.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-*Not authenticated mode*
-
-It's a limited mode where you can do some actions:
-
-- Switch instance,
-- Share videos,
-- Download videos.
-
-
-*Authenticated mode*
-
-Many features are available with this mode:
-
-- Write/delete comments
-- Upload/remove/edit videos
-- Manage (create/edit/remove) channels and playlists
-- Follow/unfollow channels
-- Thumbs-up/down
-- Check notifications
-- Mute/unmute channels
-- Report videos/accounts
-- Check your history
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/tr/full-description.txt b/app/src/fdroid_full/play/listings/tr/full-description.txt
deleted file mode 100644
index fd254e1..0000000
--- a/app/src/fdroid_full/play/listings/tr/full-description.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-*Not authenticated mode*
-
-It's a limited mode where you can do some actions:
-
-- Switch instance,
-- Share videos,
-- Download videos.
-
-
-*Authenticated mode*
-
-Many features are available with this mode:
-
-- Write/delete comments
-- Upload/remove/edit videos
-- Manage (create/edit/remove) channels and playlists
-- Follow/unfollow channels
-- Thumbs-up/down
-- Check notifications
-- Mute/unmute channels
-- Report videos/accounts
-- Check your history
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/tr/short-description.txt b/app/src/fdroid_full/play/listings/tr/short-description.txt
deleted file mode 100644
index 1f0744b..0000000
--- a/app/src/fdroid_full/play/listings/tr/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-TubeLab est une application Peertube pour les instances académiques.
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/uk/full-description.txt b/app/src/fdroid_full/play/listings/uk/full-description.txt
deleted file mode 100644
index fd254e1..0000000
--- a/app/src/fdroid_full/play/listings/uk/full-description.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-*Not authenticated mode*
-
-It's a limited mode where you can do some actions:
-
-- Switch instance,
-- Share videos,
-- Download videos.
-
-
-*Authenticated mode*
-
-Many features are available with this mode:
-
-- Write/delete comments
-- Upload/remove/edit videos
-- Manage (create/edit/remove) channels and playlists
-- Follow/unfollow channels
-- Thumbs-up/down
-- Check notifications
-- Mute/unmute channels
-- Report videos/accounts
-- Check your history
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/uk/short-description.txt b/app/src/fdroid_full/play/listings/uk/short-description.txt
deleted file mode 100644
index 1f0744b..0000000
--- a/app/src/fdroid_full/play/listings/uk/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-TubeLab est une application Peertube pour les instances académiques.
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/vi/full-description.txt b/app/src/fdroid_full/play/listings/vi/full-description.txt
deleted file mode 100644
index fd254e1..0000000
--- a/app/src/fdroid_full/play/listings/vi/full-description.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-*Not authenticated mode*
-
-It's a limited mode where you can do some actions:
-
-- Switch instance,
-- Share videos,
-- Download videos.
-
-
-*Authenticated mode*
-
-Many features are available with this mode:
-
-- Write/delete comments
-- Upload/remove/edit videos
-- Manage (create/edit/remove) channels and playlists
-- Follow/unfollow channels
-- Thumbs-up/down
-- Check notifications
-- Mute/unmute channels
-- Report videos/accounts
-- Check your history
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/vi/short-description.txt b/app/src/fdroid_full/play/listings/vi/short-description.txt
deleted file mode 100644
index 1f0744b..0000000
--- a/app/src/fdroid_full/play/listings/vi/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-TubeLab est une application Peertube pour les instances académiques.
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/listings/zh-rTW/full-description.txt b/app/src/fdroid_full/play/listings/zh-rTW/full-description.txt
deleted file mode 100644
index fd254e1..0000000
--- a/app/src/fdroid_full/play/listings/zh-rTW/full-description.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-*Not authenticated mode*
-
-It's a limited mode where you can do some actions:
-
-- Switch instance,
-- Share videos,
-- Download videos.
-
-
-*Authenticated mode*
-
-Many features are available with this mode:
-
-- Write/delete comments
-- Upload/remove/edit videos
-- Manage (create/edit/remove) channels and playlists
-- Follow/unfollow channels
-- Thumbs-up/down
-- Check notifications
-- Mute/unmute channels
-- Report videos/accounts
-- Check your history
\ No newline at end of file
diff --git a/app/src/fdroid_full/play/release-notes/en-US/default.txt b/app/src/fdroid_full/play/release-notes/en-US/default.txt
deleted file mode 100644
index b010cef..0000000
--- a/app/src/fdroid_full/play/release-notes/en-US/default.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-Added:
-- Display follow button for Sepia Search
-- Reach owner from channels
-- Surfing mode (store instances in db with quick switch)
-- Allow to delete history
-
-Changed:
-- Quicker access to account settings
-- Improve landscape mode
-
-Fix:
-- Pull to refresh crashes
-- Settings crashes
-- Fix an issue with unlisted playlists
\ No newline at end of file
diff --git a/app/src/full/res/drawable-anydpi-v24/ic_notification_tubelab.xml b/app/src/full/res/drawable-anydpi-v24/ic_notification_tubelab.xml
new file mode 100644
index 0000000..4caaeda
--- /dev/null
+++ b/app/src/full/res/drawable-anydpi-v24/ic_notification_tubelab.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/app/src/full/res/drawable-hdpi/ic_notification_tubelab.png b/app/src/full/res/drawable-hdpi/ic_notification_tubelab.png
new file mode 100644
index 0000000..27f4dd8
Binary files /dev/null and b/app/src/full/res/drawable-hdpi/ic_notification_tubelab.png differ
diff --git a/app/src/full/res/drawable-mdpi/ic_notification_tubelab.png b/app/src/full/res/drawable-mdpi/ic_notification_tubelab.png
new file mode 100644
index 0000000..d7cd8a2
Binary files /dev/null and b/app/src/full/res/drawable-mdpi/ic_notification_tubelab.png differ
diff --git a/app/src/full/res/drawable-xhdpi/ic_notification_tubelab.png b/app/src/full/res/drawable-xhdpi/ic_notification_tubelab.png
new file mode 100644
index 0000000..8633430
Binary files /dev/null and b/app/src/full/res/drawable-xhdpi/ic_notification_tubelab.png differ
diff --git a/app/src/full/res/drawable-xxhdpi/ic_notification_tubelab.png b/app/src/full/res/drawable-xxhdpi/ic_notification_tubelab.png
new file mode 100644
index 0000000..e9879d9
Binary files /dev/null and b/app/src/full/res/drawable-xxhdpi/ic_notification_tubelab.png differ
diff --git a/app/src/full/res/drawable-xxxhdpi/ic_notification_tubelab.png b/app/src/full/res/drawable-xxxhdpi/ic_notification_tubelab.png
new file mode 100644
index 0000000..21a32b0
Binary files /dev/null and b/app/src/full/res/drawable-xxxhdpi/ic_notification_tubelab.png differ
diff --git a/app/src/full/res/values-fr/strings.xml b/app/src/full/res/values-fr/strings.xml
deleted file mode 100644
index 008b24a..0000000
--- a/app/src/full/res/values-fr/strings.xml
+++ /dev/null
@@ -1,326 +0,0 @@
-
-
- Videos in list
- Change the layout for displaying videos in a list
- No instances !
- Show more
- Show less
- Screen lock
- Keep playing videos when the screen is locked
- Save
- Enable history
- Change profile picture
- Automatic playback
- If enabled, videos will be played automatically
- Fullscreen
- Automatically open videos in fullscreen
- Automatically start playing the next video
- When a video ends, follow up with the next suggested video.
- Ajouter une réponse publique
- Activity
- App
- New video from your subscriptions
- New comment on your video
- One of your video is blocked/unblocked
- Video published (after transcoding/scheduled update)
- Video import finished
- You or your channel(s) has a new follower
- Someone mentioned you in video comments
- An abuse report received a new message
- One of your abuse reports has been accepted or rejected by moderators
-
- - %d réponse
- - %d réponses
-
- Réponse
- Thème
- Permet de changer le thème de l\'application
- La vidéo ne peut pas être fédérée !
- Locale
- Locale
- Découvrir
- Notifications
- Nouveautés
- Tendances
- Plus aimées
- Une erreur s\'est produite !
- Sourdine
- Chaînes
- Ne pas lister
- Estomper
- Afficher
- Pas d\'opinion
- Choisissez une instance
- Cette instance ne semble pas être valide !
- Aucune vidéo !
- Aucune notification !
- Favicon
- Ouvrir avec
- Modifier une liste de lecture
- Fermer
- Téléverser
- Aperçu de l\'image
- Sélectionnez un fichier à transférer
- New video
- New blacklist info
- Your video is published
- Error when publishing your video
- New comment
- New follow
- Chaîne
- Vidéos
- Chaînes
- Fetch every:
-
- - Never
- - 15 minutes
- - 30 minutes
- - 1 hour
- - 2 hours
- - 6 hours
- - 12 hours
-
- Oui
- Non
- Annuler
- Télécharger
- Photo du profil
- Mettre à jour la vidéo
- Supprimer de la liste de lecture
- %d s
- %d min
- %d h
- %d j
- %s vues
- Domaine de l\'instance
- Transfert en cours, veuillez patienter …
- La vidéo a été transférée !
- Transfert annulé !
- Cliquez ici pour éditer les données de la vidéo.
- Une erreur s’est produite lors de la sélection du média !
- Télécharger %1$s
- The account has been updated!
- Confidentialité
- Déconnexion
- Connexion
- Mot de passe
- Courriel
- Étiquettes
- Valider
- Partager avec
- Partagé via TubeLab
- Nom d’utilisateur
- Paramètres
- Voulez-vous vraiment déconnecter le compte @%1$s@%2$s ?
- Suit
- Abonné·e·s
- Impossible d’obtenir l’id du client !
- Une erreur s’est produite pendant le chargement du compte !
- Une erreur s’est produite lors de la recherche !
- Aucune action ne peut être réalisée
- S\'abonner
- Mettre en sourdine
- Chercher
- Supprimer
- Êtes-vous sûr de vouloir supprimer définitivement cette liste de lecture ?
- Supprimer la liste de lecture
- Soyez le·a premier·ère à laisser un commentaire sur cette vidéo en utilisant le bouton supérieur droit !
- Les commentaires sur cette vidéos ont été désactivés !
- Choisissez une résolution
- La vidéo est rajoutée aux favoris !
- La vidéo a été retirée de vos favoris !
- Information
- Logo de l’application
-
- Abonnements
- Delete an instance
- Are you sure to delete this instance?
- Supprimer le commentaire
- Etes-vous sûr de vouloir supprimer ce commentaire ?
- Mode pour les vidéos
- Filtrer
- Recherche sépia
- Afficher le contenu sensible
- Date de publication
- Toutes
- Aujourd\'hui
- Les 7 derniers jours
- Les 30 derniers jours
- Les 365 derniers jours
- Durée
-
-
- 10 min)]]>
- Afficher toutes les catégories
- Afficher toutes les licences
- Afficher toutes les langues
- Tous ces labels
- Un de ces labels
- Appliquer le filtre
-
- - Meilleurs résultats
- - Les plus récentes
- - Les moins récentes
-
- Trier par
- Mot-clé, chaîne, vidéo, etc.
- La recherche Sepia affiche les vidéos et les chaînes qui correspondent à votre recherche mais qui n\'est pas l\'éditeur, ni le propriétaire. Si vous remarquez des problèmes avec une vidéo, signalez-la aux administrateurs sur le site Web de PeerTube où la vidéo est publiée.
- Mes vidéos
- Titre
- Licence
- Catégorie
- Langue
- Cette vidéo contient du contenu pour adultes
- Activer les commentaires
- Libellé
- La vidéo a été mise à jour !
- Créer un compte
- Adresse mèl
- Aperçu
- Modifier l\'aperçu
- Nom
- Afficher plus
- Aucune chaîne !
- Quelques explications concernant votre signalement…
- Signaler la vidéo
- Signaler
- Changer d\'instance
- Historique
- Modifier
- Réglages des vidéos
- Interface
- Cache
- Définir le cache pour les vidéos (par défaut 100Mo)
- Définir une qualité par défaut pour les vidéos
- Résolution pour les vidéos
- Cache vidéo : %d Mo
- Légendes
- Options d\'envoi
- Aucune
- Permet de changer le mode de lecture pour les vidéos (normal, streaming ou via un navigateur).
- Supprimer les commentaires du compte
- Êtes-vous sûr de vouloir supprimer tous les commentaires de ce compte ?
- Supprimer la vidéo
- Êtes-vous sûr de vouloir supprimer cette vidéo ?
- Aucune vidéo n’est disponible !
- Partager
- %1$s a commenté votre vidéo %2$s]]>
- %1$s suit votre chaîne %2$s]]>
- %1$s suit votre compte]]>
- %1$s a été publiée]]>
- %1$s a réussi]]>
- %1$s]]>
- %1$s a publié une nouvelle vidéo : %2$s]]>
- %1$s a été blacklisté]]>
- %1$s n’est plus blacklisté]]>
- %1$s has been accepted]]>
- %1$s]]>
- Ajouter un commentaire public
- Envoyer un commentaire
- Tout
-
- Delete videos history
- Are you sure you want to delete all your videos history?
- Export
- Import
- Successful export!
- Tap here to send the export by email
- New Playlist
- Open the attached file with TubeLab
- Listes de lecture
- No playlists
- Nom d\'affichage
- Vous n\'avez aucune liste de lecture. Cliquez sur l\'icône « + » pour en ajouter une
- Vous devez fournir un nom d\'affichage !
- Une chaîne est requise lorsque la liste de lecture est publique.
- Créer une liste de lecture
- Cette liste de lecture est vide.
- Confirmer le mot de passe
- J\'accepte les %1$s et les %2$s
- règles du serveur
- conditions de service
- S’inscrire
- Veuillez remplir tous les champs !
- Les mots de passe ne sont pas identiques !
- L\'e-mail ne semble pas être valide !
- Vous recevrez un e-mail de confirmation
- Utilisez au moins 8 caractères
- Le mot de passe doit contenir au moins 8 caractères
- Le nom d\'utilisateur·rice doit être en minuscule, contenir uniquement des lettres, des chiffres, des points et des caractères de soulignement
- Compte créé !
- Votre compte est créé !\n\nVous allez recevoir un email de confirmation à l\'adresse %1$s.\n\nCliquez sur le lien présent dans le mail pour valider votre compte.
- Compte
- Signaler le compte
-
- - Normal
- - Streaming
- - Magnet
- - Torrent
-
-
- - Lumière
- - Foncé
- - Automatique
-
-
- - Élevée
- - Moyenne
- - Faible
-
- Voulez-vous vous désabonner de ce compte ?
- Titre de la vidéo
- Rejoignez Peertube
- J\'ai au moins 16 ans et je suis d\'accord avec les %1$s de cette instance
- Éditer le profil
- Faire une action
- Se désabonner
- Afficher les vidéos sensibles
- Vidéo plein écran
- Il n’y a aucune vidéo Peertube dans vos favoris !
- Supprimer la chaîne
- Êtes-vous sûr de vouloir supprimer définitivement cette chaîne ?
- Vidéo dans les listes de lecture
- Aucun compte en sourdine !
- Vous devez fournir un nom d\'affichage et un nom pour la chaîne!
- Créer une chaîne
- Modifier une chaîne
- Les adresses mails %1$s ne sont pas autorisées !
- Veuillez préciser les raisons.
- Vous devez être connecté.e pour effectuer cette action !
- Le compte a été signalé !
- Le commentaire a été signalé !
- La vidéo a été signalée !
- Le mot de passe doit contenir 6 caractères !
- Le compte a été mis en sourdine !
- Modifier une vidéo
- Créer un compte
- %1$s Abonné·e·s
- Développeur
- Version %1$s
- À propos de l’application
- Faire un don
- Code source
- Suivi des tickets
- Aucune instance ne correspond à ces critères
- Sélecteur d\'instances
- Choisissez une instance
- Vidéos sensibles
- Contenu sensible : %1$s
- %1$s instances suiveuses
- Aide
- Sélection des catégories
- Sélection des langues
- Mise à jour des informations
- Fetch notifications
- Ajouter un compte
- Liste des comptes
- Pause
- Jouer
- Minimiser
- Rembobinage rapide
- Avance rapide
- Minimiser la taille des vidéos
- Minimiser la taille des vidéos lorsque l\'application est en arrière-plan (Android N+)
- Filtre de langue
- Filtrer les vidéos avec différentes langues
-
diff --git a/app/src/full/res/values/colors.xml b/app/src/full/res/values/colors.xml
index 2547404..8d944f0 100644
--- a/app/src/full/res/values/colors.xml
+++ b/app/src/full/res/values/colors.xml
@@ -7,6 +7,7 @@
#FAFAFA
#2b90d9
#F44336
-
+ #DD000000
#F44336
+ #80808080
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c55b5a0..bbfff94 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -157,13 +157,6 @@
-
-
-
-
-
{
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.paypal.me/Mastalab"));
startActivity(browserIntent);
});
+ if (BuildConfig.FLAVOR.equals("queermotion")) {
+ donatePaypal.setVisibility(View.GONE);
+ LinearLayout dev_info = findViewById(R.id.dev_info);
+ dev_info.setVisibility(View.GONE);
+ }
Button donateLiberapay = findViewById(R.id.donate_liberapay);
donateLiberapay.setOnClickListener(v -> {
- Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://liberapay.com/tom79"));
+ Intent browserIntent;
+ if (BuildConfig.FLAVOR.equals("queermotion")) {
+ browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://soutenir.queermotion.org"));
+ } else {
+ browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://liberapay.com/tom79"));
+ }
+
startActivity(browserIntent);
});
diff --git a/app/src/main/java/app/fedilab/fedilabtube/AllPlaylistsActivity.java b/app/src/main/java/app/fedilab/fedilabtube/AllPlaylistsActivity.java
index 3fb4710..5dd526b 100644
--- a/app/src/main/java/app/fedilab/fedilabtube/AllPlaylistsActivity.java
+++ b/app/src/main/java/app/fedilab/fedilabtube/AllPlaylistsActivity.java
@@ -14,7 +14,12 @@ package app.fedilab.fedilabtube;
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
* see . */
+import android.Manifest;
+import android.app.Activity;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -27,19 +32,19 @@ import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
-import android.widget.Spinner;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.app.ActivityCompat;
+import androidx.core.content.ContextCompat;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-import com.google.android.material.floatingactionbutton.FloatingActionButton;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.resource.bitmap.CenterCrop;
+import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
+import com.bumptech.glide.request.RequestOptions;
import java.util.ArrayList;
import java.util.HashMap;
@@ -54,52 +59,53 @@ import app.fedilab.fedilabtube.client.data.ChannelData;
import app.fedilab.fedilabtube.client.data.PlaylistData.Playlist;
import app.fedilab.fedilabtube.client.entities.Item;
import app.fedilab.fedilabtube.client.entities.PlaylistParams;
+import app.fedilab.fedilabtube.databinding.ActivityAllPlaylistBinding;
+import app.fedilab.fedilabtube.databinding.AddPlaylistBinding;
import app.fedilab.fedilabtube.drawer.PlaylistAdapter;
+import app.fedilab.fedilabtube.helper.Helper;
import app.fedilab.fedilabtube.viewmodel.ChannelsVM;
import app.fedilab.fedilabtube.viewmodel.PlaylistsVM;
import es.dmoral.toasty.Toasty;
-import static app.fedilab.fedilabtube.MainActivity.peertubeInformation;
+import static app.fedilab.fedilabtube.PeertubeUploadActivity.MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE;
+import static app.fedilab.fedilabtube.helper.Helper.peertubeInformation;
public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistAdapter.AllPlaylistRemoved {
PlaylistAdapter playlistAdapter;
- private RelativeLayout mainLoader;
- private RelativeLayout textviewNoAction;
private HashMap privacyToSend;
- private Spinner set_upload_channel;
- private Spinner set_upload_privacy;
private String idChannel;
private List playlists;
private Playlist playlistToEdit;
private List myChannels;
private ChannelData.Channel selectedChannel;
+ private static final int PICK_AVATAR = 467;
+ private AddPlaylistBinding bindingDialog;
+ private Uri inputData;
+ private ActivityAllPlaylistBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_all_playlist);
+ binding = ActivityAllPlaylistBinding.inflate(getLayoutInflater());
+ View viewRoot = binding.getRoot();
+ setContentView(viewRoot);
if (getSupportActionBar() != null)
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setTitle(R.string.playlists);
- textviewNoAction = findViewById(R.id.no_action);
- mainLoader = findViewById(R.id.loader);
- RelativeLayout nextElementLoader = findViewById(R.id.loading_next_items);
- mainLoader.setVisibility(View.VISIBLE);
- nextElementLoader.setVisibility(View.GONE);
+ binding.loader.setVisibility(View.VISIBLE);
+ binding.loadingNextItems.setVisibility(View.GONE);
idChannel = null;
PlaylistsVM viewModel = new ViewModelProvider(AllPlaylistsActivity.this).get(PlaylistsVM.class);
viewModel.manage(PlaylistsVM.action.GET_PLAYLISTS, null, null).observe(AllPlaylistsActivity.this, apiResponse -> manageVIewPlaylists(PlaylistsVM.action.GET_PLAYLISTS, apiResponse));
- FloatingActionButton add_new = findViewById(R.id.add_new);
-
LinkedHashMap privaciesInit = new LinkedHashMap<>(peertubeInformation.getPrivacies());
if (privaciesInit.size() > 0) {
@@ -110,13 +116,12 @@ public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistA
playlists = new ArrayList<>();
- RecyclerView lv_playlist = findViewById(R.id.lv_playlist);
playlistAdapter = new PlaylistAdapter(playlists, false);
playlistAdapter.allPlaylistRemoved = this;
- lv_playlist.setAdapter(playlistAdapter);
+ binding.lvPlaylist.setAdapter(playlistAdapter);
LinearLayoutManager mLayoutManager = new LinearLayoutManager(AllPlaylistsActivity.this);
- lv_playlist.setLayoutManager(mLayoutManager);
- add_new.setOnClickListener(view -> manageAlert(null));
+ binding.lvPlaylist.setLayoutManager(mLayoutManager);
+ binding.addNew.setOnClickListener(view -> manageAlert(null));
}
@Override
@@ -135,7 +140,7 @@ public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistA
public void manageVIewPlaylists(PlaylistsVM.action actionType, APIResponse apiResponse) {
- mainLoader.setVisibility(View.GONE);
+ binding.loader.setVisibility(View.GONE);
if (apiResponse.getError() != null) {
Toasty.error(AllPlaylistsActivity.this, apiResponse.getError().getError(), Toast.LENGTH_LONG).show();
return;
@@ -144,9 +149,9 @@ public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistA
if (apiResponse.getPlaylists() != null && apiResponse.getPlaylists().size() > 0) {
playlists.addAll(apiResponse.getPlaylists());
playlistAdapter.notifyDataSetChanged();
- textviewNoAction.setVisibility(View.GONE);
+ binding.noAction.setVisibility(View.GONE);
} else {
- textviewNoAction.setVisibility(View.VISIBLE);
+ binding.noAction.setVisibility(View.VISIBLE);
}
}
}
@@ -155,37 +160,53 @@ public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistA
playlistToEdit = playlistParam;
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(AllPlaylistsActivity.this);
- LayoutInflater inflater1 = getLayoutInflater();
- View dialogView = inflater1.inflate(R.layout.add_playlist, new LinearLayout(AllPlaylistsActivity.this), false);
- dialogBuilder.setView(dialogView);
- EditText display_name = dialogView.findViewById(R.id.display_name);
- EditText description = dialogView.findViewById(R.id.description);
- set_upload_channel = dialogView.findViewById(R.id.set_upload_channel);
- set_upload_privacy = dialogView.findViewById(R.id.set_upload_privacy);
+ bindingDialog = AddPlaylistBinding.inflate(LayoutInflater.from(AllPlaylistsActivity.this), null, false);
+ dialogBuilder.setView(bindingDialog.getRoot());
+
+ dialogBuilder.setView(bindingDialog.getRoot());
+
ChannelsVM viewModelC = new ViewModelProvider(AllPlaylistsActivity.this).get(ChannelsVM.class);
viewModelC.get(RetrofitPeertubeAPI.DataType.MY_CHANNELS, null).observe(AllPlaylistsActivity.this, this::manageVIewChannels);
- display_name.setFilters(new InputFilter[]{new InputFilter.LengthFilter(120)});
- description.setFilters(new InputFilter[]{new InputFilter.LengthFilter(1000)});
+ bindingDialog.displayName.setFilters(new InputFilter[]{new InputFilter.LengthFilter(120)});
+ bindingDialog.description.setFilters(new InputFilter[]{new InputFilter.LengthFilter(1000)});
if (playlistToEdit != null) {
- display_name.setText(playlistToEdit.getDisplayName());
- description.setText(playlistToEdit.getDescription());
+ bindingDialog.displayName.setText(playlistToEdit.getDisplayName());
+ bindingDialog.description.setText(playlistToEdit.getDescription());
}
dialogBuilder.setPositiveButton(R.string.validate, null);
dialogBuilder.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss());
AlertDialog alertDialog = dialogBuilder.create();
+
+ bindingDialog.selectFile.setOnClickListener(v -> {
+ if (ContextCompat.checkSelfPermission(AllPlaylistsActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) !=
+ PackageManager.PERMISSION_GRANTED) {
+ ActivityCompat.requestPermissions(AllPlaylistsActivity.this,
+ new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
+ MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
+ return;
+ }
+
+ Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("*/*");
+ String[] mimetypes = {"image/*"};
+ intent.putExtra(Intent.EXTRA_MIME_TYPES, mimetypes);
+ startActivityForResult(intent, PICK_AVATAR);
+ });
+ Helper.loadGiF(AllPlaylistsActivity.this, playlistParam != null ? playlistParam.getThumbnailPath() : null, bindingDialog.profilePicture);
alertDialog.setOnShowListener(dialogInterface -> {
Button button = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
button.setOnClickListener(view -> {
- if (display_name.getText() != null && display_name.getText().toString().trim().length() > 0) {
+ if (bindingDialog.displayName.getText() != null && bindingDialog.displayName.getText().toString().trim().length() > 0) {
PlaylistParams playlistElement = new PlaylistParams();
- playlistElement.setDisplayName(display_name.getText().toString().trim());
- if (description.getText() != null && description.getText().toString().trim().length() > 0) {
- playlistElement.setDescription(description.getText().toString().trim());
+ playlistElement.setDisplayName(bindingDialog.displayName.getText().toString().trim());
+ if (bindingDialog.description.getText() != null && bindingDialog.description.getText().toString().trim().length() > 0) {
+ playlistElement.setDescription(bindingDialog.description.getText().toString().trim());
}
playlistElement.setVideoChannelId(idChannel);
String label;
@@ -203,11 +224,11 @@ public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistA
new Thread(() -> {
String playlistId;
if (playlistToEdit == null) {
- APIResponse apiResponse = new RetrofitPeertubeAPI(AllPlaylistsActivity.this).createOrUpdatePlaylist(PlaylistsVM.action.CREATE_PLAYLIST, null, playlistElement, null);
+ APIResponse apiResponse = new RetrofitPeertubeAPI(AllPlaylistsActivity.this).createOrUpdatePlaylist(PlaylistsVM.action.CREATE_PLAYLIST, null, playlistElement, inputData);
playlistId = apiResponse.getActionReturn();
} else {
playlistId = playlistToEdit.getId();
- new RetrofitPeertubeAPI(AllPlaylistsActivity.this).createOrUpdatePlaylist(PlaylistsVM.action.UPDATE_PLAYLIST, playlistId, playlistElement, null);
+ new RetrofitPeertubeAPI(AllPlaylistsActivity.this).createOrUpdatePlaylist(PlaylistsVM.action.UPDATE_PLAYLIST, playlistId, playlistElement, inputData);
}
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> {
@@ -247,7 +268,7 @@ public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistA
//Hide keyboard
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
assert imm != null;
- imm.hideSoftInputFromWindow(display_name.getWindowToken(), 0);
+ imm.hideSoftInputFromWindow(bindingDialog.displayName.getWindowToken(), 0);
});
if (alertDialog.getWindow() != null)
alertDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
@@ -255,6 +276,24 @@ public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistA
}
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (requestCode == PICK_AVATAR && resultCode == Activity.RESULT_OK) {
+ if (data == null || data.getData() == null) {
+ Toasty.error(AllPlaylistsActivity.this, getString(R.string.toot_select_image_error), Toast.LENGTH_LONG).show();
+ return;
+ }
+ inputData = data.getData();
+ Glide.with(AllPlaylistsActivity.this)
+ .load(inputData)
+ .thumbnail(0.1f)
+ .apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners(10)))
+ .into(bindingDialog.profilePicture);
+
+ }
+ }
+
public void manageVIewChannels(APIResponse apiResponse) {
if (apiResponse.getError() != null || apiResponse.getChannels() == null || apiResponse.getChannels().size() == 0) {
if (apiResponse.getError() != null && apiResponse.getError().getError() != null)
@@ -280,7 +319,7 @@ public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistA
ArrayAdapter adapterChannel = new ArrayAdapter<>(AllPlaylistsActivity.this,
android.R.layout.simple_spinner_dropdown_item, channelName);
- set_upload_channel.setAdapter(adapterChannel);
+ bindingDialog.setUploadChannel.setAdapter(adapterChannel);
LinkedHashMap translations = null;
@@ -308,19 +347,19 @@ public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistA
ArrayAdapter adapterPrivacies = new ArrayAdapter<>(AllPlaylistsActivity.this,
android.R.layout.simple_spinner_dropdown_item, privaciesA);
- set_upload_privacy.setAdapter(adapterPrivacies);
+ bindingDialog.setUploadPrivacy.setAdapter(adapterPrivacies);
if (playlistToEdit != null) {
Item privacy = playlistToEdit.getPrivacy();
if (privacy.getId() > 0) {
- set_upload_privacy.setSelection(privacy.getId() - 1);
+ bindingDialog.setUploadPrivacy.setSelection(privacy.getId() - 1);
}
} else {
- set_upload_privacy.setSelection(2);
+ bindingDialog.setUploadPrivacy.setSelection(2);
}
//Manage privacies
- set_upload_privacy.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ bindingDialog.setUploadPrivacy.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view, int position, long id) {
LinkedHashMap privaciesCheck = new LinkedHashMap<>(peertubeInformation.getPrivacies());
@@ -348,12 +387,12 @@ public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistA
Item privacy = playlistToEdit.getPrivacy();
if (privacy.getId() > 0) {
- set_upload_privacy.setSelection(privacy.getId() - 1);
+ bindingDialog.setUploadPrivacy.setSelection(privacy.getId() - 1);
}
}
//Manage languages
- set_upload_channel.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ bindingDialog.setUploadChannel.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view, int position, long id) {
idChannel = channelId[position];
@@ -378,12 +417,12 @@ public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistA
}
k++;
}
- set_upload_channel.setSelection(position);
+ bindingDialog.setUploadChannel.setSelection(position);
}
}
@Override
public void onAllPlaylistRemoved() {
- textviewNoAction.setVisibility(View.VISIBLE);
+ binding.noAction.setVisibility(View.VISIBLE);
}
}
diff --git a/app/src/main/java/app/fedilab/fedilabtube/FedilabTube.java b/app/src/main/java/app/fedilab/fedilabtube/FedilabTube.java
index 95cf7b2..3c12f80 100644
--- a/app/src/main/java/app/fedilab/fedilabtube/FedilabTube.java
+++ b/app/src/main/java/app/fedilab/fedilabtube/FedilabTube.java
@@ -14,22 +14,30 @@ package app.fedilab.fedilabtube;
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
* see . */
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
import android.content.Context;
import android.content.SharedPreferences;
+import android.os.Build;
import androidx.multidex.MultiDex;
import androidx.multidex.MultiDexApplication;
import androidx.work.Configuration;
import androidx.work.WorkManager;
-import net.gotev.uploadservice.UploadService;
+import net.gotev.uploadservice.UploadServiceConfig;
+import net.gotev.uploadservice.observer.request.GlobalRequestObserver;
+
+import java.util.Objects;
import app.fedilab.fedilabtube.helper.Helper;
import app.fedilab.fedilabtube.helper.ThemeHelper;
+import app.fedilab.fedilabtube.services.GlobalUploadObserver;
import app.fedilab.fedilabtube.worker.WorkHelper;
public class FedilabTube extends MultiDexApplication {
+ static String UPLOAD_CHANNEL_ID = "upload_info_peertube";
@Override
public void onCreate() {
@@ -44,6 +52,10 @@ public class FedilabTube extends MultiDexApplication {
if (interval >= 15) {
WorkHelper.fetchNotifications(this, interval);
}
+ createNotificationChannel();
+ UploadServiceConfig.initialize(FedilabTube.this, UPLOAD_CHANNEL_ID, true);
+
+ new GlobalRequestObserver(this, new GlobalUploadObserver());
}
@@ -52,8 +64,6 @@ public class FedilabTube extends MultiDexApplication {
super.attachBaseContext(base);
MultiDex.install(FedilabTube.this);
-
- UploadService.NAMESPACE = BuildConfig.APPLICATION_ID;
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
int themePref = sharedpreferences.getInt(Helper.SET_THEME, Helper.DEFAULT_MODE);
ThemeHelper.switchTo(themePref);
@@ -61,5 +71,13 @@ public class FedilabTube extends MultiDexApplication {
}
-
+ private void createNotificationChannel() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ NotificationChannel channel = new NotificationChannel(UPLOAD_CHANNEL_ID,
+ getString(R.string.notification_channel_name),
+ NotificationManager.IMPORTANCE_LOW);
+ channel.setSound(null, null);
+ ((NotificationManager) Objects.requireNonNull(getSystemService(Context.NOTIFICATION_SERVICE))).createNotificationChannel(channel);
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/app/fedilab/fedilabtube/InstancePickerActivity.java b/app/src/main/java/app/fedilab/fedilabtube/InstancePickerActivity.java
index a16cc16..0d0190f 100644
--- a/app/src/main/java/app/fedilab/fedilabtube/InstancePickerActivity.java
+++ b/app/src/main/java/app/fedilab/fedilabtube/InstancePickerActivity.java
@@ -48,7 +48,7 @@ import app.fedilab.fedilabtube.helper.RoundedBackgroundSpan;
import app.fedilab.fedilabtube.viewmodel.InstancesVM;
import es.dmoral.toasty.Toasty;
-import static app.fedilab.fedilabtube.MainActivity.peertubeInformation;
+import static app.fedilab.fedilabtube.helper.Helper.peertubeInformation;
public class InstancePickerActivity extends AppCompatActivity {
diff --git a/app/src/main/java/app/fedilab/fedilabtube/LoginActivity.java b/app/src/main/java/app/fedilab/fedilabtube/LoginActivity.java
index 78f3f47..cb9fac2 100644
--- a/app/src/main/java/app/fedilab/fedilabtube/LoginActivity.java
+++ b/app/src/main/java/app/fedilab/fedilabtube/LoginActivity.java
@@ -43,6 +43,8 @@ import app.fedilab.fedilabtube.client.entities.OauthParams;
import app.fedilab.fedilabtube.client.entities.Token;
import app.fedilab.fedilabtube.databinding.ActivityLoginBinding;
import app.fedilab.fedilabtube.helper.Helper;
+import app.fedilab.fedilabtube.helper.HelperAcadInstance;
+import app.fedilab.fedilabtube.helper.HelperInstance;
import es.dmoral.toasty.Toasty;
import static app.fedilab.fedilabtube.client.RetrofitPeertubeAPI.updateCredential;
@@ -55,6 +57,7 @@ public class LoginActivity extends AppCompatActivity {
private static String client_secret;
private ActivityLoginBinding binding;
+ @SuppressLint("SetTextI18n")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -66,7 +69,13 @@ public class LoginActivity extends AppCompatActivity {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- SpannableString content_create = new SpannableString(getString(R.string.join_peertube));
+ SpannableString content_create;
+ if (BuildConfig.FLAVOR.compareTo("queermotion") == 0) {
+ content_create = new SpannableString(getString(R.string.register_account));
+ } else {
+ content_create = new SpannableString(getString(R.string.join_peertube));
+ }
+
content_create.setSpan(new UnderlineSpan(), 0, content_create.length(), 0);
content_create.setSpan(new ForegroundColorSpan(ContextCompat.getColor(LoginActivity.this, Helper.getColorAccent())), 0, content_create.length(),
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
@@ -80,10 +89,12 @@ public class LoginActivity extends AppCompatActivity {
});
- if (BuildConfig.full_instances) {
+ if (BuildConfig.full_instances && BuildConfig.instance_switcher) {
binding.loginInstanceContainer.setVisibility(View.VISIBLE);
}
-
+ if (BuildConfig.FLAVOR.compareTo("queermotion") == 0) {
+ binding.loginInstance.setText("queermotion.org");
+ }
if (Helper.isTablet(LoginActivity.this)) {
@@ -106,7 +117,7 @@ public class LoginActivity extends AppCompatActivity {
if (!hasFocus) {
if (binding.loginUid.getText() != null && android.util.Patterns.EMAIL_ADDRESS.matcher(binding.loginUid.getText().toString().trim()).matches()) {
String[] emailArray = binding.loginUid.getText().toString().split("@");
- if (emailArray.length > 1 && Arrays.asList(Helper.openid).contains(emailArray[1])) {
+ if (emailArray.length > 1 && Arrays.asList(HelperAcadInstance.openid).contains(emailArray[1])) {
binding.loginButton.callOnClick();
}
}
@@ -125,13 +136,13 @@ public class LoginActivity extends AppCompatActivity {
String instance, host;
if (!BuildConfig.full_instances) {
String[] emailArray = binding.loginUid.getText().toString().split("@");
- if (emailArray.length > 1 && !Arrays.asList(Helper.valideEmails).contains(emailArray[1])) {
+ if (emailArray.length > 1 && !Arrays.asList(HelperAcadInstance.valideEmails).contains(emailArray[1])) {
Toasty.error(LoginActivity.this, getString(R.string.email_error_domain, emailArray[1])).show();
binding.loginButton.setEnabled(true);
return;
}
host = emailArray[1];
- instance = Helper.getPeertubeUrl(host);
+ instance = HelperInstance.getPeertubeUrl(host);
} else {
if (binding.loginInstance.getText() == null || binding.loginInstance.getText().toString().trim().length() == 0) {
Toasty.error(LoginActivity.this, getString(R.string.not_valide_instance)).show();
@@ -165,7 +176,7 @@ public class LoginActivity extends AppCompatActivity {
}
String finalInstance = instance;
String finalHost = host;
- if (Arrays.asList(Helper.openid).contains(host) && !BuildConfig.full_instances) {
+ if (Arrays.asList(HelperAcadInstance.openid).contains(host) && !BuildConfig.full_instances) {
new Thread(() -> {
try {
Oauth oauth = new RetrofitPeertubeAPI(LoginActivity.this, finalInstance, null).oauthClient(null, null, null, null);
@@ -185,7 +196,7 @@ public class LoginActivity extends AppCompatActivity {
editor.apply();
Intent intent = new Intent(LoginActivity.this, WebviewConnectActivity.class);
Bundle b = new Bundle();
- b.putString("url", "https://" + Helper.getPeertubeUrl(finalHost) + "/plugins/auth-openid-connect/0.0.1/auth/openid-connect");
+ b.putString("url", "https://" + HelperInstance.getPeertubeUrl(finalHost) + "/plugins/auth-openid-connect/0.0.1/auth/openid-connect");
intent.putExtras(b);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
diff --git a/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java b/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java
index b2d0c83..487083b 100644
--- a/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java
+++ b/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java
@@ -16,19 +16,21 @@ package app.fedilab.fedilabtube;
import android.annotation.SuppressLint;
import android.app.Activity;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.os.Looper;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
-import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
@@ -39,12 +41,23 @@ import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentStatePagerAdapter;
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+import androidx.viewpager.widget.PagerAdapter;
+import androidx.viewpager.widget.ViewPager;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.kobakei.ratethisapp.RateThisApp;
import org.jetbrains.annotations.NotNull;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
@@ -55,6 +68,7 @@ import java.util.regex.Pattern;
import app.fedilab.fedilabtube.client.RetrofitPeertubeAPI;
import app.fedilab.fedilabtube.client.data.AccountData.Account;
import app.fedilab.fedilabtube.client.data.InstanceData;
+import app.fedilab.fedilabtube.client.data.VideoData;
import app.fedilab.fedilabtube.client.entities.Error;
import app.fedilab.fedilabtube.client.entities.OauthParams;
import app.fedilab.fedilabtube.client.entities.PeertubeInformation;
@@ -62,9 +76,11 @@ import app.fedilab.fedilabtube.client.entities.Token;
import app.fedilab.fedilabtube.client.entities.UserMe;
import app.fedilab.fedilabtube.client.entities.UserSettings;
import app.fedilab.fedilabtube.client.entities.WellKnownNodeinfo;
+import app.fedilab.fedilabtube.databinding.ActivityMainBinding;
import app.fedilab.fedilabtube.fragment.DisplayOverviewFragment;
import app.fedilab.fedilabtube.fragment.DisplayVideosFragment;
import app.fedilab.fedilabtube.helper.Helper;
+import app.fedilab.fedilabtube.helper.HelperInstance;
import app.fedilab.fedilabtube.helper.PlaylistExportHelper;
import app.fedilab.fedilabtube.helper.SwitchAccountHelper;
import app.fedilab.fedilabtube.services.RetrieveInfoService;
@@ -73,63 +89,40 @@ import app.fedilab.fedilabtube.sqlite.Sqlite;
import app.fedilab.fedilabtube.sqlite.StoredInstanceDAO;
import app.fedilab.fedilabtube.viewmodel.TimelineVM;
import es.dmoral.toasty.Toasty;
+import su.litvak.chromecast.api.v2.ChromeCast;
+import su.litvak.chromecast.api.v2.ChromeCasts;
+import su.litvak.chromecast.api.v2.ChromeCastsListener;
+import su.litvak.chromecast.api.v2.MediaStatus;
import static app.fedilab.fedilabtube.MainActivity.TypeOfConnection.NORMAL;
import static app.fedilab.fedilabtube.MainActivity.TypeOfConnection.SURFING;
-import static app.fedilab.fedilabtube.helper.Helper.academies;
+import static app.fedilab.fedilabtube.helper.Helper.peertubeInformation;
+import static app.fedilab.fedilabtube.helper.HelperAcadInstance.academies;
-public class MainActivity extends AppCompatActivity {
+public class MainActivity extends AppCompatActivity implements ChromeCastsListener {
- public static PeertubeInformation peertubeInformation;
public static int PICK_INSTANCE = 5641;
public static int PICK_INSTANCE_SURF = 5642;
public static UserMe userMe;
+ public static InstanceData.InstanceConfig instanceConfig;
public static TypeOfConnection typeOfConnection;
- final FragmentManager fm = getSupportFragmentManager();
- Fragment active;
private DisplayVideosFragment recentFragment, locaFragment, trendingFragment, subscriptionFragment, mostLikedFragment;
private DisplayOverviewFragment overviewFragment;
- private final BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
- = item -> {
- DisplayVideosFragment displayVideosFragment = null;
- int itemId = item.getItemId();
- if (itemId == R.id.navigation_subscription) {
- displayVideosFragment = subscriptionFragment;
- setTitleCustom(R.string.subscriptions);
- } else if (itemId == R.id.navigation_trending) {
- setTitleCustom(R.string.title_trending);
- displayVideosFragment = trendingFragment;
- } else if (itemId == R.id.navigation_most_liked) {
- setTitleCustom(R.string.title_most_liked);
- displayVideosFragment = mostLikedFragment;
- } else if (itemId == R.id.navigation_recently_added) {
- setTitleCustom(R.string.title_recently_added);
- displayVideosFragment = recentFragment;
- } else if (itemId == R.id.navigation_local) {
- setTitleCustom(R.string.title_local);
- displayVideosFragment = locaFragment;
- } else if (itemId == R.id.navigation_discover) {
- setTitleCustom(R.string.title_discover);
- fm.beginTransaction().hide(active).show(overviewFragment).commit();
- active = overviewFragment;
- return true;
- }
- if (displayVideosFragment != null) {
- fm.beginTransaction().hide(active).show(displayVideosFragment).commit();
- active = displayVideosFragment;
- return true;
- } else {
- return false;
- }
- };
+ private ActivityMainBinding binding;
+ private BroadcastReceiver manage_chromecast;
+ public static List chromeCasts;
+ public static ChromeCast chromeCast;
+ private VideoData.Video castedTube;
+
+ public static boolean chromecastActivated = false;
@SuppressLint("ApplySharedPref")
public static void showRadioButtonDialogFullInstances(Activity activity, boolean storeInDb) {
final SharedPreferences sharedpreferences = activity.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
AlertDialog.Builder alt_bld = new AlertDialog.Builder(activity);
alt_bld.setTitle(R.string.instance_choice);
- String instance = Helper.getLiveInstance(activity);
+ String instance = HelperInstance.getLiveInstance(activity);
final EditText input = new EditText(activity);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
@@ -141,6 +134,12 @@ public class MainActivity extends AppCompatActivity {
(dialog, which) -> new Thread(() -> {
try {
String newInstance = input.getText().toString().trim();
+ if (!newInstance.startsWith("http")) {
+ newInstance = "http://" + newInstance;
+ }
+ URL url = new URL(newInstance);
+ newInstance = url.getHost();
+
WellKnownNodeinfo.NodeInfo instanceNodeInfo = new RetrofitPeertubeAPI(activity, newInstance, null).getNodeInfo();
if (instanceNodeInfo.getSoftware() != null && instanceNodeInfo.getSoftware().getName().trim().toLowerCase().compareTo("peertube") == 0) {
SharedPreferences.Editor editor = sharedpreferences.edit();
@@ -186,13 +185,156 @@ public class MainActivity extends AppCompatActivity {
private void setTitleCustom(int titleRId) {
Toolbar toolbar = findViewById(R.id.toolbar);
TextView mTitle = toolbar.findViewById(R.id.toolbar_title);
- mTitle.setText(getString(titleRId));
+ if (mTitle != null) {
+ mTitle.setText(getString(titleRId));
+ }
}
+ private final BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
+ = item -> {
+ int itemId = item.getItemId();
+ if (itemId == R.id.navigation_discover) {
+ setTitleCustom(R.string.title_discover);
+ binding.viewpager.setCurrentItem(0);
+ } else if (itemId == R.id.navigation_subscription) {
+ binding.viewpager.setCurrentItem(1);
+ setTitleCustom(R.string.subscriptions);
+ } else if (itemId == R.id.navigation_trending) {
+ setTitleCustom(R.string.title_trending);
+ if (Helper.isLoggedIn(MainActivity.this)) {
+ binding.viewpager.setCurrentItem(2);
+ } else {
+ binding.viewpager.setCurrentItem(1);
+ }
+ } else if (itemId == R.id.navigation_most_liked) {
+ setTitleCustom(R.string.title_most_liked);
+ binding.viewpager.setCurrentItem(2);
+ } else if (itemId == R.id.navigation_recently_added) {
+ setTitleCustom(R.string.title_recently_added);
+ binding.viewpager.setCurrentItem(3);
+ } else if (itemId == R.id.navigation_local) {
+ setTitleCustom(R.string.title_local);
+ binding.viewpager.setCurrentItem(4);
+ }
+ return true;
+ };
+
+ @Override
+ public void newChromeCastDiscovered(ChromeCast chromeCast) {
+ if (chromeCasts == null) {
+ chromeCasts = new ArrayList<>();
+ chromeCasts.add(chromeCast);
+ } else {
+ boolean canBeAdded = true;
+ for (ChromeCast cast : chromeCasts) {
+ if (cast.getName().compareTo(chromeCast.getName()) == 0) {
+ canBeAdded = false;
+ break;
+ }
+ }
+ if (canBeAdded) {
+ chromeCasts.add(chromeCast);
+ }
+ }
+ try {
+ if (chromeCast.isAppRunning(Helper.CAST_ID) && chromeCast.getMediaStatus() != null && chromeCast.getMediaStatus().playerState != null) {
+ if (binding.castInfo.getVisibility() == View.GONE) {
+ binding.castInfo.setVisibility(View.VISIBLE);
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ @Override
+ public void chromeCastRemoved(ChromeCast chromeCast) {
+
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ binding = null;
+ ChromeCasts.unregisterListener(this);
+ if (manage_chromecast != null) {
+ LocalBroadcastManager.getInstance(MainActivity.this).unregisterReceiver(manage_chromecast);
+
+ new Thread(() -> {
+ if (chromeCasts != null && chromeCasts.size() > 0) {
+ for (ChromeCast cast : chromeCasts) {
+ try {
+ cast.stopApp();
+ cast.disconnect();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }).start();
+ }
+ if (chromeCasts != null) {
+ chromeCasts = null;
+ }
+ if (chromeCast != null) {
+ chromeCast = null;
+ }
+ }
+
+ //Method for discovering cast devices
+ public void discoverCast() {
+ new Thread(() -> {
+ if (chromeCasts != null) {
+ for (ChromeCast cast : chromeCasts) {
+ try {
+ cast.disconnect();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ chromeCasts = null;
+ }
+ chromeCasts = new ArrayList<>();
+ try {
+ List interfaces;
+ interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
+ for (NetworkInterface ni : interfaces) {
+ if ((!ni.isLoopback()) && ni.isUp() && (ni.getName().equals("wlan0"))) {
+ Enumeration inetAddressEnumeration = ni.getInetAddresses();
+ while (inetAddressEnumeration.hasMoreElements()) {
+ InetAddress inetAddress = inetAddressEnumeration.nextElement();
+ ChromeCasts.restartDiscovery(inetAddress);
+ int tryFind = 0;
+ while (ChromeCasts.get().isEmpty() && tryFind < 5) {
+ try {
+ Thread.sleep(1000);
+ tryFind++;
+ } catch (InterruptedException ignored) {
+ }
+ }
+ }
+ }
+ }
+ ChromeCasts.stopDiscovery();
+ Handler mainHandler = new Handler(Looper.getMainLooper());
+ Runnable myRunnable = this::invalidateOptionsMenu;
+ mainHandler.post(myRunnable);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }).start();
+ }
+
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
+ binding = ActivityMainBinding.inflate(getLayoutInflater());
+ View view = binding.getRoot();
+ setContentView(view);
+ ChromeCastsListener chromeCastsListener = this;
+ ChromeCasts.registerListener(chromeCastsListener);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
@@ -208,22 +350,6 @@ public class MainActivity extends AppCompatActivity {
}
checkIfConnectedUsers();
- Fragment fragment = getSupportFragmentManager().findFragmentByTag("5");
- if (fragment != null)
- getSupportFragmentManager().beginTransaction().remove(fragment).commit();
- fragment = getSupportFragmentManager().findFragmentByTag("4");
- if (fragment != null)
- getSupportFragmentManager().beginTransaction().remove(fragment).commit();
- fragment = getSupportFragmentManager().findFragmentByTag("3");
- if (fragment != null)
- getSupportFragmentManager().beginTransaction().remove(fragment).commit();
- fragment = getSupportFragmentManager().findFragmentByTag("2");
- if (fragment != null)
- getSupportFragmentManager().beginTransaction().remove(fragment).commit();
- fragment = getSupportFragmentManager().findFragmentByTag("1");
- if (fragment != null)
- getSupportFragmentManager().beginTransaction().remove(fragment).commit();
-
recentFragment = new DisplayVideosFragment();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.TIMELINE_TYPE, TimelineVM.TimelineType.RECENT);
@@ -250,99 +376,48 @@ public class MainActivity extends AppCompatActivity {
mostLikedFragment.setArguments(bundle);
overviewFragment = new DisplayOverviewFragment();
-
- if (active == null) {
- active = overviewFragment;
- }
-
-
if (!Helper.isLoggedIn(MainActivity.this)) {
- fm.beginTransaction().add(R.id.nav_host_fragment, locaFragment, "5").hide(locaFragment).commit();
- fm.beginTransaction().add(R.id.nav_host_fragment, recentFragment, "4").hide(recentFragment).commit();
- fm.beginTransaction().add(R.id.nav_host_fragment, mostLikedFragment, "3").hide(mostLikedFragment).commit();
- fm.beginTransaction().add(R.id.nav_host_fragment, trendingFragment, "2").hide(trendingFragment).commit();
- fm.beginTransaction().add(R.id.nav_host_fragment, overviewFragment, "1").commit();
+ PagerAdapter mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
+ binding.viewpager.setAdapter(mPagerAdapter);
}
+ binding.viewpager.setOffscreenPageLimit(5);
+
+
+ binding.viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ MenuItem item = binding.navView.getMenu().getItem(position);
+ binding.navView.setSelectedItemId(item.getItemId());
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+
+ }
+ });
+
+
toolbar.setOnClickListener(v -> {
- if (active instanceof DisplayVideosFragment) {
- ((DisplayVideosFragment) active).scrollToTop();
- } else if (active instanceof DisplayOverviewFragment) {
- ((DisplayOverviewFragment) active).scrollToTop();
+ if (binding.viewpager.getAdapter() == null) {
+ return;
+ }
+ if (binding.viewpager.getAdapter().instantiateItem(binding.viewpager, binding.viewpager.getCurrentItem()) instanceof DisplayVideosFragment) {
+ ((DisplayVideosFragment) binding.viewpager.getAdapter().instantiateItem(binding.viewpager, binding.viewpager.getCurrentItem())).scrollToTop();
+ } else if (binding.viewpager.getAdapter().instantiateItem(binding.viewpager, binding.viewpager.getCurrentItem()) instanceof DisplayOverviewFragment) {
+ ((DisplayOverviewFragment) binding.viewpager.getAdapter().instantiateItem(binding.viewpager, binding.viewpager.getCurrentItem())).scrollToTop();
}
});
setTitleCustom(R.string.title_discover);
if (Helper.isLoggedIn(MainActivity.this)) {
-
navView.inflateMenu(R.menu.bottom_nav_menu_connected);
- new Thread(() -> {
- final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
- String tokenStr = sharedpreferences.getString(Helper.PREF_KEY_OAUTH_TOKEN, null);
- String instance = Helper.getLiveInstance(MainActivity.this);
- SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
- String instanceShar = sharedpreferences.getString(Helper.PREF_INSTANCE, null);
- String userIdShar = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
- Account account = new AccountDAO(MainActivity.this, db).getAccountByToken(tokenStr);
- if (account == null) {
- account = new AccountDAO(MainActivity.this, db).getAccountByIdInstance(userIdShar, instanceShar);
- }
- if (account != null) {
- Account finalAccount = account;
- OauthParams oauthParams = new OauthParams();
- oauthParams.setGrant_type("refresh_token");
- oauthParams.setClient_id(account.getClient_id());
- oauthParams.setClient_secret(account.getClient_secret());
- oauthParams.setRefresh_token(account.getRefresh_token());
- oauthParams.setAccess_token(account.getToken());
- try {
- Token token = new RetrofitPeertubeAPI(MainActivity.this).manageToken(oauthParams);
- if (token == null && Helper.instanceOnline(instance)) {
- runOnUiThread(() -> Helper.logoutCurrentUser(MainActivity.this, finalAccount));
- return;
- } else if (token == null) {
- return;
- }
- runOnUiThread(() -> {
- //To avoid a token issue with subscriptions, adding fragment is done when the token is refreshed.
- new Handler().post(() -> {
- fm.beginTransaction().add(R.id.nav_host_fragment, locaFragment, "5").hide(locaFragment).commit();
- fm.beginTransaction().add(R.id.nav_host_fragment, recentFragment, "4").hide(recentFragment).commitAllowingStateLoss();
- fm.beginTransaction().add(R.id.nav_host_fragment, trendingFragment, "3").hide(trendingFragment).commitAllowingStateLoss();
- fm.beginTransaction().add(R.id.nav_host_fragment, subscriptionFragment, "2").hide(subscriptionFragment).commitAllowingStateLoss();
- fm.beginTransaction().add(R.id.nav_host_fragment, overviewFragment, "1").commitAllowingStateLoss();
- });
- });
-
- userMe = new RetrofitPeertubeAPI(MainActivity.this, instance, token.getAccess_token()).verifyCredentials();
- if (userMe != null && userMe.getAccount() != null) {
- new AccountDAO(MainActivity.this, db).updateAccount(userMe.getAccount());
- SharedPreferences.Editor editor = sharedpreferences.edit();
- editor.putString(Helper.PREF_KEY_ID, account.getId());
- editor.putString(Helper.PREF_KEY_NAME, account.getUsername());
- editor.putBoolean(getString(R.string.set_autoplay_choice), userMe.isAutoPlayVideo());
- editor.putBoolean(getString(R.string.set_store_in_history), userMe.isVideosHistoryEnabled());
- editor.putBoolean(getString(R.string.set_autoplay_next_video_choice), userMe.isAutoPlayNextVideo());
- editor.putString(getString(R.string.set_video_sensitive_choice), userMe.getNsfwPolicy());
- //Sync languages from server
- List videoLanguageServer = userMe.getVideoLanguages();
- if (videoLanguageServer != null) {
- Set videoLanguageServerSet = new TreeSet<>(videoLanguageServer);
- videoLanguageServerSet.addAll(videoLanguageServer);
- Set videoLanguageLocal = sharedpreferences.getStringSet(getString(R.string.set_video_language_choice), null);
- if (videoLanguageServerSet.size() > 0 && videoLanguageLocal != null) {
- videoLanguageServer.addAll(videoLanguageLocal);
- }
- editor.putStringSet(getString(R.string.set_video_language_choice), videoLanguageServerSet);
- editor.apply();
- }
- }
- } catch (Error error) {
- runOnUiThread(() -> Helper.logoutCurrentUser(MainActivity.this, finalAccount));
- error.printStackTrace();
- }
- }
- }).start();
+ refreshToken();
} else {
navView.inflateMenu(R.menu.bottom_nav_menu);
@@ -363,6 +438,100 @@ public class MainActivity extends AppCompatActivity {
if (!BuildConfig.full_instances) {
PlaylistExportHelper.manageIntentUrl(MainActivity.this, getIntent());
}
+
+ binding.castClose.setOnClickListener(v -> {
+ Intent intentBC = new Intent(Helper.RECEIVE_CAST_SETTINGS);
+ Bundle b = new Bundle();
+ b.putInt("displayed", 0);
+ intentBC.putExtras(b);
+ LocalBroadcastManager.getInstance(MainActivity.this).sendBroadcast(intentBC);
+ });
+
+ binding.castTogglePlay.setOnClickListener(v -> {
+ if (chromeCast != null) {
+ new Thread(() -> {
+ try {
+ Handler mainHandler = new Handler(Looper.getMainLooper());
+ Runnable myRunnable = () -> binding.castTogglePlay.setVisibility(View.GONE);
+ mainHandler.post(myRunnable);
+ int icon = -1;
+ if (chromeCast.getMediaStatus().playerState == MediaStatus.PlayerState.PLAYING) {
+ chromeCast.pause();
+ icon = R.drawable.ic_baseline_play_arrow_32;
+ } else if (chromeCast.getMediaStatus().playerState == MediaStatus.PlayerState.PAUSED) {
+ chromeCast.play();
+ icon = R.drawable.ic_baseline_pause_32;
+ }
+ if (icon != -1) {
+ int finalIcon = icon;
+ myRunnable = () -> binding.castTogglePlay.setImageResource(finalIcon);
+ mainHandler.post(myRunnable);
+ }
+ myRunnable = () -> binding.castTogglePlay.setVisibility(View.VISIBLE);
+ mainHandler.post(myRunnable);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }).start();
+ }
+ });
+ manage_chromecast = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Bundle b = intent.getExtras();
+ assert b != null;
+ int state = b.getInt("state_asked", -1);
+ int displayed = b.getInt("displayed", -1);
+ castedTube = b.getParcelable("castedTube");
+
+ if (state == 1) {
+ discoverCast();
+ } else if (state == 0) {
+ new Thread(() -> {
+ try {
+ if (chromeCast != null) {
+ chromeCast.stopApp();
+ chromeCast.disconnect();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }).start();
+ }
+ if (displayed == 1) {
+ chromecastActivated = true;
+ if (castedTube != null) {
+ binding.castInfo.setVisibility(View.VISIBLE);
+ Helper.loadGiF(MainActivity.this, castedTube.getThumbnailPath(), binding.castView);
+ binding.castTitle.setText(castedTube.getTitle());
+ binding.castDescription.setText(castedTube.getDescription());
+ }
+ } else if (displayed == 0) {
+ chromecastActivated = false;
+ binding.castInfo.setVisibility(View.GONE);
+ new Thread(() -> {
+ try {
+ if (chromeCast != null) {
+ chromeCast.stopApp();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }).start();
+ }
+ }
+ };
+ final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
+
+ LocalBroadcastManager.getInstance(MainActivity.this).registerReceiver(manage_chromecast, new IntentFilter(Helper.RECEIVE_CAST_SETTINGS));
+ int search_cast = sharedpreferences.getInt(getString(R.string.set_cast_choice), 0);
+ if (search_cast == 1) {
+ discoverCast();
+ }
+ }
+
+ public DisplayVideosFragment getSubscriptionFragment() {
+ return subscriptionFragment;
}
private void startInForeground() {
@@ -374,6 +543,88 @@ public class MainActivity extends AppCompatActivity {
}
}
+ private void refreshToken() {
+ new Thread(() -> {
+ final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
+ String tokenStr = sharedpreferences.getString(Helper.PREF_KEY_OAUTH_TOKEN, null);
+ String instance = HelperInstance.getLiveInstance(MainActivity.this);
+ SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
+ String instanceShar = sharedpreferences.getString(Helper.PREF_INSTANCE, null);
+ String userIdShar = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
+ Account account = new AccountDAO(MainActivity.this, db).getAccountByToken(tokenStr);
+ if (account == null) {
+ account = new AccountDAO(MainActivity.this, db).getAccountByIdInstance(userIdShar, instanceShar);
+ }
+ if (account != null) {
+ Account finalAccount = account;
+ OauthParams oauthParams = new OauthParams();
+ oauthParams.setGrant_type("refresh_token");
+ oauthParams.setClient_id(account.getClient_id());
+ oauthParams.setClient_secret(account.getClient_secret());
+ oauthParams.setRefresh_token(account.getRefresh_token());
+ oauthParams.setAccess_token(account.getToken());
+ try {
+ Token token = new RetrofitPeertubeAPI(MainActivity.this).manageToken(oauthParams);
+ if (token == null) {
+ return;
+ }
+ runOnUiThread(() -> {
+ //To avoid a token issue with subscriptions, adding fragment is done when the token is refreshed.
+ new Handler().post(() -> {
+ if (Helper.isLoggedIn(MainActivity.this)) {
+ PagerAdapter mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
+ binding.viewpager.setAdapter(mPagerAdapter);
+ }
+ });
+ });
+
+ userMe = new RetrofitPeertubeAPI(MainActivity.this, instance, token.getAccess_token()).verifyCredentials();
+ if (userMe != null && userMe.getAccount() != null) {
+ new AccountDAO(MainActivity.this, db).updateAccount(userMe.getAccount());
+ SharedPreferences.Editor editor = sharedpreferences.edit();
+ editor.putString(Helper.PREF_KEY_ID, account.getId());
+ editor.putString(Helper.PREF_KEY_NAME, account.getUsername());
+ editor.putBoolean(getString(R.string.set_autoplay_choice), userMe.isAutoPlayVideo());
+ editor.putBoolean(getString(R.string.set_store_in_history), userMe.isVideosHistoryEnabled());
+ editor.putBoolean(getString(R.string.set_autoplay_next_video_choice), userMe.isAutoPlayNextVideo());
+ editor.putString(getString(R.string.set_video_sensitive_choice), userMe.getNsfwPolicy());
+ //Sync languages from server
+ List videoLanguageServer = userMe.getVideoLanguages();
+ if (videoLanguageServer != null) {
+ Set videoLanguageServerSet = new TreeSet<>(videoLanguageServer);
+ videoLanguageServerSet.addAll(videoLanguageServer);
+ Set videoLanguageLocal = sharedpreferences.getStringSet(getString(R.string.set_video_language_choice), null);
+ if (videoLanguageServerSet.size() > 0 && videoLanguageLocal != null) {
+ videoLanguageServer.addAll(videoLanguageLocal);
+ }
+ editor.putStringSet(getString(R.string.set_video_language_choice), videoLanguageServerSet);
+ editor.apply();
+ }
+ }
+ instanceConfig = new RetrofitPeertubeAPI(MainActivity.this).getConfigInstance();
+ } catch (Error error) {
+ runOnUiThread(() -> {
+ AlertDialog.Builder alt_bld = new AlertDialog.Builder(this);
+ alt_bld.setTitle(R.string.refresh_token_failed);
+ alt_bld.setMessage(R.string.refresh_token_failed_message);
+ alt_bld.setNegativeButton(R.string.action_logout, (dialog, id) -> {
+ dialog.dismiss();
+ Helper.logoutCurrentUser(MainActivity.this, finalAccount);
+ });
+ alt_bld.setPositiveButton(R.string._retry, (dialog, id) -> {
+ dialog.dismiss();
+ refreshToken();
+ });
+ AlertDialog alert = alt_bld.create();
+ alert.show();
+
+ });
+ error.printStackTrace();
+ }
+ }
+ }).start();
+ }
+
@Override
public boolean onCreateOptionsMenu(@NotNull Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
@@ -383,7 +634,7 @@ public class MainActivity extends AppCompatActivity {
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
- Pattern link = Pattern.compile("(https?://[\\da-z.-]+\\.[a-z.]{2,10})/videos/watch/(\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12})$");
+ Pattern link = Pattern.compile("(https?://[\\da-z.-]+\\.[a-z.]{2,10})/videos/watch/(\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12})(\\?start=(\\d+[hH])?(\\d+[mM])?(\\d+[sS])?)?$");
Matcher matcherLink = link.matcher(query.trim());
if (matcherLink.find()) {
Intent intent = new Intent(MainActivity.this, PeertubeActivity.class);
@@ -422,18 +673,17 @@ public class MainActivity extends AppCompatActivity {
MenuItem instanceItem = menu.findItem(R.id.action_change_instance);
MenuItem accountItem = menu.findItem(R.id.action_account);
- Toolbar toolbar = findViewById(R.id.toolbar);
- ImageView instances = toolbar.findViewById(R.id.instances);
- if (BuildConfig.full_instances && ((Helper.isLoggedIn(MainActivity.this) && typeOfConnection == NORMAL) || typeOfConnection == SURFING)) {
- instances.setVisibility(View.VISIBLE);
- instances.setOnClickListener(null);
- instances.setOnClickListener(v -> {
+
+ if (BuildConfig.surfing_mode && ((Helper.isLoggedIn(MainActivity.this) && typeOfConnection == NORMAL) || typeOfConnection == SURFING)) {
+ binding.instances.setVisibility(View.VISIBLE);
+ binding.instances.setOnClickListener(null);
+ binding.instances.setOnClickListener(v -> {
Intent intent = new Intent(MainActivity.this, ManageInstancesActivity.class);
startActivity(intent);
overridePendingTransition(R.anim.slide_in_up, R.anim.slide_out_up);
});
} else {
- instances.setVisibility(View.GONE);
+ binding.instances.setVisibility(View.GONE);
}
switch (typeOfConnection) {
case UNKNOWN:
@@ -485,13 +735,17 @@ public class MainActivity extends AppCompatActivity {
break;
}
+ if (!BuildConfig.instance_switcher) {
+ instanceItem.setVisible(false);
+ }
- if (!BuildConfig.full_instances) {
+ if (!BuildConfig.sepia_search) {
sepiaSearchItem.setVisible(false);
}
return true;
}
+
private void checkIfConnectedUsers() {
new Thread(() -> {
try {
@@ -601,13 +855,6 @@ public class MainActivity extends AppCompatActivity {
return super.onOptionsItemSelected(item);
}
- public void setActive(DisplayVideosFragment displayVideosFragment) {
- this.active = displayVideosFragment;
- }
-
- public void setSubscriptionFragment(DisplayVideosFragment displayVideosFragment) {
- this.subscriptionFragment = displayVideosFragment;
- }
@Override
protected void onNewIntent(Intent intent) {
@@ -631,10 +878,10 @@ public class MainActivity extends AppCompatActivity {
AlertDialog.Builder alt_bld = new AlertDialog.Builder(this);
alt_bld.setTitle(R.string.instance_choice);
final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
- String acad = Helper.getLiveInstance(MainActivity.this);
+ String acad = HelperInstance.getLiveInstance(MainActivity.this);
int i = 0;
for (String item : academies) {
- if (Helper.getPeertubeUrl(item).compareTo(acad) == 0) {
+ if (HelperInstance.getPeertubeUrl(item).compareTo(acad) == 0) {
break;
}
i++;
@@ -662,11 +909,55 @@ public class MainActivity extends AppCompatActivity {
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.PREF_INSTANCE, String.valueOf(data.getData()));
editor.commit();
- finish();
+ recreate();
}
}
}
+ private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
+
+ ScreenSlidePagerAdapter(FragmentManager fm) {
+ super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
+ }
+
+ @NotNull
+ @Override
+ public Fragment getItem(final int position) {
+ if (Helper.isLoggedIn(MainActivity.this)) {
+ switch (position) {
+ case 0:
+ return overviewFragment;
+ case 1:
+ return subscriptionFragment;
+ case 2:
+ return trendingFragment;
+ case 3:
+ return recentFragment;
+ case 4:
+ return locaFragment;
+ }
+ } else {
+ switch (position) {
+ case 0:
+ return overviewFragment;
+ case 1:
+ return trendingFragment;
+ case 2:
+ return mostLikedFragment;
+ case 3:
+ return recentFragment;
+ case 4:
+ return locaFragment;
+ }
+ }
+ return overviewFragment;
+ }
+
+ @Override
+ public int getCount() {
+ return 5;
+ }
+ }
public enum TypeOfConnection {
UNKNOWN,
diff --git a/app/src/main/java/app/fedilab/fedilabtube/PeertubeActivity.java b/app/src/main/java/app/fedilab/fedilabtube/PeertubeActivity.java
index d30280c..86dce98 100644
--- a/app/src/main/java/app/fedilab/fedilabtube/PeertubeActivity.java
+++ b/app/src/main/java/app/fedilab/fedilabtube/PeertubeActivity.java
@@ -17,7 +17,6 @@ package app.fedilab.fedilabtube;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
-import android.app.Dialog;
import android.app.PictureInPictureParams;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -29,6 +28,7 @@ import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.PorterDuff;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
@@ -37,19 +37,23 @@ import android.os.Handler;
import android.os.Looper;
import android.support.v4.media.session.MediaSessionCompat;
import android.text.Html;
+import android.text.SpannableString;
import android.text.Spanned;
+import android.text.TextPaint;
+import android.text.method.LinkMovementMethod;
+import android.text.style.ClickableSpan;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
+import android.view.Menu;
import android.view.MenuItem;
+import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.view.inputmethod.InputMethodManager;
-import android.widget.ArrayAdapter;
+import android.webkit.MimeTypeMap;
import android.widget.EditText;
-import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -66,6 +70,7 @@ import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.lifecycle.ViewModelProvider;
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -79,6 +84,7 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.MediaItem;
+import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector;
@@ -100,8 +106,12 @@ import com.google.android.exoplayer2.video.VideoListener;
import org.jetbrains.annotations.NotNull;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.text.DateFormat;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -109,6 +119,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import app.fedilab.fedilabtube.client.APIResponse;
+import app.fedilab.fedilabtube.client.MenuItemVideo;
import app.fedilab.fedilabtube.client.RetrofitPeertubeAPI;
import app.fedilab.fedilabtube.client.data.AccountData.Account;
import app.fedilab.fedilabtube.client.data.CaptionData.Caption;
@@ -116,15 +127,19 @@ import app.fedilab.fedilabtube.client.data.CommentData;
import app.fedilab.fedilabtube.client.data.CommentData.Comment;
import app.fedilab.fedilabtube.client.data.PlaylistData;
import app.fedilab.fedilabtube.client.data.VideoData;
+import app.fedilab.fedilabtube.client.entities.Error;
import app.fedilab.fedilabtube.client.entities.File;
-import app.fedilab.fedilabtube.client.entities.ItemStr;
+import app.fedilab.fedilabtube.client.entities.MenuItemView;
import app.fedilab.fedilabtube.client.entities.PlaylistExist;
import app.fedilab.fedilabtube.client.entities.Report;
+import app.fedilab.fedilabtube.client.entities.UserSettings;
import app.fedilab.fedilabtube.databinding.ActivityPeertubeBinding;
import app.fedilab.fedilabtube.drawer.CommentListAdapter;
+import app.fedilab.fedilabtube.drawer.MenuAdapter;
+import app.fedilab.fedilabtube.drawer.MenuItemAdapter;
import app.fedilab.fedilabtube.helper.CacheDataSourceFactory;
-import app.fedilab.fedilabtube.helper.FullScreenMediaController;
import app.fedilab.fedilabtube.helper.Helper;
+import app.fedilab.fedilabtube.helper.HelperInstance;
import app.fedilab.fedilabtube.sqlite.AccountDAO;
import app.fedilab.fedilabtube.sqlite.Sqlite;
import app.fedilab.fedilabtube.viewmodel.CaptionsVM;
@@ -137,29 +152,34 @@ import app.fedilab.fedilabtube.webview.CustomWebview;
import app.fedilab.fedilabtube.webview.MastalabWebChromeClient;
import app.fedilab.fedilabtube.webview.MastalabWebViewClient;
import es.dmoral.toasty.Toasty;
+import su.litvak.chromecast.api.v2.ChromeCast;
+import su.litvak.chromecast.api.v2.MediaStatus;
+import su.litvak.chromecast.api.v2.Status;
+import static app.fedilab.fedilabtube.MainActivity.chromeCast;
+import static app.fedilab.fedilabtube.MainActivity.chromeCasts;
+import static app.fedilab.fedilabtube.MainActivity.chromecastActivated;
import static app.fedilab.fedilabtube.client.RetrofitPeertubeAPI.ActionType.ADD_COMMENT;
import static app.fedilab.fedilabtube.client.RetrofitPeertubeAPI.ActionType.RATEVIDEO;
import static app.fedilab.fedilabtube.client.RetrofitPeertubeAPI.ActionType.REPLY;
import static app.fedilab.fedilabtube.client.RetrofitPeertubeAPI.ActionType.REPORT_ACCOUNT;
import static app.fedilab.fedilabtube.client.RetrofitPeertubeAPI.ActionType.REPORT_VIDEO;
+import static app.fedilab.fedilabtube.helper.Helper.CAST_ID;
import static app.fedilab.fedilabtube.helper.Helper.getAttColor;
-import static app.fedilab.fedilabtube.helper.Helper.getLiveInstance;
import static app.fedilab.fedilabtube.helper.Helper.isLoggedIn;
import static app.fedilab.fedilabtube.helper.Helper.loadGiF;
+import static app.fedilab.fedilabtube.helper.Helper.peertubeInformation;
import static com.google.android.exoplayer2.Player.MEDIA_ITEM_TRANSITION_REASON_AUTO;
-public class PeertubeActivity extends AppCompatActivity implements CommentListAdapter.AllCommentRemoved, Player.EventListener, VideoListener, TorrentListener {
+public class PeertubeActivity extends AppCompatActivity implements CommentListAdapter.AllCommentRemoved, Player.EventListener, VideoListener, TorrentListener, MenuAdapter.ItemClicked, MenuItemAdapter.ItemAction {
public static String video_id;
public static List playedVideos = new ArrayList<>();
private String peertubeInstance, videoUuid;
- private FullScreenMediaController.fullscreen fullscreen;
private ImageView fullScreenIcon;
private SimpleExoPlayer player;
private boolean fullScreenMode;
- private Dialog fullScreenDialog;
private VideoData.Video peertube;
private int mode;
private Map> playlists;
@@ -182,6 +202,11 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
private String show_more_content;
private videoOrientation videoOrientationType;
private int initialOrientation;
+ private String currentResolution;
+ private String currentCaption;
+ private boolean isRemote;
+ private boolean willPlayFromIntent;
+ private String chromeCastVideoURL;
public static void hideKeyboard(Activity activity) {
if (activity != null && activity.getWindow() != null) {
@@ -208,7 +233,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
@Override
public void onStreamStarted(Torrent torrent) {
- startStream(torrent.getVideoFile().getAbsolutePath(), null, autoPlay, -1, null, null);
+ startStream(torrent.getVideoFile().getAbsolutePath(), null, autoPlay, -1, null, null, true);
}
@Override
@@ -232,7 +257,6 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
binding = ActivityPeertubeBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
@@ -245,13 +269,15 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
Account account = new AccountDAO(PeertubeActivity.this, db).getAccountByToken(token);
Helper.loadGiF(PeertubeActivity.this, account.getAvatar() != null ? account.getAvatar().getPath() : null, binding.myPp);
}
-
+ isRemote = false;
TorrentOptions torrentOptions = new TorrentOptions.Builder()
.saveLocation(getCacheDir())
.autoDownload(true)
.removeFilesAfterStop(true)
.build();
+
+ fullScreenMode = false;
torrentStream = TorrentStream.init(torrentOptions);
torrentStream.addListener(PeertubeActivity.this);
initialOrientation = getResources().getConfiguration().orientation;
@@ -283,14 +309,14 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
Bundle b = intent.getExtras();
if (b != null) {
- peertubeInstance = b.getString("peertube_instance", Helper.getLiveInstance(PeertubeActivity.this));
+ peertubeInstance = b.getString("peertube_instance", HelperInstance.getLiveInstance(PeertubeActivity.this));
videoUuid = b.getString("video_uuid", null);
isMyVideo = b.getBoolean("isMyVideo", false);
sepiaSearch = b.getBoolean("sepia_search", false);
peertube = b.getParcelable("video");
}
- manageIntentUrl(intent);
+ willPlayFromIntent = manageIntentUrl(intent);
binding.peertubeDescriptionMore.setOnClickListener(v -> {
if (show_more_content != null && peertube != null) {
@@ -314,6 +340,11 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
playInMinimized = false;
}
+ if (peertube != null && peertube.isNsfw()) {
+ binding.videoSensitive.setVisibility(View.VISIBLE);
+ } else {
+ binding.videoSensitive.setVisibility(View.INVISIBLE);
+ }
if (mode == Helper.VIDEO_MODE_WEBVIEW) {
binding.webviewVideo.setVisibility(View.VISIBLE);
binding.mediaVideo.setVisibility(View.GONE);
@@ -322,29 +353,12 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
MastalabWebChromeClient mastalabWebChromeClient = new MastalabWebChromeClient(PeertubeActivity.this, webview_video, binding.mainMediaFrame, binding.videoLayout);
mastalabWebChromeClient.setOnToggledFullscreen(fullscreen -> {
-
if (fullscreen) {
binding.videoLayout.setVisibility(View.VISIBLE);
- WindowManager.LayoutParams attrs = getWindow().getAttributes();
- attrs.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
- attrs.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
- getWindow().setAttributes(attrs);
- getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
- binding.peertubeInformationContainer.setVisibility(View.GONE);
- if (videoOrientationType == videoOrientation.LANDSCAPE) {
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
- } else {
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- }
} else {
- WindowManager.LayoutParams attrs = getWindow().getAttributes();
- attrs.flags &= ~WindowManager.LayoutParams.FLAG_FULLSCREEN;
- attrs.flags &= ~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
- getWindow().setAttributes(attrs);
- getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
binding.videoLayout.setVisibility(View.GONE);
- binding.peertubeInformationContainer.setVisibility(View.VISIBLE);
}
+ toogleFullscreen(fullscreen);
});
binding.webviewVideo.getSettings().setAllowFileAccess(true);
binding.webviewVideo.setWebChromeClient(mastalabWebChromeClient);
@@ -361,21 +375,23 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
if (mode != Helper.VIDEO_MODE_WEBVIEW) {
binding.doubleTapPlayerView.setControllerShowTimeoutMs(1000);
binding.doubleTapPlayerView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FIT);
- initFullscreenDialog();
- initFullscreenButton();
+ initControllerButtons();
binding.doubleTapPlayerView
.setDoubleTapDelay(500);
binding.doubleTapPlayerView.setDoubleTapEnabled(true);
+ binding.doubleTapPlayerView.setControllerShowTimeoutMs(0);
binding.mediaVideo.performListener(new YouTubeOverlay.PerformListener() {
@Override
public void onAnimationStart() {
binding.mediaVideo.setVisibility(View.VISIBLE);
+ binding.doubleTapPlayerView.setUseController(false);
}
@Override
public void onAnimationEnd() {
binding.mediaVideo.setVisibility(View.GONE);
+ binding.doubleTapPlayerView.setUseController(true);
}
}).playerView(binding.doubleTapPlayerView).seekSeconds(10);
binding.doubleTapPlayerView.setPlayer(player);
@@ -389,7 +405,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
binding.closeReply.setOnClickListener(v -> closeCommentThread());
binding.closePost.setOnClickListener(v -> closePostComment());
- commentListAdapter = new CommentListAdapter(comments, isMyVideo || Helper.isVideoOwner(PeertubeActivity.this, peertube), false);
+ commentListAdapter = new CommentListAdapter(comments, isMyVideo || Helper.isVideoOwner(PeertubeActivity.this, peertube), false, peertubeInstance, sepiaSearch);
commentListAdapter.allCommentRemoved = PeertubeActivity.this;
LinearLayoutManager mLayoutManager = new LinearLayoutManager(PeertubeActivity.this);
binding.peertubeComments.setLayoutManager(mLayoutManager);
@@ -410,22 +426,58 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
}
}
});
- if (peertube != null && sepiaSearch && peertube.getEmbedUrl() != null && Helper.isLoggedIn(PeertubeActivity.this)) {
+ if (!willPlayFromIntent && peertube != null && sepiaSearch && peertube.getEmbedUrl() != null && Helper.isLoggedIn(PeertubeActivity.this)) {
SearchVM viewModelSearch = new ViewModelProvider(PeertubeActivity.this).get(SearchVM.class);
- viewModelSearch.getVideos("0", peertube.getEmbedUrl()).observe(PeertubeActivity.this, this::manageVIewVideos);
+ viewModelSearch.getVideos("0", peertube.getUuid()).observe(PeertubeActivity.this, this::manageVIewVideos);
} else {
playVideo();
}
+
registBroadcastReceiver();
if (autoFullscreen && autoPlay) {
openFullscreenDialog();
- if (videoOrientationType == videoOrientation.LANDSCAPE) {
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
- } else {
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- }
}
- binding.postCommentButton.setOnClickListener(v -> openPostComment(null, 0));
+ binding.postCommentButton.setOnClickListener(v -> {
+ if (isLoggedIn(PeertubeActivity.this) && !sepiaSearch) {
+ openPostComment(null, 0);
+ } else {
+ if (sepiaSearch) {
+ Toasty.info(PeertubeActivity.this, getString(R.string.federation_issue), Toasty.LENGTH_SHORT).show();
+ } else {
+ Toasty.error(PeertubeActivity.this, getString(R.string.not_logged_in), Toast.LENGTH_SHORT).show();
+ }
+ }
+ });
+
+ binding.castPlay.setOnClickListener(v -> {
+ binding.castLoader.setVisibility(View.VISIBLE);
+ if (chromeCast != null) {
+ new Thread(() -> {
+ try {
+ int icon = -1;
+ if (chromeCast.getMediaStatus().playerState == MediaStatus.PlayerState.PLAYING) {
+ chromeCast.pause();
+ icon = R.drawable.ic_baseline_play_arrow_32;
+ } else if (chromeCast.getMediaStatus().playerState == MediaStatus.PlayerState.PAUSED) {
+ chromeCast.play();
+ icon = R.drawable.ic_baseline_pause_32;
+ }
+ if (icon != -1) {
+ Handler mainHandler = new Handler(Looper.getMainLooper());
+ int finalIcon = icon;
+ Runnable myRunnable = () -> binding.castPlay.setImageResource(finalIcon);
+ mainHandler.post(myRunnable);
+ }
+ Handler mainHandler = new Handler(Looper.getMainLooper());
+ Runnable myRunnable = () -> binding.castLoader.setVisibility(View.GONE);
+ mainHandler.post(myRunnable);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }).start();
+ }
+ });
+
}
private void manageVIewVideos(APIResponse apiResponse) {
@@ -434,7 +486,12 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
return;
}
peertube = apiResponse.getPeertubes().get(0);
- if (peertube.getUserHistory() != null) {
+ if (peertube.isNsfw()) {
+ binding.videoSensitive.setVisibility(View.VISIBLE);
+ } else {
+ binding.videoSensitive.setVisibility(View.INVISIBLE);
+ }
+ if (player != null && peertube.getUserHistory() != null) {
player.seekTo(peertube.getUserHistory().getCurrentTime() * 1000);
}
sepiaSearch = false;
@@ -477,7 +534,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
comment.setInReplyToCommentId(null);
comment.setTotalReplies(0);
commentsThread.add(0, comment);
- commentReplyListAdapter = new CommentListAdapter(commentsThread, Helper.isVideoOwner(PeertubeActivity.this, peertube), true);
+ commentReplyListAdapter = new CommentListAdapter(commentsThread, Helper.isVideoOwner(PeertubeActivity.this, peertube), true, peertubeInstance, sepiaSearch);
LinearLayoutManager mLayoutManager = new LinearLayoutManager(PeertubeActivity.this);
binding.peertubeReply.setLayoutManager(mLayoutManager);
binding.peertubeReply.setNestedScrollingEnabled(false);
@@ -506,8 +563,10 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
super.onNewIntent(intent);
Bundle b = intent.getExtras();
if (b != null) {
- peertubeInstance = b.getString("peertube_instance", Helper.getLiveInstance(PeertubeActivity.this));
+ isRemote = false;
+ peertubeInstance = b.getString("peertube_instance", HelperInstance.getLiveInstance(PeertubeActivity.this));
videoUuid = b.getString("video_uuid", null);
+ setRequestedOrientationCustom(initialOrientation);
if (comments != null && comments.size() > 0) {
int number = comments.size();
comments.clear();
@@ -515,17 +574,35 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
}
playVideo();
}
- manageIntentUrl(intent);
+ willPlayFromIntent = manageIntentUrl(intent);
}
- private void manageIntentUrl(Intent intent) {
+ private boolean manageIntentUrl(Intent intent) {
if (intent.getData() != null) { //Comes from a link
String url = intent.getData().toString();
- Pattern link = Pattern.compile("(https?://[\\da-z.-]+\\.[a-z.]{2,10})/videos/watch/(\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12})$");
+ Pattern link = Pattern.compile("(https?://[\\da-z.-]+\\.[a-z.]{2,10})/videos/watch/(\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12})(\\?start=(\\d+[hH])?(\\d+[mM])?(\\d+[sS])?)?$");
Matcher matcherLink = link.matcher(url);
if (matcherLink.find()) {
String instance = matcherLink.group(1);
String uuid = matcherLink.group(2);
+ String hour = matcherLink.group(4);
+ String min = matcherLink.group(5);
+ String sec = matcherLink.group(6);
+ int hourInt, minInt, secInt;
+ int totalSeconds = 0;
+ if (hour != null) {
+ hourInt = Integer.parseInt(hour.replace("h", ""));
+ totalSeconds += 3600 * hourInt;
+ }
+ if (min != null) {
+ minInt = Integer.parseInt(min.replace("m", ""));
+ totalSeconds += 60 * minInt;
+ }
+ if (sec != null) {
+ secInt = Integer.parseInt(sec.replace("s", ""));
+ totalSeconds += secInt;
+ }
+
if (instance != null && uuid != null) {
peertubeInstance = instance.replace("https://", "").replace("http://", "");
sepiaSearch = true; // Sepia search flag is used because, at this time we don't know if the video is federated.
@@ -533,8 +610,24 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
peertube = new VideoData.Video();
peertube.setUuid(uuid);
peertube.setEmbedUrl(url);
- SearchVM viewModelSearch = new ViewModelProvider(PeertubeActivity.this).get(SearchVM.class);
- viewModelSearch.getVideos("0", peertube.getEmbedUrl()).observe(PeertubeActivity.this, this::manageVIewVideos);
+ if (totalSeconds > 0) {
+ VideoData.UserHistory userHistory = new VideoData.UserHistory();
+ userHistory.setCurrentTime(totalSeconds);
+ peertube.setUserHistory(userHistory);
+ }
+ TimelineVM viewModelTimeline = new ViewModelProvider(PeertubeActivity.this).get(TimelineVM.class);
+ viewModelTimeline.getVideo(peertubeInstance, peertube.getUuid(), false).observe(PeertubeActivity.this, this::manageVIewVideo);
+ if (player != null) {
+ player.release();
+ }
+ if (comments != null && comments.size() > 0) {
+ int number = comments.size();
+ comments.clear();
+ commentListAdapter.notifyItemRangeRemoved(0, number);
+ }
+ fetchComments();
+ isRemote = true;
+ return true;
} else {
Helper.forwardToAnotherApp(PeertubeActivity.this, intent);
finish();
@@ -544,6 +637,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
finish();
}
}
+ return false;
}
private void playVideo() {
@@ -554,52 +648,54 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
binding.doubleTapPlayerView.setPlayer(player);
binding.loader.setVisibility(View.GONE);
player.setPlayWhenReady(autoPlay);
+ if (autoPlay) {
+ binding.doubleTapPlayerView.hideController();
+ }
captions = null;
}
+ currentResolution = null;
show_more_content = null;
+ currentCaption = "null";
binding.peertubeDescriptionMore.setVisibility(View.GONE);
+
if (autoFullscreen && autoPlay) {
- fullscreen = FullScreenMediaController.fullscreen.ON;
- setFullscreen(FullScreenMediaController.fullscreen.ON);
- fullScreenMode = true;
openFullscreenDialog();
- if (videoOrientationType == videoOrientation.LANDSCAPE) {
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
- } else {
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- }
- } else {
- fullscreen = FullScreenMediaController.fullscreen.OFF;
- setFullscreen(FullScreenMediaController.fullscreen.OFF);
- fullScreenMode = false;
}
binding.peertubePlaylist.setVisibility(View.VISIBLE);
- binding.peertubeBookmark.setVisibility(View.GONE);
TimelineVM feedsViewModel = new ViewModelProvider(PeertubeActivity.this).get(TimelineVM.class);
- feedsViewModel.getVideo(sepiaSearch ? peertubeInstance : null, videoUuid, isMyVideo).observe(PeertubeActivity.this, this::manageVIewVideo);
+ if (!isRemote) {
+ feedsViewModel.getVideo(sepiaSearch ? peertubeInstance : null, videoUuid, isMyVideo).observe(PeertubeActivity.this, this::manageVIewVideo);
+ }
CaptionsVM captionsViewModel = new ViewModelProvider(PeertubeActivity.this).get(CaptionsVM.class);
captionsViewModel.getCaptions(sepiaSearch ? peertubeInstance : null, videoUuid).observe(PeertubeActivity.this, this::manageCaptions);
new Thread(() -> {
try {
- RetrofitPeertubeAPI api = new RetrofitPeertubeAPI(PeertubeActivity.this);
+ RetrofitPeertubeAPI api;
+ if (peertubeInstance != null) {
+ api = new RetrofitPeertubeAPI(PeertubeActivity.this, peertubeInstance, null);
+ } else {
+ api = new RetrofitPeertubeAPI(PeertubeActivity.this);
+ }
VideoData.Description description = api.getVideoDescription(videoUuid);
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> {
- if (description == null) {
- binding.peertubeDescriptionMore.setVisibility(View.GONE);
- show_more_content = null;
- } else {
- if (!PeertubeActivity.this.isFinishing()) {
- if (peertube != null && peertube.getDescription() != null && description.getDescription() != null && description.getDescription().compareTo(peertube.getDescription()) > 0) {
- binding.peertubeDescriptionMore.setVisibility(View.VISIBLE);
- show_more_content = description.getDescription();
- } else {
- binding.peertubeDescriptionMore.setVisibility(View.GONE);
- show_more_content = null;
+ if (!isFinishing()) {
+ if (description == null) {
+ binding.peertubeDescriptionMore.setVisibility(View.GONE);
+ show_more_content = null;
+ } else {
+ if (!PeertubeActivity.this.isFinishing()) {
+ if (peertube != null && ((peertube.getDescription() == null && description.getDescription() != null && description.getDescription().trim().length() > 0) || (peertube.getDescription() != null && description.getDescription() != null
+ && description.getDescription().compareTo(peertube.getDescription()) > 0))) {
+ binding.peertubeDescriptionMore.setVisibility(View.VISIBLE);
+ show_more_content = description.getDescription();
+ } else {
+ binding.peertubeDescriptionMore.setVisibility(View.GONE);
+ show_more_content = null;
+ }
}
}
}
-
};
mainHandler.post(myRunnable);
} catch (Exception e) {
@@ -608,18 +704,19 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
}).start();
}
- public void change() {
- if (fullscreen == FullScreenMediaController.fullscreen.ON) {
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN |
- WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- Objects.requireNonNull(getSupportActionBar()).hide();
- binding.peertubeInformationContainer.setVisibility(View.GONE);
- } else {
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
- WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
- Objects.requireNonNull(getSupportActionBar()).show();
- binding.peertubeInformationContainer.setVisibility(View.VISIBLE);
+ @Override
+ public boolean onCreateOptionsMenu(@NotNull Menu menu) {
+ getMenuInflater().inflate(R.menu.video_menu, menu);
+ MenuItem castItem = menu.findItem(R.id.action_cast);
+ if (chromeCasts != null && chromeCasts.size() > 0) {
+ castItem.setVisible(true);
+ if (chromeCast != null && chromeCast.isConnected()) {
+ castItem.setIcon(R.drawable.ic_baseline_cast_connected_24);
+ } else {
+ castItem.setIcon(R.drawable.ic_baseline_cast_24);
+ }
}
+ return true;
}
@Override
@@ -630,6 +727,101 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
}
finish();
return true;
+ } else if (item.getItemId() == R.id.action_cast) {
+ if (chromeCasts != null && chromeCasts.size() > 0) {
+ String[] chromecast_choice = new String[chromeCasts.size()];
+ AlertDialog.Builder alt_bld = new AlertDialog.Builder(this);
+ alt_bld.setTitle(R.string.chromecast_choice);
+ int i = 0;
+ for (ChromeCast cc : chromeCasts) {
+ chromecast_choice[i] = cc.getTitle();
+ i++;
+ }
+ i = 0;
+ for (ChromeCast cc : chromeCasts) {
+ if (chromecastActivated && cc.isConnected()) {
+ break;
+ }
+ i++;
+ }
+
+ alt_bld.setSingleChoiceItems(chromecast_choice, i, (dialog, position) -> {
+ chromeCast = chromeCasts.get(position);
+ new Thread(() -> {
+ if (chromeCast != null) {
+ Intent intentBC = new Intent(Helper.RECEIVE_CAST_SETTINGS);
+ Bundle b = new Bundle();
+ if (chromecastActivated) {
+ b.putInt("displayed", 0);
+ intentBC.putExtras(b);
+ LocalBroadcastManager.getInstance(PeertubeActivity.this).sendBroadcast(intentBC);
+ Handler mainHandler = new Handler(Looper.getMainLooper());
+ Runnable myRunnable = () -> {
+ binding.doubleTapPlayerView.setVisibility(View.VISIBLE);
+ binding.castController.setVisibility(View.GONE);
+ };
+ mainHandler.post(myRunnable);
+
+ } else {
+ b.putInt("displayed", 1);
+ b.putParcelable("castedTube", peertube);
+ intentBC.putExtras(b);
+ LocalBroadcastManager.getInstance(PeertubeActivity.this).sendBroadcast(intentBC);
+ try {
+ Handler mainHandler = new Handler(Looper.getMainLooper());
+ Runnable myRunnable = () -> {
+ invalidateOptionsMenu();
+ binding.castLoader.setVisibility(View.VISIBLE);
+ player.setPlayWhenReady(false);
+ binding.doubleTapPlayerView.setVisibility(View.GONE);
+ binding.castController.setVisibility(View.VISIBLE);
+ dialog.dismiss();
+ if (chromeCastVideoURL != null) {
+ if (player != null && player.getCurrentPosition() > 0) {
+ chromeCastVideoURL += "?start=" + (player.getCurrentPosition() / 1000);
+ }
+ }
+ };
+ mainHandler.post(myRunnable);
+ if (!chromeCast.isConnected()) {
+ chromeCast.connect();
+ }
+ myRunnable = this::invalidateOptionsMenu;
+ mainHandler.post(myRunnable);
+ Status status = chromeCast.getStatus();
+ if (chromeCast.isAppAvailable(CAST_ID) && !status.isAppRunning(CAST_ID)) {
+ chromeCast.launchApp(CAST_ID);
+ }
+
+ if (chromeCastVideoURL != null) {
+ String mime = MimeTypeMap.getFileExtensionFromUrl(chromeCastVideoURL);
+ chromeCast.setRequestTimeout(60000);
+ chromeCast.load(peertube.getTitle(), null, chromeCastVideoURL, mime);
+ chromeCast.play();
+ binding.castPlay.setImageResource(R.drawable.ic_baseline_pause_32);
+ }
+ myRunnable = () -> binding.castLoader.setVisibility(View.GONE);
+ mainHandler.post(myRunnable);
+ } catch (IOException | GeneralSecurityException e) {
+ e.printStackTrace();
+ }
+ }
+
+ Handler mainHandler = new Handler(Looper.getMainLooper());
+ Runnable myRunnable = () -> {
+ invalidateOptionsMenu();
+ dialog.dismiss();
+ };
+ mainHandler.post(myRunnable);
+
+ }
+ }).start();
+
+ });
+ alt_bld.setPositiveButton(R.string.close, (dialog, id) -> dialog.dismiss());
+ AlertDialog alert = alt_bld.create();
+ alert.show();
+ }
}
return super.onOptionsItemSelected(item);
}
@@ -671,13 +863,6 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
alertDialog2.show();
}
- public FullScreenMediaController.fullscreen getFullscreen() {
- return fullscreen;
- }
-
- public void setFullscreen(FullScreenMediaController.fullscreen fullscreen) {
- this.fullscreen = fullscreen;
- }
public void manageCaptions(APIResponse apiResponse) {
if (apiResponse == null || (apiResponse.getError() != null) || apiResponse.getCaptions() == null || apiResponse.getCaptions().size() == 0) {
@@ -710,12 +895,64 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
i++;
}
nextVideo = apiResponse.getPeertubes().get(i);
- MediaItem mediaItem = new MediaItem.Builder().setUri(Uri.parse(nextVideo.getFileUrl(null, PeertubeActivity.this))).build();
- player.addMediaItem(mediaItem);
+ if (!playedVideos.contains(nextVideo.getId()) && player != null && nextVideo.getFileUrl(null, PeertubeActivity.this) != null) {
+ MediaItem mediaItem = new MediaItem.Builder().setUri(Uri.parse(nextVideo.getFileUrl(null, PeertubeActivity.this))).build();
+ player.addMediaItem(mediaItem);
+ }
}
- @SuppressLint("ClickableViewAccessibility")
+
public void manageVIewVideo(APIResponse apiResponse) {
+ if (!isRemote && apiResponse != null && apiResponse.getPeertubes() != null && apiResponse.getPeertubes().get(0).getErrorCode() == 1 && apiResponse.getPeertubes().get(0).getOriginUrl() != null) {
+ String url = apiResponse.getPeertubes().get(0).getOriginUrl();
+ Pattern link = Pattern.compile("(https?://[\\da-z.-]+\\.[a-z.]{2,10})/videos/watch/(\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12})(\\?start=(\\d+[hH])?(\\d+[mM])?(\\d+[sS])?)?$");
+ Matcher matcherLink = link.matcher(url);
+ if (matcherLink.find()) {
+ String instance = matcherLink.group(1);
+ String uuid = matcherLink.group(2);
+ String hour = matcherLink.group(4);
+ String min = matcherLink.group(5);
+ String sec = matcherLink.group(6);
+ int hourInt, minInt, secInt;
+ int totalSeconds = 0;
+ if (hour != null) {
+ hourInt = Integer.parseInt(hour.replace("h", ""));
+ totalSeconds += 3600 * hourInt;
+ }
+ if (min != null) {
+ minInt = Integer.parseInt(min.replace("m", ""));
+ totalSeconds += 60 * minInt;
+ }
+ if (sec != null) {
+ secInt = Integer.parseInt(sec.replace("strue", ""));
+ totalSeconds += secInt;
+ }
+
+ if (instance != null && uuid != null) {
+ peertubeInstance = instance.replace("https://", "").replace("http://", "");
+ sepiaSearch = true; // Sepia search flag is used because, at this time we don't know if the video is federated.
+ videoUuid = uuid;
+ peertube = new VideoData.Video();
+ peertube.setUuid(uuid);
+ peertube.setEmbedUrl(url);
+ isRemote = true;
+ if (totalSeconds > 0) {
+ VideoData.UserHistory userHistory = new VideoData.UserHistory();
+ userHistory.setCurrentTime(totalSeconds);
+ peertube.setUserHistory(userHistory);
+ }
+ TimelineVM viewModelTimeline = new ViewModelProvider(PeertubeActivity.this).get(TimelineVM.class);
+ viewModelTimeline.getVideo(peertubeInstance, peertube.getUuid(), false).observe(PeertubeActivity.this, this::manageVIewVideo);
+ }
+ }
+ return;
+ }
+
+ if (apiResponse != null && apiResponse.getPeertubes() != null && apiResponse.getPeertubes().size() > 0 && apiResponse.getPeertubes().get(0).getErrorMessage() != null) {
+ Toasty.error(PeertubeActivity.this, apiResponse.getPeertubes().get(0).getErrorMessage(), Toast.LENGTH_LONG).show();
+ binding.loader.setVisibility(View.GONE);
+ return;
+ }
if (apiResponse == null || (apiResponse.getError() != null) || apiResponse.getPeertubes() == null || apiResponse.getPeertubes().size() == 0) {
Toasty.error(PeertubeActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
binding.loader.setVisibility(View.GONE);
@@ -727,11 +964,19 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
return;
}
long position = -1;
+
+ long previousPositionHistory = 0;
+ if (peertube != null && peertube.getUserHistory() != null) {
+ previousPositionHistory = peertube.getUserHistory().getCurrentTime();
+ }
+ peertube = apiResponse.getPeertubes().get(0);
+ VideoData.UserHistory userHistory = new VideoData.UserHistory();
+ userHistory.setCurrentTime(previousPositionHistory);
+ peertube.setUserHistory(userHistory);
+
if (peertube.getUserHistory() != null) {
position = peertube.getUserHistory().getCurrentTime() * 1000;
}
-
- peertube = apiResponse.getPeertubes().get(0);
if (peertube.getTags() != null && peertube.getTags().size() > 0) {
SearchVM searchViewModel = new ViewModelProvider(PeertubeActivity.this).get(SearchVM.class);
searchViewModel.searchNextVideos(peertube.getTags()).observe(PeertubeActivity.this, this::manageNextVideos);
@@ -748,31 +993,87 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
binding.writeCommentContainer.setVisibility(View.GONE);
}
+ if (peertube.isNsfw()) {
+ binding.videoSensitive.setVisibility(View.VISIBLE);
+ } else {
+ binding.videoSensitive.setVisibility(View.INVISIBLE);
+ }
+
binding.peertubePlaylist.setOnClickListener(v -> {
PlaylistsVM viewModelOwnerPlaylist = new ViewModelProvider(PeertubeActivity.this).get(PlaylistsVM.class);
viewModelOwnerPlaylist.manage(PlaylistsVM.action.GET_PLAYLISTS, null, null).observe(PeertubeActivity.this, this::manageVIewPlaylists);
});
- if (peertube.isCommentsEnabled()) {
- if (Helper.isLoggedIn(PeertubeActivity.this)) {
- binding.postCommentButton.setVisibility(View.VISIBLE);
- } else {
- binding.postCommentButton.setVisibility(View.GONE);
+ binding.videoInformation.setOnClickListener(v -> {
+ AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(PeertubeActivity.this);
+ LayoutInflater inflater = getLayoutInflater();
+ View dialogView = inflater.inflate(R.layout.popup_video_info, new LinearLayout(PeertubeActivity.this), false);
+ TextView info_privacy = dialogView.findViewById(R.id.info_privacy);
+ TextView info_published_at = dialogView.findViewById(R.id.info_published_at);
+ TextView info_category = dialogView.findViewById(R.id.info_category);
+ TextView info_license = dialogView.findViewById(R.id.info_license);
+ TextView info_language = dialogView.findViewById(R.id.info_language);
+ TextView info_duration = dialogView.findViewById(R.id.info_duration);
+ TextView info_tags = dialogView.findViewById(R.id.info_tags);
+
+ LinkedHashMap privaciesInit = new LinkedHashMap<>(peertubeInformation.getPrivacies());
+ info_privacy.setText(privaciesInit.get(peertube.getPrivacy().getId()));
+ LinkedHashMap licenseInit = new LinkedHashMap<>(peertubeInformation.getLicences());
+ info_license.setText(licenseInit.get(peertube.getLicence().getId()));
+ LinkedHashMap languageStr = new LinkedHashMap<>(peertubeInformation.getLanguages());
+ info_language.setText(languageStr.get(peertube.getLanguage().getId()));
+ LinkedHashMap categoryInit = new LinkedHashMap<>(peertubeInformation.getCategories());
+ info_category.setText(categoryInit.get(peertube.getCategory().getId()));
+
+ info_duration.setText(Helper.secondsToString(peertube.getDuration()));
+ String format = DateFormat.getDateInstance(DateFormat.LONG).format(peertube.getPublishedAt());
+ info_published_at.setText(format);
+ List tags = peertube.getTags();
+ StringBuilder sb = new StringBuilder();
+ for (String tag : tags) {
+ sb.append("#").append(tag).append(" ");
}
- CommentVM commentViewModel = new ViewModelProvider(PeertubeActivity.this).get(CommentVM.class);
- commentViewModel.getThread(sepiaSearch ? peertubeInstance : null, videoUuid, max_id).observe(PeertubeActivity.this, this::manageVIewComment);
- if (Helper.isLoggedIn(PeertubeActivity.this) && !sepiaSearch) {
- binding.writeCommentContainer.setVisibility(View.VISIBLE);
+
+ SpannableString spannableString = new SpannableString(sb.toString());
+ for (String tag : tags) {
+ String target = "#" + tag;
+ if (spannableString.toString().contains(target)) {
+ for (int startPosition = -1; (startPosition = spannableString.toString().indexOf(target, startPosition + 1)) != -1; startPosition++) {
+ final int endPosition = startPosition + target.length();
+ if (endPosition <= spannableString.toString().length() && endPosition >= startPosition) {
+ spannableString.setSpan(new ClickableSpan() {
+ @Override
+ public void onClick(@NonNull View textView) {
+ Intent intent = new Intent(PeertubeActivity.this, SearchActivity.class);
+ Bundle b = new Bundle();
+ String search = tag.trim();
+ b.putString("search", search);
+ intent.putExtras(b);
+ startActivity(intent);
+ }
+
+ @Override
+ public void updateDrawState(@NonNull TextPaint ds) {
+ super.updateDrawState(ds);
+ ds.setUnderlineText(false);
+ ds.setColor(getResources().getColor(R.color.colorAccent));
+ }
+ },
+ startPosition, endPosition,
+ Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+ }
+ }
+ }
}
- binding.peertubeComments.setVisibility(View.VISIBLE);
- } else {
- binding.postCommentButton.setVisibility(View.GONE);
- binding.peertubeComments.setVisibility(View.GONE);
- binding.writeCommentContainer.setVisibility(View.GONE);
- binding.noActionText.setText(getString(R.string.comment_no_allowed_peertube));
- binding.noAction.setVisibility(View.VISIBLE);
- binding.writeCommentContainer.setVisibility(View.GONE);
- }
+ info_tags.setText(spannableString, TextView.BufferType.SPANNABLE);
+ info_tags.setMovementMethod(LinkMovementMethod.getInstance());
+ dialogBuilder.setView(dialogView);
+ dialogBuilder.setNeutralButton(R.string.close, (dialog, id) -> dialog.dismiss());
+ AlertDialog alertDialog = dialogBuilder.create();
+ alertDialog.show();
+ });
+
+ fetchComments();
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
setTitle(peertube.getName());
@@ -783,7 +1084,13 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
binding.peertubeDislikeCount.setText(Helper.withSuffix(peertube.getDislikes()));
binding.peertubeLikeCount.setText(Helper.withSuffix(peertube.getLikes()));
binding.peertubeViewCount.setText(Helper.withSuffix(peertube.getViews()));
- loadGiF(PeertubeActivity.this, peertube.getChannel().getAvatar() != null ? peertube.getChannel().getAvatar().getPath() : null, binding.ppChannel);
+ String ppChannelURL;
+ if (sepiaSearch) {
+ ppChannelURL = peertube.getChannel().getAvatar() != null ? "https://" + peertubeInstance + peertube.getChannel().getAvatar().getPath() : null;
+ } else {
+ ppChannelURL = peertube.getChannel().getAvatar() != null ? peertube.getChannel().getAvatar().getPath() : null;
+ }
+ loadGiF(PeertubeActivity.this, ppChannelURL, binding.ppChannel);
binding.ppChannel.setOnClickListener(v -> {
Intent intent = new Intent(PeertubeActivity.this, ShowChannelActivity.class);
Bundle b = new Bundle();
@@ -853,7 +1160,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
});
- if (mode == Helper.VIDEO_MODE_NORMAL) {
+ if (mode != Helper.VIDEO_MODE_WEBVIEW) {
player = new SimpleExoPlayer.Builder(PeertubeActivity.this).build();
player.addVideoListener(PeertubeActivity.this);
@@ -864,9 +1171,12 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
startStream(
apiResponse.getPeertubes().get(0).getFileUrl(null, PeertubeActivity.this),
apiResponse.getPeertubes().get(0).getStreamingPlaylists().size() > 0 ? apiResponse.getPeertubes().get(0).getStreamingPlaylists().get(0).getPlaylistUrl() : null,
- autoPlay, position, null, null);
+ autoPlay, position, null, null, true);
player.prepare();
player.setPlayWhenReady(autoPlay);
+ if (autoPlay) {
+ binding.doubleTapPlayerView.hideController();
+ }
}
@@ -875,9 +1185,6 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
popup.getMenuInflater()
.inflate(R.menu.main_video, popup.getMenu());
- if (captions == null) {
- popup.getMenu().findItem(R.id.action_captions).setEnabled(false);
- }
if (!isMyVideo) {
popup.getMenu().findItem(R.id.action_edit).setVisible(false);
}
@@ -931,63 +1238,6 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
b.putString("video_id", peertube.getUuid());
intent.putExtras(b);
startActivity(intent);
- } else if (itemId == R.id.action_captions) {
- AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(PeertubeActivity.this);
- if (captions == null) {
- return true;
- }
-
- String[] itemsKeyLanguage = new String[captions.size() + 1];
- String[] itemsLabelLanguage = new String[captions.size() + 1];
- itemsLabelLanguage[0] = getString(R.string.none);
- itemsKeyLanguage[0] = "null";
- int i = 1;
- if (captions.size() > 0) {
- for (Caption caption : captions) {
- ItemStr lang = caption.getLanguage();
- itemsLabelLanguage[i] = lang.getLabel();
- itemsKeyLanguage[i] = lang.getId();
- i++;
- }
- }
- dialogBuilder.setSingleChoiceItems(itemsLabelLanguage, i, (dialog, which) -> {
-
- Uri uri = null;
- if (which > 0) {
- if (!sepiaSearch) {
- uri = Uri.parse("https://" + getLiveInstance(PeertubeActivity.this) + captions.get(which - 1).getCaptionPath());
- } else {
- uri = Uri.parse("https://" + peertubeInstance + captions.get(which - 1).getCaptionPath());
- }
- }
- long newPosition = player.getCurrentPosition();
-
- if (player != null)
- player.release();
-
- TrackSelector trackSelector = new DefaultTrackSelector(PeertubeActivity.this, new AdaptiveTrackSelection.Factory());
- player = new SimpleExoPlayer.Builder(PeertubeActivity.this).setTrackSelector(trackSelector).build();
- binding.mediaVideo.player(player);
- binding.doubleTapPlayerView.setPlayer(player);
- startStream(
- apiResponse.getPeertubes().get(0).getFileUrl(null, PeertubeActivity.this),
- null,
- true,
- newPosition,
- uri,
- itemsKeyLanguage[which]
- );
- dialog.dismiss();
- });
-
- dialogBuilder.setOnDismissListener(dialogInterface -> {
-
- });
- dialogBuilder.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss());
-
- AlertDialog alertDialog = dialogBuilder.create();
- alertDialog.setTitle(getString(R.string.pickup_captions));
- alertDialog.show();
} else if (itemId == R.id.action_report) {
AlertDialog alertDialog;
AlertDialog.Builder dialogBuilder;
@@ -1008,11 +1258,10 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
});
}
- private void startStream(String videoURL, String streamingPlaylistsURLS, boolean autoPlay, long position, Uri subtitles, String lang) {
- if (videoURL != null) {
+ private void stream(String videoURL, String streamingPlaylistsURLS, boolean autoPlay, long position, Uri subtitles, String lang) {
+ if (videoURL != null && !videoURL.endsWith("m3u8")) {
if (videoURL.endsWith(".torrent")) {
-
torrentStream.startStream(videoURL);
return;
} else {
@@ -1049,6 +1298,9 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
}
}
} else {
+ if (streamingPlaylistsURLS == null && videoURL != null) {
+ streamingPlaylistsURLS = videoURL;
+ }
MediaItem mediaItem = new MediaItem.Builder().setUri(Uri.parse(streamingPlaylistsURLS)).build();
HlsMediaSource hlsMediaSource = new HlsMediaSource.Factory(new DefaultHttpDataSourceFactory(System.getProperty("http.agent")))
.createMediaSource(mediaItem);
@@ -1059,17 +1311,74 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
player.seekTo(0, position);
}
player.setPlayWhenReady(autoPlay);
+ if (autoPlay) {
+ binding.doubleTapPlayerView.hideController();
+ }
+ }
+
+ private void fetchComments() {
+ if (peertube.isCommentsEnabled()) {
+ if (Helper.isLoggedIn(PeertubeActivity.this)) {
+ binding.postCommentButton.setVisibility(View.VISIBLE);
+ } else {
+ binding.postCommentButton.setVisibility(View.GONE);
+ }
+ CommentVM commentViewModel = new ViewModelProvider(PeertubeActivity.this).get(CommentVM.class);
+ commentViewModel.getThread(sepiaSearch ? peertubeInstance : null, videoUuid, max_id).observe(PeertubeActivity.this, this::manageVIewComment);
+ if (Helper.isLoggedIn(PeertubeActivity.this) && !sepiaSearch) {
+ binding.writeCommentContainer.setVisibility(View.VISIBLE);
+ }
+ binding.peertubeComments.setVisibility(View.VISIBLE);
+ binding.noAction.setVisibility(View.GONE);
+ } else {
+ binding.postCommentButton.setVisibility(View.GONE);
+ binding.peertubeComments.setVisibility(View.GONE);
+ binding.writeCommentContainer.setVisibility(View.GONE);
+ binding.noActionText.setText(getString(R.string.comment_no_allowed_peertube));
+ binding.noAction.setVisibility(View.VISIBLE);
+ binding.writeCommentContainer.setVisibility(View.GONE);
+ }
+ }
+
+ private void startStream(String videoURL, String streamingPlaylistsURLS, boolean autoPlay, long position, Uri subtitles, String lang, boolean promptNSFW) {
+
+ chromeCastVideoURL = videoURL;
+ SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
+ String nsfwAction = sharedpreferences.getString(getString(R.string.set_video_sensitive_choice), Helper.BLUR);
+ if (promptNSFW && peertube != null && peertube.isNsfw() && (nsfwAction.compareTo(Helper.BLUR) == 0 || nsfwAction.compareTo(Helper.DO_NOT_LIST) == 0)) {
+ AlertDialog alertDialog;
+ AlertDialog.Builder dialogBuilder;
+ dialogBuilder = new AlertDialog.Builder(PeertubeActivity.this);
+ dialogBuilder.setTitle(R.string.nsfw_title_warning);
+ dialogBuilder.setCancelable(false);
+ dialogBuilder.setMessage(R.string.nsfw_message_warning);
+ dialogBuilder.setNegativeButton(R.string.no, (dialog, id) -> {
+ dialog.dismiss();
+ finish();
+ });
+ dialogBuilder.setPositiveButton(R.string.play, (dialog, id) -> {
+ stream(videoURL, streamingPlaylistsURLS, autoPlay, position, subtitles, lang);
+ dialog.dismiss();
+ });
+ alertDialog = dialogBuilder.create();
+ alertDialog.show();
+ } else {
+ stream(videoURL, streamingPlaylistsURLS, autoPlay, position, subtitles, lang);
+ }
+
+
}
@Override
public void onConfigurationChanged(@NotNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
-
+ if (binding.castController.getVisibility() == View.VISIBLE) {
+ return;
+ }
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
if (mode != Helper.VIDEO_MODE_WEBVIEW) {
openFullscreenDialog();
}
- setFullscreen(FullScreenMediaController.fullscreen.ON);
if (initialOrientation == Configuration.ORIENTATION_LANDSCAPE) {
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(
ConstraintLayout.LayoutParams.MATCH_PARENT,
@@ -1082,7 +1391,6 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
if (mode != Helper.VIDEO_MODE_WEBVIEW) {
closeFullscreenDialog();
}
- setFullscreen(FullScreenMediaController.fullscreen.OFF);
if (initialOrientation == Configuration.ORIENTATION_LANDSCAPE) {
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(
ConstraintLayout.LayoutParams.MATCH_PARENT,
@@ -1092,7 +1400,6 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
binding.videoContainer.setLayoutParams(param);
}
}
- change();
}
@Override
@@ -1106,9 +1413,6 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
torrentStream.stopStream();
}
unregisterReceiver();
- if (fullScreenDialog != null && fullScreenDialog.isShowing()) {
- fullScreenDialog.dismiss();
- }
}
@Override
@@ -1123,6 +1427,9 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
onStopCalled = false;
if (player != null && !player.isPlaying()) {
player.setPlayWhenReady(autoPlay);
+ if (autoPlay) {
+ binding.doubleTapPlayerView.hideController();
+ }
}
}
@@ -1134,7 +1441,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
}
if (player != null && (!isPlayInMinimized || !playInMinimized)) {
player.setPlayWhenReady(false);
- } else if (playInMinimized) {
+ } else if (playInMinimized && binding.castController.getVisibility() != View.VISIBLE) {
enterVideoMode();
}
}
@@ -1152,6 +1459,8 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
if (player != null && isPlayInMinimized) {
if (!sharedpreferences.getBoolean(getString(R.string.set_play_screen_lock_choice), false)) {
player.setPlayWhenReady(false);
+ } else {
+ player.setWakeMode(C.WAKE_MODE_NETWORK);
}
}
}
@@ -1161,15 +1470,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
}
private void unregisterReceiver() {
- int apiLevel = Build.VERSION.SDK_INT;
-
- if (apiLevel >= 7) {
- try {
- getApplicationContext().unregisterReceiver(mPowerKeyReceiver);
- } catch (IllegalArgumentException e) {
- mPowerKeyReceiver = null;
- }
- } else {
+ if (mPowerKeyReceiver != null) {
getApplicationContext().unregisterReceiver(mPowerKeyReceiver);
mPowerKeyReceiver = null;
}
@@ -1184,6 +1485,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
private void enterVideoMode() {
if (playInMinimized && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && player != null) {
isPlayInMinimized = true;
+ setRequestedOrientationCustom(initialOrientation);
MediaSessionCompat mediaSession = new MediaSessionCompat(this, getPackageName());
MediaSessionConnector mediaSessionConnector = new MediaSessionConnector(mediaSession);
mediaSessionConnector.setPlayer(player);
@@ -1198,25 +1500,39 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
@Override
public void onBackPressed() {
+
+ if (binding.videoParamsSubmenu.getVisibility() == View.VISIBLE) {
+ closeSubMenuMenuOptions();
+ return;
+ }
+ if (binding.videoParams.getVisibility() == View.VISIBLE) {
+ closeMainMenuOptions();
+ return;
+ }
if (binding.postComment.getVisibility() == View.VISIBLE) {
closePostComment();
- } else if (binding.replyThread.getVisibility() == View.VISIBLE) {
+ return;
+ }
+ if (binding.replyThread.getVisibility() == View.VISIBLE) {
closeCommentThread();
+ return;
+ }
+
+ if (fullScreenMode && player != null && player.isPlaying()) {
+ player.setPlayWhenReady(false);
+ return;
+ }
+
+ if (playInMinimized && player != null) {
+ enterVideoMode();
} else {
- if (playInMinimized && player != null) {
- enterVideoMode();
- } else {
- super.onBackPressed();
- }
+ super.onBackPressed();
}
}
@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig) {
- if (isInPictureInPictureMode) {
- setFullscreen(FullScreenMediaController.fullscreen.ON);
- } else {
- setFullscreen(FullScreenMediaController.fullscreen.OFF);
+ if (!isInPictureInPictureMode) {
if (onStopCalled) {
isPlayInMinimized = false;
finishAndRemoveTask();
@@ -1224,80 +1540,46 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
}
}
- public void displayResolution() {
- AlertDialog.Builder builderSingle = new AlertDialog.Builder(PeertubeActivity.this);
- builderSingle.setTitle(R.string.pickup_resolution);
- final ArrayAdapter arrayAdapter = new ArrayAdapter<>(PeertubeActivity.this, android.R.layout.select_dialog_item);
- for (File file : peertube.getFiles()) {
- if (file.getResolutions() != null) {
- if (file.getResolutions().getLabel().compareTo("0p") != 0) {
- arrayAdapter.add(file.getResolutions().getLabel());
+
+ private void toogleFullscreen(boolean fullscreen) {
+
+ if (fullscreen) {
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN |
+ WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ Objects.requireNonNull(getSupportActionBar()).hide();
+ binding.bottomVideo.setVisibility(View.GONE);
+ Objects.requireNonNull(getSupportActionBar()).hide();
+ if (videoOrientationType == videoOrientation.LANDSCAPE) {
+ if (getResources().getConfiguration().orientation != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
+ setRequestedOrientationCustom(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
}
+ } else {
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
+ Objects.requireNonNull(getSupportActionBar()).show();
+ binding.bottomVideo.setVisibility(View.VISIBLE);
+ Objects.requireNonNull(getSupportActionBar()).show();
}
- builderSingle.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
- builderSingle.setAdapter(arrayAdapter, (dialog, which) -> {
- String res = Objects.requireNonNull(arrayAdapter.getItem(which)).substring(0, Objects.requireNonNull(arrayAdapter.getItem(which)).length() - 1);
-
- binding.loader.setVisibility(View.VISIBLE);
- long position = player.getCurrentPosition();
- PlayerControlView controlView = binding.doubleTapPlayerView.findViewById(R.id.exo_controller);
- TextView resolution = controlView.findViewById(R.id.resolution);
- resolution.setText(String.format("%sp", res));
- if (mode == Helper.VIDEO_MODE_NORMAL) {
- if (player != null)
- player.release();
- player = new SimpleExoPlayer.Builder(PeertubeActivity.this).build();
- binding.mediaVideo.player(player);
- binding.doubleTapPlayerView.setPlayer(player);
- binding.loader.setVisibility(View.GONE);
- startStream(
- peertube.getFileUrl(res, PeertubeActivity.this),
- peertube.getStreamingPlaylists().size() > 0 ? peertube.getStreamingPlaylists().get(0).getPlaylistUrl() : null,
- true, position, null, null);
- }
-
- });
- builderSingle.show();
- }
-
- private void initFullscreenDialog() {
-
- fullScreenDialog = new Dialog(this, android.R.style.Theme_Black_NoTitleBar_Fullscreen) {
- public void onBackPressed() {
- if (player != null && player.isPlaying() && fullScreenMode) {
- player.setPlayWhenReady(false);
- }
- if (fullScreenMode) {
- closeFullscreenDialog();
- if (!Helper.isTablet(PeertubeActivity.this) && initialOrientation != Configuration.ORIENTATION_LANDSCAPE) {
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- Handler handler = new Handler();
- handler.postDelayed(() -> setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR), 2000);
- } else {
- binding.peertubeInformationContainer.setVisibility(View.VISIBLE);
- }
- }
- super.onBackPressed();
- }
- };
}
private void openFullscreenDialog() {
-
- ((ViewGroup) binding.doubleTapPlayerView.getParent()).removeView(binding.doubleTapPlayerView);
- fullScreenDialog.addContentView(binding.doubleTapPlayerView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
fullScreenIcon.setImageDrawable(ContextCompat.getDrawable(PeertubeActivity.this, R.drawable.ic_baseline_fullscreen_exit_24));
fullScreenMode = true;
+ toogleFullscreen(true);
+ }
- fullScreenDialog.show();
+ private void closeFullscreenDialog() {
+ fullScreenMode = false;
+ fullScreenIcon.setImageDrawable(ContextCompat.getDrawable(PeertubeActivity.this, R.drawable.ic_baseline_fullscreen_24));
+ toogleFullscreen(false);
}
public void openCommentThread(Comment comment) {
CommentVM commentViewModel = new ViewModelProvider(PeertubeActivity.this).get(CommentVM.class);
binding.peertubeReply.setVisibility(View.GONE);
- commentViewModel.getRepliesComment(videoUuid, comment.getId()).observe(PeertubeActivity.this, apiResponse -> manageVIewCommentReply(comment, apiResponse));
+ commentViewModel.getRepliesComment(sepiaSearch ? peertubeInstance : null, videoUuid, comment.getId()).observe(PeertubeActivity.this, apiResponse -> manageVIewCommentReply(comment, apiResponse));
binding.replyThread.setVisibility(View.VISIBLE);
TranslateAnimation animate = new TranslateAnimation(
@@ -1313,6 +1595,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
public void onAnimationEnd(Animation animation) {
binding.peertubeInformationContainer.setVisibility(View.GONE);
}
+
@Override
public void onAnimationRepeat(Animation animation) {
}
@@ -1321,6 +1604,273 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
binding.replyThread.startAnimation(animate);
}
+
+ public void openMainMenuOptions() {
+ binding.videoParams.setVisibility(View.VISIBLE);
+ DisplayMetrics displayMetrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
+ int height = displayMetrics.heightPixels;
+ binding.doubleTapPlayerView.hideController();
+ List menuItemVideos = new ArrayList<>();
+ if (peertube.getAllFile(PeertubeActivity.this) != null && peertube.getAllFile(PeertubeActivity.this).size() > 0) {
+ MenuItemVideo resolutionItem = new MenuItemVideo();
+ resolutionItem.setIcon(R.drawable.ic_baseline_high_quality_24);
+ resolutionItem.setTitle(getString(R.string.pickup_resolution));
+ resolutionItem.setAction(MenuItemVideo.actionType.RESOLUTION);
+ menuItemVideos.add(resolutionItem);
+
+ }
+ MenuItemVideo speedItem = new MenuItemVideo();
+ speedItem.setIcon(R.drawable.ic_baseline_speed_24);
+ speedItem.setTitle(getString(R.string.playback_speed));
+ speedItem.setAction(MenuItemVideo.actionType.SPEED);
+ menuItemVideos.add(speedItem);
+
+ if (captions != null) {
+ MenuItemVideo captionItem = new MenuItemVideo();
+ captionItem.setIcon(R.drawable.ic_baseline_subtitles_24);
+ captionItem.setTitle(getString(R.string.captions));
+ captionItem.setAction(MenuItemVideo.actionType.CAPTION);
+ menuItemVideos.add(captionItem);
+ }
+
+ MenuItemVideo autoNextItem = new MenuItemVideo();
+ autoNextItem.setIcon(R.drawable.ic_baseline_play_arrow_24);
+ autoNextItem.setTitle(getString(R.string.set_autoplay_next_video_settings));
+ autoNextItem.setAction(MenuItemVideo.actionType.AUTONEXT);
+ menuItemVideos.add(autoNextItem);
+
+ MenuAdapter menuAdapter = new MenuAdapter(menuItemVideos);
+ binding.mainOptionsVideo.setAdapter(menuAdapter);
+ menuAdapter.itemClicked = this;
+ binding.mainOptionsVideo.setLayoutManager(new LinearLayoutManager(PeertubeActivity.this));
+
+ TranslateAnimation animate = new TranslateAnimation(
+ 0,
+ 0,
+ height,
+ 0);
+ animate.setDuration(500);
+ binding.videoParams.startAnimation(animate);
+ }
+
+ @Override
+ public void onItemClicked(MenuItemVideo.actionType action) {
+ binding.videoParamsSubmenu.setVisibility(View.VISIBLE);
+ List items = new ArrayList<>();
+ switch (action) {
+ case RESOLUTION:
+ binding.subMenuTitle.setText(R.string.pickup_resolution);
+ int position = 0;
+ for (File file : peertube.getFiles()) {
+ if (file.getResolutions() != null) {
+ if (file.getResolutions().getLabel().compareTo("0p") != 0) {
+ MenuItemView item = new MenuItemView();
+ item.setId(position);
+ item.setLabel(file.getResolutions().getLabel());
+ if (file.getResolutions().getLabel().compareTo(currentResolution) == 0) {
+ item.setSelected(true);
+ }
+ items.add(item);
+ position++;
+ }
+ }
+ }
+ break;
+ case SPEED:
+ binding.subMenuTitle.setText(R.string.playback_speed);
+ items = new ArrayList<>();
+ items.add(new MenuItemView(25, "0.25x", player.getPlaybackParameters().speed == 0.25));
+ items.add(new MenuItemView(50, "0.5x", player.getPlaybackParameters().speed == 0.5));
+ items.add(new MenuItemView(75, "0.75x", player.getPlaybackParameters().speed == 0.75));
+ items.add(new MenuItemView(100, getString(R.string.normal), player.getPlaybackParameters().speed == 1));
+ items.add(new MenuItemView(125, "1.25x", player.getPlaybackParameters().speed == 1.25));
+ items.add(new MenuItemView(150, "1.5x", player.getPlaybackParameters().speed == 1.5));
+ items.add(new MenuItemView(175, "1.75x", player.getPlaybackParameters().speed == 1.75));
+ items.add(new MenuItemView(200, "2x", player.getPlaybackParameters().speed == 2.0));
+ break;
+ case CAPTION:
+ binding.subMenuTitle.setText(R.string.pickup_captions);
+ items = new ArrayList<>();
+ items.add(new MenuItemView(-1, "null", getString(R.string.none), currentCaption.compareTo("null") == 0));
+ int i = 0;
+ for (Caption caption : captions) {
+ items.add(new MenuItemView(i, caption.getLanguage().getId(), caption.getLanguage().getLabel(), currentCaption.compareTo(caption.getLanguage().getId()) == 0));
+ }
+ break;
+ case AUTONEXT:
+ binding.subMenuTitle.setText(R.string.set_autoplay_next_video_settings);
+ SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
+ boolean autoplayNextVideo = sharedpreferences.getBoolean(getString(R.string.set_autoplay_next_video_choice), true);
+ items.add(new MenuItemView(0, getString(R.string.no), !autoplayNextVideo));
+ items.add(new MenuItemView(1, getString(R.string.yes), autoplayNextVideo));
+ break;
+ }
+ MenuItemAdapter menuItemAdapter = new MenuItemAdapter(action, items);
+ binding.subMenuRecycler.setAdapter(menuItemAdapter);
+ menuItemAdapter.itemAction = this;
+ binding.subMenuRecycler.setLayoutManager(new LinearLayoutManager(PeertubeActivity.this));
+
+ DisplayMetrics displayMetrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
+ int height = displayMetrics.heightPixels;
+ TranslateAnimation animate = new TranslateAnimation(
+ 0,
+ 0,
+ height,
+ 0);
+ animate.setDuration(500);
+ binding.videoParamsSubmenu.startAnimation(animate);
+ }
+
+ @Override
+ public void which(MenuItemVideo.actionType action, MenuItemView item) {
+ closeMainMenuOptions();
+ switch (action) {
+ case RESOLUTION:
+ String res = item.getLabel();
+ binding.loader.setVisibility(View.VISIBLE);
+ long position = player.getCurrentPosition();
+ PlayerControlView controlView = binding.doubleTapPlayerView.findViewById(R.id.exo_controller);
+ TextView resolution = controlView.findViewById(R.id.resolution);
+ currentResolution = res;
+ resolution.setText(String.format("%s", res));
+ if (mode == Helper.VIDEO_MODE_NORMAL) {
+ if (player != null)
+ player.release();
+ player = new SimpleExoPlayer.Builder(PeertubeActivity.this).build();
+ binding.mediaVideo.player(player);
+ binding.doubleTapPlayerView.setPlayer(player);
+ binding.loader.setVisibility(View.GONE);
+ startStream(
+ peertube.getFileUrl(res, PeertubeActivity.this),
+ peertube.getStreamingPlaylists().size() > 0 ? peertube.getStreamingPlaylists().get(0).getPlaylistUrl() : null,
+ true, position, null, null, false);
+ }
+ break;
+ case SPEED:
+ int speed = item.getId();
+ float ratio = (float) speed / 100;
+ PlaybackParameters param = new PlaybackParameters(ratio);
+ if (player != null) {
+ player.setPlaybackParameters(param);
+ }
+ break;
+ case CAPTION:
+ Uri uri = null;
+ Caption captionToUse = null;
+ for (Caption caption : captions) {
+ if (caption.getLanguage().getId().compareTo(item.getStrId()) == 0) {
+ captionToUse = caption;
+ break;
+ }
+ }
+ if (captionToUse != null) {
+ if (!sepiaSearch) {
+ uri = Uri.parse("https://" + HelperInstance.getLiveInstance(PeertubeActivity.this) + captionToUse.getCaptionPath());
+ } else {
+ uri = Uri.parse("https://" + peertubeInstance + captionToUse.getCaptionPath());
+ }
+ }
+ currentCaption = item.getStrId();
+ long newPosition = player.getCurrentPosition();
+
+ if (player != null)
+ player.release();
+
+ TrackSelector trackSelector = new DefaultTrackSelector(PeertubeActivity.this, new AdaptiveTrackSelection.Factory());
+ player = new SimpleExoPlayer.Builder(PeertubeActivity.this).setTrackSelector(trackSelector).build();
+ binding.mediaVideo.player(player);
+ binding.doubleTapPlayerView.setPlayer(player);
+ startStream(
+ peertube.getFileUrl(null, PeertubeActivity.this),
+ null,
+ true,
+ newPosition,
+ uri,
+ item.getStrId(),
+ false
+ );
+ break;
+ case AUTONEXT:
+ SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sharedpreferences.edit();
+ editor.putBoolean(getString(R.string.set_autoplay_next_video_choice), item.getId() == 1);
+ editor.apply();
+ if (Helper.isLoggedIn(PeertubeActivity.this)) {
+ new Thread(() -> {
+ UserSettings userSettings = new UserSettings();
+ userSettings.setAutoPlayNextVideo(item.getId() == 1);
+ try {
+ RetrofitPeertubeAPI api = new RetrofitPeertubeAPI(PeertubeActivity.this);
+ api.updateUser(userSettings);
+ } catch (Exception | Error e) {
+ e.printStackTrace();
+ }
+ }).start();
+ }
+ break;
+ }
+ closeSubMenuMenuOptions();
+ }
+
+ public void closeMainMenuOptions() {
+ DisplayMetrics displayMetrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
+ int height = displayMetrics.heightPixels;
+ TranslateAnimation animate = new TranslateAnimation(
+ 0,
+ 0,
+ 0,
+ height);
+ animate.setAnimationListener(new Animation.AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ binding.videoParams.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+ }
+ });
+ animate.setDuration(500);
+ binding.videoParams.startAnimation(animate);
+ }
+
+
+
+ public void closeSubMenuMenuOptions() {
+ DisplayMetrics displayMetrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
+ int height = displayMetrics.heightPixels;
+ TranslateAnimation animate = new TranslateAnimation(
+ 0,
+ 0,
+ 0,
+ height);
+ animate.setAnimationListener(new Animation.AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ binding.videoParamsSubmenu.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+ }
+ });
+ animate.setDuration(500);
+ binding.videoParamsSubmenu.startAnimation(animate);
+ }
+
+
private void sendComment(Comment comment, int position) {
if (isLoggedIn(PeertubeActivity.this) && !sepiaSearch) {
if (comment == null) {
@@ -1480,16 +2030,8 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
}
}
- private void closeFullscreenDialog() {
- ((ViewGroup) binding.doubleTapPlayerView.getParent()).removeView(binding.doubleTapPlayerView);
- ((FrameLayout) findViewById(R.id.main_media_frame)).addView(binding.doubleTapPlayerView);
- fullScreenMode = false;
- fullScreenDialog.dismiss();
- fullScreenIcon.setImageDrawable(ContextCompat.getDrawable(PeertubeActivity.this, R.drawable.ic_baseline_fullscreen_24));
- }
-
- private void initFullscreenButton() {
+ private void initControllerButtons() {
PlayerControlView controlView = binding.doubleTapPlayerView.findViewById(R.id.exo_controller);
fullScreenIcon = controlView.findViewById(R.id.exo_fullscreen_icon);
@@ -1497,41 +2039,48 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
fullScreenButton.setOnClickListener(v -> {
if (!fullScreenMode) {
openFullscreenDialog();
- if (videoOrientationType == videoOrientation.LANDSCAPE) {
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
- } else {
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- }
} else {
closeFullscreenDialog();
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- Handler handler = new Handler();
- handler.postDelayed(() -> setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR), 2000);
-
+ setRequestedOrientationCustom(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
});
+
ImageButton playButton = controlView.findViewById(R.id.exo_play);
playButton.setOnClickListener(v -> {
if (autoFullscreen && !fullScreenMode) {
openFullscreenDialog();
- if (videoOrientationType == videoOrientation.LANDSCAPE) {
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
- } else {
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- }
}
player.setPlayWhenReady(true);
});
View exo_next = controlView.findViewById(R.id.exo_next);
exo_next.setOnClickListener(v -> playNextVideo());
+
+ View exoSettings = controlView.findViewById(R.id.exo_settings);
+ exoSettings.setOnClickListener(v -> {
+ if (binding.videoParams.getVisibility() == View.VISIBLE) {
+ closeMainMenuOptions();
+ } else {
+ openMainMenuOptions();
+ }
+ });
+ }
+
+ private void setRequestedOrientationCustom(int orientationCustom) {
+ setRequestedOrientation(orientationCustom);
+ Handler handler = new Handler();
+ handler.postDelayed(() -> setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR), 2000);
}
private void initResolution() {
PlayerControlView controlView = binding.doubleTapPlayerView.findViewById(R.id.exo_controller);
TextView resolution = controlView.findViewById(R.id.resolution);
- if (peertube.getFiles() != null && peertube.getFiles().size() > 0) {
- resolution.setText(String.format("%s", Helper.defaultFile(PeertubeActivity.this, peertube.getFiles()).getResolutions().getLabel()));
- resolution.setOnClickListener(v -> displayResolution());
+ if (Helper.defaultFile(PeertubeActivity.this, peertube.getFiles()) != null) {
+ currentResolution = Helper.defaultFile(PeertubeActivity.this, peertube.getFiles()).getResolutions().getLabel();
+ if (peertube.getFiles() != null && peertube.getFiles().size() > 0) {
+ resolution.setText(String.format("%s", currentResolution));
+ } else {
+ resolution.setVisibility(View.GONE);
+ }
} else {
resolution.setVisibility(View.GONE);
}
@@ -1646,6 +2195,31 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
}
}
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent event) {
+
+ if (MotionEvent.ACTION_UP == event.getAction()) {
+ Rect viewRectParams = new Rect();
+ binding.videoParams.getGlobalVisibleRect(viewRectParams);
+ if (binding.videoParams.getVisibility() == View.VISIBLE && !viewRectParams.contains((int) event.getRawX(), (int) event.getRawY())) {
+ closeMainMenuOptions();
+ if (binding.videoParamsSubmenu.getVisibility() == View.VISIBLE) {
+ closeSubMenuMenuOptions();
+ }
+ }
+ Rect viewRectParamsSub = new Rect();
+ binding.videoParamsSubmenu.getGlobalVisibleRect(viewRectParamsSub);
+ if (binding.videoParamsSubmenu.getVisibility() == View.VISIBLE && !viewRectParamsSub.contains((int) event.getRawX(), (int) event.getRawY())) {
+ closeSubMenuMenuOptions();
+ if (binding.videoParams.getVisibility() == View.VISIBLE) {
+ closeMainMenuOptions();
+ }
+ }
+ }
+ return super.dispatchTouchEvent(event);
+ }
+
private void updateHistory(long position) {
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
boolean storeInHistory = sharedpreferences.getBoolean(getString(R.string.set_store_in_history), true);
@@ -1684,9 +2258,11 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
public void onMediaItemTransition(MediaItem mediaItem, int reason) {
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
boolean autoplayNextVideo = sharedpreferences.getBoolean(getString(R.string.set_autoplay_next_video_choice), true);
- if (reason == MEDIA_ITEM_TRANSITION_REASON_AUTO && autoplayNextVideo) {
+ if (reason == MEDIA_ITEM_TRANSITION_REASON_AUTO) {
player.removeMediaItems(0, player.getMediaItemCount());
- playNextVideo();
+ if (!sepiaSearch && autoplayNextVideo) {
+ playNextVideo();
+ }
}
}
@@ -1696,6 +2272,8 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
}
+
+
enum videoOrientation {
LANDSCAPE,
PORTRAIT
diff --git a/app/src/main/java/app/fedilab/fedilabtube/PeertubeEditUploadActivity.java b/app/src/main/java/app/fedilab/fedilabtube/PeertubeEditUploadActivity.java
index ce8b7bc..b044650 100644
--- a/app/src/main/java/app/fedilab/fedilabtube/PeertubeEditUploadActivity.java
+++ b/app/src/main/java/app/fedilab/fedilabtube/PeertubeEditUploadActivity.java
@@ -16,21 +16,17 @@ package app.fedilab.fedilabtube;
import android.Manifest;
import android.app.Activity;
-import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.EditText;
-import android.widget.ImageView;
-import android.widget.Spinner;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
@@ -40,39 +36,34 @@ import androidx.core.content.ContextCompat;
import androidx.lifecycle.ViewModelProvider;
import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.resource.bitmap.CenterCrop;
+import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
+import com.bumptech.glide.request.RequestOptions;
-import net.gotev.uploadservice.MultipartUploadRequest;
-import net.gotev.uploadservice.ServerResponse;
-import net.gotev.uploadservice.UploadInfo;
-import net.gotev.uploadservice.UploadNotificationConfig;
-import net.gotev.uploadservice.UploadStatusDelegate;
-
-import java.io.FileNotFoundException;
-import java.net.MalformedURLException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import java.util.UUID;
import app.fedilab.fedilabtube.client.APIResponse;
import app.fedilab.fedilabtube.client.RetrofitPeertubeAPI;
import app.fedilab.fedilabtube.client.data.ChannelData.Channel;
+import app.fedilab.fedilabtube.client.data.VideoData;
import app.fedilab.fedilabtube.client.data.VideoData.Video;
import app.fedilab.fedilabtube.client.entities.Item;
import app.fedilab.fedilabtube.client.entities.ItemStr;
import app.fedilab.fedilabtube.client.entities.VideoParams;
+import app.fedilab.fedilabtube.databinding.ActivityPeertubeEditBinding;
import app.fedilab.fedilabtube.helper.Helper;
import app.fedilab.fedilabtube.viewmodel.ChannelsVM;
import app.fedilab.fedilabtube.viewmodel.MyVideoVM;
import app.fedilab.fedilabtube.viewmodel.PostActionsVM;
import app.fedilab.fedilabtube.viewmodel.TimelineVM;
import es.dmoral.toasty.Toasty;
-import mabbas007.tagsedittext.TagsEditText;
-import static app.fedilab.fedilabtube.MainActivity.peertubeInformation;
import static app.fedilab.fedilabtube.client.RetrofitPeertubeAPI.ActionType.PEERTUBEDELETEVIDEO;
import static app.fedilab.fedilabtube.client.RetrofitPeertubeAPI.DataType.MY_CHANNELS;
+import static app.fedilab.fedilabtube.helper.Helper.peertubeInformation;
public class PeertubeEditUploadActivity extends AppCompatActivity {
@@ -82,23 +73,21 @@ public class PeertubeEditUploadActivity extends AppCompatActivity {
private final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 724;
Item licenseToSend, privacyToSend, categoryToSend;
ItemStr languageToSend;
- private Button set_upload_submit;
- private Spinner set_upload_privacy, set_upload_categories, set_upload_licenses, set_upload_languages, set_upload_channel;
- private EditText p_video_title, p_video_description;
- private TagsEditText p_video_tags;
- private CheckBox set_upload_nsfw, set_upload_enable_comments;
private LinkedHashMap channels;
private String videoId;
private Channel channel;
- private ImageView p_video_preview;
- private Button set_preview;
private VideoParams videoParams;
private Video video;
private String channelToSendId;
+ private ActivityPeertubeEditBinding binding;
+ private Uri inputData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ binding = ActivityPeertubeEditBinding.inflate(getLayoutInflater());
+ View view = binding.getRoot();
+ setContentView(view);
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
@@ -113,23 +102,8 @@ public class PeertubeEditUploadActivity extends AppCompatActivity {
}
if (getSupportActionBar() != null)
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- setContentView(R.layout.activity_peertube_edit);
- set_upload_submit = findViewById(R.id.set_upload_submit);
- Button set_upload_delete = findViewById(R.id.set_upload_delete);
- set_upload_privacy = findViewById(R.id.set_upload_privacy);
- set_upload_channel = findViewById(R.id.set_upload_channel);
- set_upload_categories = findViewById(R.id.set_upload_categories);
- set_upload_licenses = findViewById(R.id.set_upload_licenses);
- set_upload_languages = findViewById(R.id.set_upload_languages);
- p_video_title = findViewById(R.id.p_video_title);
- p_video_description = findViewById(R.id.p_video_description);
- p_video_tags = findViewById(R.id.p_video_tags);
- p_video_preview = findViewById(R.id.p_video_preview);
- set_upload_nsfw = findViewById(R.id.set_upload_nsfw);
- set_upload_enable_comments = findViewById(R.id.set_upload_enable_comments);
- set_preview = findViewById(R.id.set_preview);
- set_upload_delete.setOnClickListener(v -> {
+ binding.setUploadDelete.setOnClickListener(v -> {
AlertDialog.Builder builderInner;
builderInner = new AlertDialog.Builder(PeertubeEditUploadActivity.this);
builderInner.setMessage(getString(R.string.delete_video_confirmation));
@@ -165,7 +139,7 @@ public class PeertubeEditUploadActivity extends AppCompatActivity {
}
ArrayAdapter adapterCatgories = new ArrayAdapter<>(PeertubeEditUploadActivity.this,
android.R.layout.simple_spinner_dropdown_item, categoriesA);
- set_upload_categories.setAdapter(adapterCatgories);
+ binding.setUploadCategories.setAdapter(adapterCatgories);
//Populate licenses
@@ -183,7 +157,7 @@ public class PeertubeEditUploadActivity extends AppCompatActivity {
}
ArrayAdapter adapterLicenses = new ArrayAdapter<>(PeertubeEditUploadActivity.this,
android.R.layout.simple_spinner_dropdown_item, licensesA);
- set_upload_licenses.setAdapter(adapterLicenses);
+ binding.setUploadLicenses.setAdapter(adapterLicenses);
//Populate languages
@@ -201,7 +175,7 @@ public class PeertubeEditUploadActivity extends AppCompatActivity {
}
ArrayAdapter adapterLanguages = new ArrayAdapter<>(PeertubeEditUploadActivity.this,
android.R.layout.simple_spinner_dropdown_item, languagesA);
- set_upload_languages.setAdapter(adapterLanguages);
+ binding.setUploadLanguages.setAdapter(adapterLanguages);
//Populate languages
@@ -220,18 +194,19 @@ public class PeertubeEditUploadActivity extends AppCompatActivity {
ArrayAdapter adapterPrivacies = new ArrayAdapter<>(PeertubeEditUploadActivity.this,
android.R.layout.simple_spinner_dropdown_item, privaciesA);
- set_upload_privacy.setAdapter(adapterPrivacies);
+ binding.setUploadPrivacy.setAdapter(adapterPrivacies);
TimelineVM feedsViewModel = new ViewModelProvider(PeertubeEditUploadActivity.this).get(TimelineVM.class);
feedsViewModel.getMyVideo(null, videoId).observe(PeertubeEditUploadActivity.this, this::manageVIewVideo);
+
channels = new LinkedHashMap<>();
setTitle(R.string.edit_video);
}
public void manageUpdate(APIResponse apiResponse) {
- set_upload_submit.setEnabled(true);
+ binding.setUploadSubmit.setEnabled(true);
if (apiResponse.getError() != null) {
if (apiResponse.getError() != null && apiResponse.getError().getError() != null)
Toasty.error(PeertubeEditUploadActivity.this, apiResponse.getError().getError(), Toast.LENGTH_LONG).show();
@@ -247,7 +222,7 @@ public class PeertubeEditUploadActivity extends AppCompatActivity {
Toasty.error(PeertubeEditUploadActivity.this, apiResponse.getError().getError(), Toast.LENGTH_LONG).show();
else
Toasty.error(PeertubeEditUploadActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
- set_upload_submit.setEnabled(true);
+ binding.setUploadSubmit.setEnabled(true);
return;
}
@@ -263,11 +238,11 @@ public class PeertubeEditUploadActivity extends AppCompatActivity {
categoryToSend = video.getCategory();
if (video.getThumbnailPath() != null) {
- Helper.loadGiF(PeertubeEditUploadActivity.this, video.getThumbnailPath(), p_video_preview);
+ Helper.loadGiF(PeertubeEditUploadActivity.this, video.getThumbnailPath(), binding.pVideoPreview);
}
- set_preview.setOnClickListener(v -> {
+ binding.setPreview.setOnClickListener(v -> {
if (ContextCompat.checkSelfPermission(PeertubeEditUploadActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) !=
PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(PeertubeEditUploadActivity.this,
@@ -324,11 +299,28 @@ public class PeertubeEditUploadActivity extends AppCompatActivity {
boolean commentEnabled = video.isCommentsEnabled();
boolean isNSFW = video.isNsfw();
- set_upload_enable_comments.setChecked(commentEnabled);
- set_upload_nsfw.setChecked(isNSFW);
+ binding.setUploadEnableComments.setChecked(commentEnabled);
+ binding.setUploadNsfw.setChecked(isNSFW);
- p_video_title.setText(title);
- p_video_description.setText(video.getDescription());
+ binding.pVideoTitle.setText(title);
+ binding.pVideoDescription.setText(video.getDescription());
+
+ new Thread(() -> {
+ try {
+ RetrofitPeertubeAPI api;
+ api = new RetrofitPeertubeAPI(PeertubeEditUploadActivity.this);
+ VideoData.Description description = api.getVideoDescription(video.getUuid());
+ Handler mainHandler = new Handler(Looper.getMainLooper());
+ Runnable myRunnable = () -> {
+ if (description != null) {
+ binding.pVideoDescription.setText(description.getDescription());
+ }
+ };
+ mainHandler.post(myRunnable);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }).start();
LinkedHashMap categories = new LinkedHashMap<>(peertubeInformation.getCategories());
LinkedHashMap licences = new LinkedHashMap<>(peertubeInformation.getLicences());
@@ -382,7 +374,7 @@ public class PeertubeEditUploadActivity extends AppCompatActivity {
}
}
//Manage privacies
- set_upload_privacy.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ binding.setUploadPrivacy.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view, int position, long id) {
updatePrivacyPosition(position);
@@ -393,7 +385,7 @@ public class PeertubeEditUploadActivity extends AppCompatActivity {
}
});
- set_upload_licenses.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ binding.setUploadLicenses.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view, int position, long id) {
updateLicensePosition(position);
@@ -405,7 +397,7 @@ public class PeertubeEditUploadActivity extends AppCompatActivity {
}
});
//Manage categories
- set_upload_categories.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ binding.setUploadCategories.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view, int position, long id) {
updateCategoryPosition(position);
@@ -418,7 +410,7 @@ public class PeertubeEditUploadActivity extends AppCompatActivity {
});
//Manage languages
- set_upload_languages.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ binding.setUploadLanguages.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view, int position, long id) {
updateLanguagesPosition(position);
@@ -430,7 +422,7 @@ public class PeertubeEditUploadActivity extends AppCompatActivity {
}
});
//Manage languages
- set_upload_channel.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ binding.setUploadChannel.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view, int position, long id) {
@@ -447,11 +439,11 @@ public class PeertubeEditUploadActivity extends AppCompatActivity {
Item finalLicenseToSend = licenseToSend;
ItemStr finalLanguageToSend = languageToSend;
Item finalPrivacyToSend = privacyToSend;
- set_upload_submit.setOnClickListener(v -> {
- String title1 = p_video_title.getText().toString().trim();
- String description = p_video_description.getText().toString().trim();
- boolean isNSFW1 = set_upload_nsfw.isChecked();
- boolean commentEnabled1 = set_upload_enable_comments.isChecked();
+ binding.setUploadSubmit.setOnClickListener(v -> {
+ String title1 = binding.pVideoTitle.getText() != null ? binding.pVideoTitle.getText().toString().trim() : "";
+ String description = binding.pVideoDescription.getText() != null ? binding.pVideoDescription.getText().toString().trim() : "";
+ boolean isNSFW1 = binding.setUploadNsfw.isChecked();
+ boolean commentEnabled1 = binding.setUploadEnableComments.isChecked();
videoParams = new VideoParams();
videoParams.setName(title1);
videoParams.setDescription(description);
@@ -460,28 +452,27 @@ public class PeertubeEditUploadActivity extends AppCompatActivity {
videoParams.setCategory(finalCategoryToSend.getId());
videoParams.setLicence(String.valueOf(finalLicenseToSend.getId()));
videoParams.setLanguage(finalLanguageToSend.getId());
-
videoParams.setChannelId(channelToSendId);
videoParams.setPrivacy(finalPrivacyToSend.getId());
- List tags = p_video_tags.getTags();
+ List tags = binding.pVideoTags.getTags();
videoParams.setTags(tags);
- set_upload_submit.setEnabled(false);
+ binding.setUploadSubmit.setEnabled(false);
MyVideoVM myVideoVM = new ViewModelProvider(PeertubeEditUploadActivity.this).get(MyVideoVM.class);
- myVideoVM.updateVideo(videoId, videoParams, null, null).observe(PeertubeEditUploadActivity.this, this::manageUpdate);
+ myVideoVM.updateVideo(videoId, videoParams, inputData, inputData).observe(PeertubeEditUploadActivity.this, this::manageUpdate);
});
- set_upload_privacy.setSelection(privacyPosition, false);
+ binding.setUploadPrivacy.setSelection(privacyPosition, false);
updatePrivacyPosition(privacyPosition);
- set_upload_languages.setSelection(languagePosition, false);
+ binding.setUploadLanguages.setSelection(languagePosition, false);
updateLanguagesPosition(languagePosition);
- set_upload_licenses.setSelection(licensePosition, false);
+ binding.setUploadLicenses.setSelection(licensePosition, false);
updateLicensePosition(licensePosition);
- set_upload_categories.setSelection(categoryPosition, false);
+ binding.setUploadCategories.setSelection(categoryPosition, false);
updateCategoryPosition(categoryPosition);
List tags = video.getTags();
if (tags != null && tags.size() > 0) {
- p_video_tags.setTags(tags.toArray(new String[0]));
+ binding.pVideoTags.setTags(tags.toArray(new String[0]));
}
}
@@ -572,53 +563,12 @@ public class PeertubeEditUploadActivity extends AppCompatActivity {
Toasty.error(PeertubeEditUploadActivity.this, getString(R.string.toot_select_image_error), Toast.LENGTH_LONG).show();
return;
}
- UploadNotificationConfig uploadConfig = new UploadNotificationConfig();
- uploadConfig.getCompleted().autoClear = true;
- try {
- SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
- String token = sharedpreferences.getString(Helper.PREF_KEY_OAUTH_TOKEN, null);
- Uri uri = data.getData();
- try {
- String uploadId = UUID.randomUUID().toString();
- new MultipartUploadRequest(PeertubeEditUploadActivity.this, uploadId, "https://" + Helper.getLiveInstance(PeertubeEditUploadActivity.this) + "/api/v1/" + String.format("/videos/%s", video.getId()))
- .addFileToUpload(uri.toString().replace("file://", ""), "thumbnailfile")
- .setMethod("PUT")
- .addHeader("Authorization", "Bearer " + token)
- .setNotificationConfig(uploadConfig)
- .setMaxRetries(2)
- .setDelegate(new UploadStatusDelegate() {
- @Override
- public void onProgress(Context context, UploadInfo uploadInfo) {
- // your code here
- }
-
- @Override
- public void onError(Context context, UploadInfo uploadInfo, ServerResponse serverResponse,
- Exception exception) {
- Toasty.error(PeertubeEditUploadActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
- }
-
- @Override
- public void onCompleted(Context context, UploadInfo uploadInfo, ServerResponse serverResponse) {
- Glide.with(PeertubeEditUploadActivity.this)
- .load(uri)
- .into(p_video_preview);
- }
-
- @Override
- public void onCancelled(Context context, UploadInfo uploadInfo) {
- // your code here
- }
- })
- .startUpload();
- } catch (FileNotFoundException e) {
- Toasty.error(PeertubeEditUploadActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
- e.printStackTrace();
- }
- } catch (MalformedURLException e) {
- Toasty.error(PeertubeEditUploadActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
- e.printStackTrace();
- }
+ inputData = data.getData();
+ Glide.with(PeertubeEditUploadActivity.this)
+ .load(data.getData())
+ .thumbnail(0.1f)
+ .apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners(10)))
+ .into(binding.pVideoPreview);
}
}
@@ -651,7 +601,7 @@ public class PeertubeEditUploadActivity extends AppCompatActivity {
}
ArrayAdapter adapterChannel = new ArrayAdapter<>(PeertubeEditUploadActivity.this,
android.R.layout.simple_spinner_dropdown_item, channelName);
- set_upload_channel.setAdapter(adapterChannel);
+ binding.setUploadChannel.setAdapter(adapterChannel);
int channelPosition = 0;
if (channels.containsKey(channel.getName())) {
LinkedHashMap channelsIterator = new LinkedHashMap<>(channels);
@@ -666,9 +616,15 @@ public class PeertubeEditUploadActivity extends AppCompatActivity {
channelPosition++;
}
}
- set_upload_channel.setSelection(channelPosition, false);
+ binding.setUploadChannel.setSelection(channelPosition, false);
updateUploadChannel(channelPosition);
- set_upload_submit.setEnabled(true);
+ binding.setUploadSubmit.setEnabled(true);
+ }
+
+ @Override
+ public void onBackPressed() {
+ super.onBackPressed();
+ finish();
}
@SuppressWarnings({"unused", "RedundantSuppression"})
diff --git a/app/src/main/java/app/fedilab/fedilabtube/PeertubeRegisterActivity.java b/app/src/main/java/app/fedilab/fedilabtube/PeertubeRegisterActivity.java
index 9c29462..772397a 100644
--- a/app/src/main/java/app/fedilab/fedilabtube/PeertubeRegisterActivity.java
+++ b/app/src/main/java/app/fedilab/fedilabtube/PeertubeRegisterActivity.java
@@ -38,7 +38,8 @@ import app.fedilab.fedilabtube.client.APIResponse;
import app.fedilab.fedilabtube.client.RetrofitPeertubeAPI;
import app.fedilab.fedilabtube.client.entities.AccountCreation;
import app.fedilab.fedilabtube.databinding.ActivityRegisterPeertubeBinding;
-import app.fedilab.fedilabtube.helper.Helper;
+import app.fedilab.fedilabtube.helper.HelperAcadInstance;
+import app.fedilab.fedilabtube.helper.HelperInstance;
import es.dmoral.toasty.Toasty;
import static app.fedilab.fedilabtube.MainActivity.PICK_INSTANCE;
@@ -49,6 +50,7 @@ public class PeertubeRegisterActivity extends AppCompatActivity {
private String instance;
private ActivityRegisterPeertubeBinding binding;
+ @SuppressLint("SetTextI18n")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -61,7 +63,7 @@ public class PeertubeRegisterActivity extends AppCompatActivity {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- if (BuildConfig.full_instances) {
+ if (BuildConfig.full_instances && BuildConfig.instance_switcher) {
binding.loginInstanceContainer.setVisibility(View.VISIBLE);
binding.titleLoginInstance.setVisibility(View.VISIBLE);
} else {
@@ -69,6 +71,10 @@ public class PeertubeRegisterActivity extends AppCompatActivity {
binding.titleLoginInstance.setVisibility(View.GONE);
}
+ if (BuildConfig.FLAVOR.compareTo("queermotion") == 0) {
+ binding.loginInstance.setText("queermotion.org");
+ }
+
binding.username.setOnFocusChangeListener((view, focused) -> {
if (!focused && binding.username.getText() != null) {
Pattern patternUsername = Pattern.compile("^[a-z0-9._]{1,50}$");
@@ -129,7 +135,7 @@ public class PeertubeRegisterActivity extends AppCompatActivity {
}
String[] emailArray = binding.email.getText().toString().split("@");
if (!BuildConfig.full_instances) {
- if (emailArray.length > 1 && !Arrays.asList(Helper.valideEmails).contains(emailArray[1])) {
+ if (emailArray.length > 1 && !Arrays.asList(HelperAcadInstance.valideEmails).contains(emailArray[1])) {
Toasty.error(PeertubeRegisterActivity.this, getString(R.string.email_error_domain, emailArray[1])).show();
return;
}
@@ -158,7 +164,7 @@ public class PeertubeRegisterActivity extends AppCompatActivity {
});
} else {
String host = emailArray[1];
- instance = Helper.getPeertubeUrl(host);
+ instance = HelperInstance.getPeertubeUrl(host);
}
if (instance != null) {
instance = instance.toLowerCase().trim();
diff --git a/app/src/main/java/app/fedilab/fedilabtube/PeertubeUploadActivity.java b/app/src/main/java/app/fedilab/fedilabtube/PeertubeUploadActivity.java
index 3bb3f3b..ae2534f 100644
--- a/app/src/main/java/app/fedilab/fedilabtube/PeertubeUploadActivity.java
+++ b/app/src/main/java/app/fedilab/fedilabtube/PeertubeUploadActivity.java
@@ -21,46 +21,51 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
-import android.database.Cursor;
+import android.graphics.Color;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
-import android.provider.OpenableColumns;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.Spinner;
-import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
+import androidx.documentfile.provider.DocumentFile;
import androidx.lifecycle.ViewModelProvider;
-import net.gotev.uploadservice.MultipartUploadRequest;
-import net.gotev.uploadservice.UploadNotificationAction;
-import net.gotev.uploadservice.UploadNotificationConfig;
-import java.io.File;
+import net.gotev.uploadservice.data.UploadNotificationAction;
+import net.gotev.uploadservice.data.UploadNotificationConfig;
+import net.gotev.uploadservice.data.UploadNotificationStatusConfig;
+import net.gotev.uploadservice.extensions.ContextExtensionsKt;
+import net.gotev.uploadservice.protocols.multipart.MultipartUploadRequest;
+
+import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
-import java.util.UUID;
import app.fedilab.fedilabtube.client.APIResponse;
+import app.fedilab.fedilabtube.client.RetrofitPeertubeAPI;
import app.fedilab.fedilabtube.client.data.ChannelData;
+import app.fedilab.fedilabtube.client.entities.UserMe;
+import app.fedilab.fedilabtube.databinding.ActivityPeertubeUploadBinding;
import app.fedilab.fedilabtube.helper.Helper;
+import app.fedilab.fedilabtube.helper.HelperInstance;
import app.fedilab.fedilabtube.viewmodel.ChannelsVM;
import es.dmoral.toasty.Toasty;
-import static app.fedilab.fedilabtube.MainActivity.peertubeInformation;
+import static app.fedilab.fedilabtube.MainActivity.userMe;
import static app.fedilab.fedilabtube.client.RetrofitPeertubeAPI.DataType.MY_CHANNELS;
+import static app.fedilab.fedilabtube.helper.Helper.peertubeInformation;
public class PeertubeUploadActivity extends AppCompatActivity {
@@ -68,16 +73,12 @@ public class PeertubeUploadActivity extends AppCompatActivity {
public static final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 724;
private final int PICK_IVDEO = 52378;
- private Button set_upload_file, set_upload_submit;
- private Spinner set_upload_privacy, set_upload_channel;
- private TextView set_upload_file_name;
- private EditText video_title;
private HashMap channels;
private Uri uri;
private String filename;
private HashMap privacyToSend;
private HashMap channelToSend;
-
+ private ActivityPeertubeUploadBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -86,14 +87,60 @@ public class PeertubeUploadActivity extends AppCompatActivity {
if (getSupportActionBar() != null)
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- setContentView(R.layout.activity_peertube_upload);
+ binding = ActivityPeertubeUploadBinding.inflate(getLayoutInflater());
+ View view = binding.getRoot();
+ setContentView(view);
+
+
+ new Thread(() -> {
+ UserMe.VideoQuota videoQuotaReply = new RetrofitPeertubeAPI(PeertubeUploadActivity.this).getVideoQuota();
+ runOnUiThread(() -> {
+ if (videoQuotaReply != null) {
+ long videoQuota = videoQuotaReply.getVideoQuotaUsed();
+ long dailyQuota = videoQuotaReply.getVideoQuotaUsedDaily();
+ long instanceVideoQuota = userMe.getVideoQuota();
+ long instanceDailyQuota = userMe.getVideoQuotaDaily();
+
+ if (instanceVideoQuota != -1 && instanceVideoQuota != 0) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ binding.totalQuota.setProgress((int) (videoQuota * 100 / instanceVideoQuota), true);
+ } else {
+ binding.totalQuota.setProgress((int) (videoQuota * 100 / instanceVideoQuota));
+ }
+ } else {
+ int progress = videoQuota > 0 ? 30 : 0;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ binding.totalQuota.setProgress(progress, true);
+ } else {
+ binding.totalQuota.setProgress(progress);
+ }
+ }
+ if (instanceDailyQuota != -1 && instanceDailyQuota != 0) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ binding.dailyQuota.setProgress((int) (dailyQuota * 100 / instanceDailyQuota), true);
+ } else {
+ binding.dailyQuota.setProgress((int) (dailyQuota * 100 / instanceDailyQuota));
+ }
+ } else {
+ int progress = dailyQuota > 0 ? 30 : 0;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ binding.dailyQuota.setProgress(progress, true);
+ } else {
+ binding.dailyQuota.setProgress(progress);
+ }
+ }
+ binding.totalQuotaValue.setText(
+ String.format(Locale.getDefault(), "%s/%s",
+ Helper.returnRoundedSize(PeertubeUploadActivity.this, videoQuota),
+ Helper.returnRoundedSize(PeertubeUploadActivity.this, instanceVideoQuota)));
+ binding.dailyQuotaValue.setText(
+ String.format(Locale.getDefault(), "%s/%s",
+ Helper.returnRoundedSize(PeertubeUploadActivity.this, dailyQuota),
+ Helper.returnRoundedSize(PeertubeUploadActivity.this, instanceDailyQuota)));
+ }
+ });
+ }).start();
- set_upload_file = findViewById(R.id.set_upload_file);
- set_upload_file_name = findViewById(R.id.set_upload_file_name);
- set_upload_channel = findViewById(R.id.set_upload_channel);
- set_upload_privacy = findViewById(R.id.set_upload_privacy);
- set_upload_submit = findViewById(R.id.set_upload_submit);
- video_title = findViewById(R.id.video_title);
ChannelsVM viewModelC = new ViewModelProvider(PeertubeUploadActivity.this).get(ChannelsVM.class);
viewModelC.get(MY_CHANNELS, null).observe(PeertubeUploadActivity.this, this::manageVIewChannels);
@@ -109,33 +156,18 @@ public class PeertubeUploadActivity extends AppCompatActivity {
Toasty.error(PeertubeUploadActivity.this, getString(R.string.toot_select_image_error), Toast.LENGTH_LONG).show();
return;
}
- set_upload_submit.setEnabled(true);
-
+ binding.setUploadSubmit.setEnabled(true);
uri = data.getData();
-
- String uriString = uri.toString();
- File myFile = new File(uriString);
filename = null;
- if (uriString.startsWith("content://")) {
- Cursor cursor = null;
- try {
- cursor = getContentResolver().query(uri, null, null, null, null);
- if (cursor != null && cursor.moveToFirst()) {
- filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
- }
- } finally {
- assert cursor != null;
- cursor.close();
- }
- } else if (uriString.startsWith("file://")) {
- filename = myFile.getName();
+ DocumentFile documentFile = DocumentFile.fromSingleUri(this, uri);
+ if (documentFile != null) {
+ filename = documentFile.getName();
}
if (filename == null) {
filename = new Date().toString();
}
- set_upload_file_name.setVisibility(View.VISIBLE);
- set_upload_file_name.setText(filename);
-
+ binding.setUploadFileName.setVisibility(View.VISIBLE);
+ binding.setUploadFileName.setText(filename);
}
}
@@ -179,7 +211,7 @@ public class PeertubeUploadActivity extends AppCompatActivity {
channelToSend.put(channelName[0], channelId[0]);
ArrayAdapter adapterChannel = new ArrayAdapter<>(PeertubeUploadActivity.this,
android.R.layout.simple_spinner_dropdown_item, channelName);
- set_upload_channel.setAdapter(adapterChannel);
+ binding.setUploadChannel.setAdapter(adapterChannel);
if (peertubeInformation == null) {
return;
@@ -209,10 +241,10 @@ public class PeertubeUploadActivity extends AppCompatActivity {
ArrayAdapter adapterPrivacies = new ArrayAdapter<>(PeertubeUploadActivity.this,
android.R.layout.simple_spinner_dropdown_item, privaciesA);
- set_upload_privacy.setAdapter(adapterPrivacies);
+ binding.setUploadPrivacy.setAdapter(adapterPrivacies);
//Manage privacies
- set_upload_privacy.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ binding.setUploadPrivacy.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view, int position, long id) {
LinkedHashMap privaciesCheck = new LinkedHashMap<>(peertubeInformation.getPrivacies());
@@ -235,9 +267,9 @@ public class PeertubeUploadActivity extends AppCompatActivity {
}
});
- set_upload_file.setEnabled(true);
+ binding.setUploadFile.setEnabled(true);
- set_upload_file.setOnClickListener(v -> {
+ binding.setUploadFile.setOnClickListener(v -> {
if (ContextCompat.checkSelfPermission(PeertubeUploadActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) !=
PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(PeertubeUploadActivity.this,
@@ -245,7 +277,7 @@ public class PeertubeUploadActivity extends AppCompatActivity {
MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
return;
}
- Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+ Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
String[] mimetypes = {"video/*"};
@@ -255,7 +287,7 @@ public class PeertubeUploadActivity extends AppCompatActivity {
});
//Manage languages
- set_upload_channel.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ binding.setUploadChannel.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view, int position, long id) {
LinkedHashMap channelsCheck = new LinkedHashMap<>(channels);
@@ -279,44 +311,33 @@ public class PeertubeUploadActivity extends AppCompatActivity {
}
});
- set_upload_submit.setOnClickListener(v -> {
+ binding.setUploadSubmit.setOnClickListener(v -> {
if (uri != null) {
Map.Entry channelM = channelToSend.entrySet().iterator().next();
String idChannel = channelM.getValue();
Map.Entry privacyM = privacyToSend.entrySet().iterator().next();
Integer idPrivacy = privacyM.getKey();
-
+ if (binding.videoTitle.getText() != null && binding.videoTitle.getText().toString().trim().length() > 0) {
+ filename = binding.videoTitle.getText().toString().trim();
+ }
try {
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
String token = sharedpreferences.getString(Helper.PREF_KEY_OAUTH_TOKEN, null);
- UploadNotificationConfig uploadConfig = new UploadNotificationConfig();
- Intent in = new Intent(PeertubeUploadActivity.this, PeertubeEditUploadActivity.class);
- PendingIntent clickIntent = PendingIntent.getActivity(PeertubeUploadActivity.this, 1, in, PendingIntent.FLAG_UPDATE_CURRENT);
- uploadConfig
- .setClearOnActionForAllStatuses(true);
-
- uploadConfig.getProgress().message = getString(R.string.uploading);
- uploadConfig.getCompleted().message = getString(R.string.upload_video_success);
- uploadConfig.getError().message = getString(R.string.toast_error);
- uploadConfig.getCancelled().message = getString(R.string.toast_cancelled);
- uploadConfig.getCompleted().actions.add(new UploadNotificationAction(R.drawable.ic_baseline_check_24, getString(R.string.video_uploaded_action), clickIntent));
-
- if (video_title != null && video_title.getText() != null && video_title.getText().toString().trim().length() > 0) {
- filename = video_title.getText().toString().trim();
- }
- String uploadId = UUID.randomUUID().toString();
- new MultipartUploadRequest(PeertubeUploadActivity.this, uploadId, "https://" + Helper.getLiveInstance(PeertubeUploadActivity.this) + "/api/v1/videos/upload")
- .addFileToUpload(uri.toString().replace("file://", ""), "videofile")
- .addHeader("Authorization", "Bearer " + token)
- .setNotificationConfig(uploadConfig)
- .addParameter("name", filename)
- .addParameter("channelId", idChannel)
+ new MultipartUploadRequest(PeertubeUploadActivity.this, "https://" + HelperInstance.getLiveInstance(PeertubeUploadActivity.this) + "/api/v1/videos/upload")
+ .setMethod("POST")
+ .setBearerAuth(token)
+ .addHeader("User-Agent", getString(R.string.app_name) + "/" + BuildConfig.VERSION_NAME)
.addParameter("privacy", String.valueOf(idPrivacy))
.addParameter("nsfw", "false")
+ .addParameter("name", filename)
.addParameter("commentsEnabled", "true")
+ .addParameter("downloadEnabled", "true")
.addParameter("waitTranscoding", "true")
- .setMaxRetries(3)
+ .addParameter("channelId", idChannel)
+ .addFileToUpload(uri.toString(), "videofile")
+ .setNotificationConfig((context, uploadId) -> getNotificationConfig(uploadId))
+ .setMaxRetries(2)
.startUpload();
finish();
} catch (Exception exc) {
@@ -325,4 +346,74 @@ public class PeertubeUploadActivity extends AppCompatActivity {
}
});
}
+
+ UploadNotificationConfig getNotificationConfig(String uploadId) {
+ PendingIntent clickIntent = PendingIntent.getActivity(
+ PeertubeUploadActivity.this, 1, new Intent(this, PeertubeEditUploadActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
+
+ final boolean autoClear = false;
+ final boolean clearOnAction = true;
+ final boolean ringToneEnabled = true;
+ final ArrayList noActions = new ArrayList<>(1);
+
+ final UploadNotificationAction cancelAction = new UploadNotificationAction(
+ R.drawable.ic_baseline_cancel_24,
+ getString(R.string.cancel),
+ ContextExtensionsKt.getCancelUploadIntent(this, uploadId)
+ );
+
+
+ final ArrayList progressActions = new ArrayList<>(1);
+ progressActions.add(cancelAction);
+
+ UploadNotificationStatusConfig progress = new UploadNotificationStatusConfig(
+ getString(R.string.app_name),
+ getString(R.string.uploading),
+ R.drawable.ic_baseline_cloud_upload_24,
+ Color.BLUE,
+ null,
+ clickIntent,
+ progressActions,
+ clearOnAction,
+ autoClear
+ );
+
+ UploadNotificationStatusConfig success = new UploadNotificationStatusConfig(
+ getString(R.string.app_name),
+ getString(R.string.upload_video_success),
+ R.drawable.ic_baseline_check_24,
+ Color.GREEN,
+ null,
+ clickIntent,
+ noActions,
+ clearOnAction,
+ autoClear
+ );
+
+
+ UploadNotificationStatusConfig error = new UploadNotificationStatusConfig(
+ getString(R.string.app_name),
+ getString(R.string.toast_error),
+ R.drawable.ic_baseline_error_24,
+ Color.RED,
+ null,
+ clickIntent,
+ noActions,
+ clearOnAction,
+ autoClear
+ );
+
+ UploadNotificationStatusConfig cancelled = new UploadNotificationStatusConfig(
+ getString(R.string.app_name),
+ getString(R.string.toast_cancelled),
+ R.drawable.ic_baseline_cancel_24,
+ Color.YELLOW,
+ null,
+ clickIntent,
+ noActions,
+ clearOnAction
+ );
+
+ return new UploadNotificationConfig(FedilabTube.UPLOAD_CHANNEL_ID, ringToneEnabled, progress, success, error, cancelled);
+ }
}
diff --git a/app/src/main/java/app/fedilab/fedilabtube/SearchActivity.java b/app/src/main/java/app/fedilab/fedilabtube/SearchActivity.java
index 4df50cf..636ca09 100644
--- a/app/src/main/java/app/fedilab/fedilabtube/SearchActivity.java
+++ b/app/src/main/java/app/fedilab/fedilabtube/SearchActivity.java
@@ -16,11 +16,22 @@ package app.fedilab.fedilabtube;
import android.os.Bundle;
import android.view.MenuItem;
+import android.view.View;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
-import androidx.fragment.app.FragmentTransaction;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentStatePagerAdapter;
+import androidx.viewpager.widget.PagerAdapter;
+import androidx.viewpager.widget.ViewPager;
+import com.google.android.material.tabs.TabLayout;
+
+import org.jetbrains.annotations.NotNull;
+
+import app.fedilab.fedilabtube.databinding.ActivitySearchResultBinding;
+import app.fedilab.fedilabtube.fragment.DisplayChannelsFragment;
import app.fedilab.fedilabtube.fragment.DisplayVideosFragment;
import es.dmoral.toasty.Toasty;
@@ -29,12 +40,15 @@ public class SearchActivity extends AppCompatActivity {
private String search;
+ private ActivitySearchResultBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ binding = ActivitySearchResultBinding.inflate(getLayoutInflater());
+ View view = binding.getRoot();
+ setContentView(view);
- setContentView(R.layout.activity_search_result);
Bundle b = getIntent().getExtras();
if (b != null) {
search = b.getString("search");
@@ -46,15 +60,64 @@ public class SearchActivity extends AppCompatActivity {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setTitle(search);
+ binding.searchTabLayout.addTab(binding.searchTabLayout.newTab().setText(getString(R.string.videos)));
+ binding.searchTabLayout.addTab(binding.searchTabLayout.newTab().setText(getString(R.string.channels)));
+ binding.searchPager.setOffscreenPageLimit(2);
+
+ PagerAdapter mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
+ binding.searchPager.setAdapter(mPagerAdapter);
+ binding.searchPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ TabLayout.Tab tab = binding.searchTabLayout.getTabAt(position);
+ if (tab != null)
+ tab.select();
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+
+ }
+ });
+
+ binding.searchTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
+ @Override
+ public void onTabSelected(TabLayout.Tab tab) {
+ binding.searchPager.setCurrentItem(tab.getPosition());
+ }
+
+ @Override
+ public void onTabUnselected(TabLayout.Tab tab) {
+
+ }
+
+ @Override
+ public void onTabReselected(TabLayout.Tab tab) {
+ Fragment fragment = null;
+ if (binding.searchPager.getAdapter() != null)
+ fragment = (Fragment) binding.searchPager.getAdapter().instantiateItem(binding.searchPager, tab.getPosition());
+ switch (tab.getPosition()) {
+ case 0:
+ if (fragment != null) {
+ DisplayVideosFragment displayVideosFragment = ((DisplayVideosFragment) fragment);
+ displayVideosFragment.scrollToTop();
+ }
+ break;
+ case 1:
+ if (fragment != null) {
+ DisplayChannelsFragment displayChannelsFragment = ((DisplayChannelsFragment) fragment);
+ displayChannelsFragment.scrollToTop();
+ }
+ break;
+ }
+ }
+ });
- if (savedInstanceState == null) {
- DisplayVideosFragment displayVideosFragment = new DisplayVideosFragment();
- Bundle bundle = new Bundle();
- bundle.putString("search_peertube", search);
- displayVideosFragment.setArguments(bundle);
- FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
- ft.add(R.id.container, displayVideosFragment).commit();
- }
}
@@ -67,4 +130,37 @@ public class SearchActivity extends AppCompatActivity {
return super.onOptionsItemSelected(item);
}
+
+ /**
+ * Pager adapter for the 2 fragments
+ */
+ private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
+
+ ScreenSlidePagerAdapter(FragmentManager fm) {
+ super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
+ }
+
+ @NotNull
+ @Override
+ public Fragment getItem(int position) {
+ Bundle bundle = new Bundle();
+ if (position == 0) {
+ DisplayVideosFragment displayVideosFragment = new DisplayVideosFragment();
+ bundle.putString("search_peertube", search);
+ displayVideosFragment.setArguments(bundle);
+ return displayVideosFragment;
+ }
+ DisplayChannelsFragment displayChannelsFragment = new DisplayChannelsFragment();
+ bundle.putString("search_peertube", search);
+ displayChannelsFragment.setArguments(bundle);
+ return displayChannelsFragment;
+ }
+
+
+ @Override
+ public int getCount() {
+ return 2;
+ }
+ }
+
}
diff --git a/app/src/main/java/app/fedilab/fedilabtube/SepiaSearchActivity.java b/app/src/main/java/app/fedilab/fedilabtube/SepiaSearchActivity.java
index 618fd9b..b69e922 100644
--- a/app/src/main/java/app/fedilab/fedilabtube/SepiaSearchActivity.java
+++ b/app/src/main/java/app/fedilab/fedilabtube/SepiaSearchActivity.java
@@ -21,12 +21,8 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.RadioGroup;
-import android.widget.Spinner;
import androidx.appcompat.app.AppCompatActivity;
-import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
@@ -42,27 +38,29 @@ import java.util.List;
import java.util.Map;
import app.fedilab.fedilabtube.client.entities.SepiaSearch;
+import app.fedilab.fedilabtube.databinding.ActivitySepiaSearchBinding;
import app.fedilab.fedilabtube.fragment.DisplaySepiaSearchFragment;
import app.fedilab.fedilabtube.helper.Helper;
-import mabbas007.tagsedittext.TagsEditText;
-import static app.fedilab.fedilabtube.MainActivity.peertubeInformation;
import static app.fedilab.fedilabtube.PeertubeActivity.hideKeyboard;
+import static app.fedilab.fedilabtube.helper.Helper.peertubeInformation;
public class SepiaSearchActivity extends AppCompatActivity {
private SepiaSearch sepiaSearchVideo, sepiaSearchChannel;
- private TagsEditText sepia_element_all_of_tags, sepia_element_one_of_tags;
- private MaterialSearchBar searchBar;
- private ConstraintLayout filter_elements;
+
+ private ActivitySepiaSearchBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_sepia_search);
+ binding = ActivitySepiaSearchBinding.inflate(getLayoutInflater());
+ View rootView = binding.getRoot();
+ setContentView(rootView);
+
sepiaSearchVideo = new SepiaSearch();
sepiaSearchChannel = new SepiaSearch();
@@ -76,21 +74,18 @@ public class SepiaSearchActivity extends AppCompatActivity {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- Button filter = findViewById(R.id.filter);
- filter_elements = findViewById(R.id.filter_elements);
- filter.setOnClickListener(view -> {
- if (filter_elements.getVisibility() == View.VISIBLE) {
- filter_elements.setVisibility(View.GONE);
+ binding.filter.setOnClickListener(view -> {
+ if (binding.filterElements.getVisibility() == View.VISIBLE) {
+ binding.filterElements.setVisibility(View.GONE);
} else {
- filter_elements.setVisibility(View.VISIBLE);
+ binding.filterElements.setVisibility(View.VISIBLE);
}
});
- RadioGroup sepia_element_nsfw = findViewById(R.id.sepia_element_nsfw);
- sepia_element_nsfw.setOnCheckedChangeListener((group, checkedId) -> sepiaSearchVideo.setNsfw(checkedId != R.id.sepia_element_nsfw_no));
- RadioGroup radio_date = findViewById(R.id.radio_date);
- radio_date.setOnCheckedChangeListener((group, checkedId) -> {
+ binding.sepiaElementNsfw.setOnCheckedChangeListener((group, checkedId) -> sepiaSearchVideo.setNsfw(checkedId != R.id.sepia_element_nsfw_no));
+
+ binding.radioDate.setOnCheckedChangeListener((group, checkedId) -> {
if (checkedId == R.id.sepia_element_published_date_today) {
Calendar cal = GregorianCalendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0);
@@ -122,8 +117,7 @@ public class SepiaSearchActivity extends AppCompatActivity {
});
- RadioGroup duration = findViewById(R.id.duration);
- duration.setOnCheckedChangeListener((group, checkedId) -> {
+ binding.duration.setOnCheckedChangeListener((group, checkedId) -> {
if (checkedId == R.id.sepia_element_duration_short) {
sepiaSearchVideo.setDurationMin(0);
sepiaSearchVideo.setDurationMax(240);
@@ -140,11 +134,10 @@ public class SepiaSearchActivity extends AppCompatActivity {
});
- Spinner sort_by = findViewById(R.id.sort_by);
ArrayAdapter adapterSortBy = new ArrayAdapter<>(SepiaSearchActivity.this,
android.R.layout.simple_spinner_dropdown_item, getResources().getStringArray(R.array.sort_by_array));
- sort_by.setAdapter(adapterSortBy);
- sort_by.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ binding.sortBy.setAdapter(adapterSortBy);
+ binding.sortBy.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view, int position, long id) {
String orderby, channelOrderBy;
@@ -171,12 +164,6 @@ public class SepiaSearchActivity extends AppCompatActivity {
}
});
- Spinner sepia_element_category = findViewById(R.id.sepia_element_category);
- Spinner sepia_element_license = findViewById(R.id.sepia_element_license);
- Spinner sepia_element_language = findViewById(R.id.sepia_element_language);
-
- sepia_element_all_of_tags = findViewById(R.id.sepia_element_all_of_tags);
- sepia_element_one_of_tags = findViewById(R.id.sepia_element_one_of_tags);
LinkedHashMap categories = new LinkedHashMap<>(peertubeInformation.getCategories());
LinkedHashMap licences = new LinkedHashMap<>(peertubeInformation.getLicences());
@@ -203,7 +190,7 @@ public class SepiaSearchActivity extends AppCompatActivity {
}
ArrayAdapter adapterCatgories = new ArrayAdapter<>(SepiaSearchActivity.this,
android.R.layout.simple_spinner_dropdown_item, categoriesA);
- sepia_element_category.setAdapter(adapterCatgories);
+ binding.sepiaElementCategory.setAdapter(adapterCatgories);
//Populate licenses
@@ -222,7 +209,7 @@ public class SepiaSearchActivity extends AppCompatActivity {
}
ArrayAdapter adapterLicenses = new ArrayAdapter<>(SepiaSearchActivity.this,
android.R.layout.simple_spinner_dropdown_item, licensesA);
- sepia_element_license.setAdapter(adapterLicenses);
+ binding.sepiaElementLicense.setAdapter(adapterLicenses);
//Populate languages
String[] languagesA = new String[languages.size() + 1];
@@ -240,10 +227,10 @@ public class SepiaSearchActivity extends AppCompatActivity {
}
ArrayAdapter adapterLanguages = new ArrayAdapter<>(SepiaSearchActivity.this,
android.R.layout.simple_spinner_dropdown_item, languagesA);
- sepia_element_language.setAdapter(adapterLanguages);
+ binding.sepiaElementLanguage.setAdapter(adapterLanguages);
- sepia_element_license.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ binding.sepiaElementLicense.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view, int position, long id) {
updateLicensePosition(position);
@@ -255,7 +242,7 @@ public class SepiaSearchActivity extends AppCompatActivity {
}
});
//Manage categories
- sepia_element_category.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ binding.sepiaElementCategory.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view, int position, long id) {
updateCategoryPosition(position);
@@ -268,7 +255,7 @@ public class SepiaSearchActivity extends AppCompatActivity {
});
//Manage languages
- sepia_element_language.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ binding.sepiaElementLanguage.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view, int position, long id) {
updateLanguagesPosition(position);
@@ -281,9 +268,7 @@ public class SepiaSearchActivity extends AppCompatActivity {
});
- searchBar = findViewById(R.id.searchBar);
-
- searchBar.setOnSearchActionListener(new MaterialSearchBar.OnSearchActionListener() {
+ binding.searchBar.setOnSearchActionListener(new MaterialSearchBar.OnSearchActionListener() {
@Override
public void onSearchStateChanged(boolean enabled) {
@@ -299,22 +284,21 @@ public class SepiaSearchActivity extends AppCompatActivity {
makeSearch();
}
});
- Button apply_filter = findViewById(R.id.apply_filter);
- apply_filter.setOnClickListener(v -> makeSearch());
+ binding.applyFilter.setOnClickListener(v -> makeSearch());
- searchBar.openSearch();
+ binding.searchBar.openSearch();
}
private void makeSearch() {
hideKeyboard(SepiaSearchActivity.this);
sepiaSearchVideo.setStart("0");
- if (sepia_element_one_of_tags.getTags().size() > 0) {
- sepiaSearchVideo.setTagsOneOf(sepia_element_one_of_tags.getTags());
+ if (binding.sepiaElementOneOfTags.getTags().size() > 0) {
+ sepiaSearchVideo.setTagsOneOf(binding.sepiaElementOneOfTags.getTags());
} else {
sepiaSearchVideo.setTagsOneOf(null);
}
- if (sepia_element_all_of_tags.getTags().size() > 0) {
- sepiaSearchVideo.setTagsAllOf(sepia_element_all_of_tags.getTags());
+ if (binding.sepiaElementAllOfTags.getTags().size() > 0) {
+ sepiaSearchVideo.setTagsAllOf(binding.sepiaElementAllOfTags.getTags());
} else {
sepiaSearchVideo.setTagsAllOf(null);
}
@@ -322,8 +306,8 @@ public class SepiaSearchActivity extends AppCompatActivity {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("SEPIA_SEARCH");
if (fragment != null)
getSupportFragmentManager().beginTransaction().remove(fragment).commit();
- filter_elements.setVisibility(View.GONE);
- sepiaSearchVideo.setSearch(searchBar.getText());
+ binding.filterElements.setVisibility(View.GONE);
+ sepiaSearchVideo.setSearch(binding.searchBar.getText());
DisplaySepiaSearchFragment displaySepiaSearchFragment = new DisplaySepiaSearchFragment();
Bundle bundle = new Bundle();
bundle.putParcelable("sepiaSearchVideo", sepiaSearchVideo);
diff --git a/app/src/main/java/app/fedilab/fedilabtube/ShowAccountActivity.java b/app/src/main/java/app/fedilab/fedilabtube/ShowAccountActivity.java
index e9f41ca..259d2d2 100644
--- a/app/src/main/java/app/fedilab/fedilabtube/ShowAccountActivity.java
+++ b/app/src/main/java/app/fedilab/fedilabtube/ShowAccountActivity.java
@@ -288,13 +288,12 @@ public class ShowAccountActivity extends AppCompatActivity {
if (position == 0) {
DisplayChannelsFragment displayChannelsFragment = new DisplayChannelsFragment();
bundle.putString("name", account.getAcct());
- bundle.putBoolean("myChannels", false);
displayChannelsFragment.setArguments(bundle);
return displayChannelsFragment;
}
DisplayVideosFragment displayVideosFragment = new DisplayVideosFragment();
bundle.putSerializable(Helper.TIMELINE_TYPE, TimelineVM.TimelineType.ACCOUNT_VIDEOS);
- bundle.putString("channelId", account.getAcct());
+ bundle.putParcelable("account", account);
bundle.putString("peertube_instance", account.getHost());
displayVideosFragment.setArguments(bundle);
return displayVideosFragment;
diff --git a/app/src/main/java/app/fedilab/fedilabtube/ShowChannelActivity.java b/app/src/main/java/app/fedilab/fedilabtube/ShowChannelActivity.java
index faae6f7..a47deb1 100644
--- a/app/src/main/java/app/fedilab/fedilabtube/ShowChannelActivity.java
+++ b/app/src/main/java/app/fedilab/fedilabtube/ShowChannelActivity.java
@@ -157,18 +157,23 @@ public class ShowChannelActivity extends AppCompatActivity {
account_follow.setOnClickListener(v -> {
AlertDialog.Builder builderSingle = new AlertDialog.Builder(ShowChannelActivity.this);
builderSingle.setTitle(getString(R.string.list_of_accounts));
- if (accounts != null) {
- final OwnAccountsAdapter accountsListAdapter = new OwnAccountsAdapter(ShowChannelActivity.this, accounts);
- builderSingle.setAdapter(accountsListAdapter, (dialog, which) -> {
- new Thread(() -> {
- try {
- RetrofitPeertubeAPI peertubeAPI = new RetrofitPeertubeAPI(ShowChannelActivity.this, accounts.get(which).getHost(), accounts.get(which).getToken());
- peertubeAPI.post(FOLLOW, channel.getAcct(), null);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }).start();
- });
+ if (accounts != null && accounts.size() > 0) {
+ if (accounts.size() > 1) {
+ final OwnAccountsAdapter accountsListAdapter = new OwnAccountsAdapter(ShowChannelActivity.this, accounts);
+ builderSingle.setAdapter(accountsListAdapter, (dialog, which) -> {
+ new Thread(() -> {
+ try {
+ RetrofitPeertubeAPI peertubeAPI = new RetrofitPeertubeAPI(ShowChannelActivity.this, accounts.get(which).getHost(), accounts.get(which).getToken());
+ peertubeAPI.post(FOLLOW, channel.getAcct(), null);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }).start();
+ });
+ } else {
+ RetrofitPeertubeAPI peertubeAPI = new RetrofitPeertubeAPI(ShowChannelActivity.this, accounts.get(0).getHost(), accounts.get(0).getToken());
+ peertubeAPI.post(FOLLOW, channel.getAcct(), null);
+ }
}
builderSingle.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
builderSingle.show();
@@ -493,7 +498,7 @@ public class ShowChannelActivity extends AppCompatActivity {
DisplayVideosFragment displayVideosFragment = new DisplayVideosFragment();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.TIMELINE_TYPE, TimelineVM.TimelineType.CHANNEL_VIDEOS);
- bundle.putString("channelId", channel.getAcct());
+ bundle.putParcelable("channel", channel);
bundle.putString("peertube_instance", channel.getHost());
bundle.putBoolean("sepia_search", sepiaSearch);
displayVideosFragment.setArguments(bundle);
diff --git a/app/src/main/java/app/fedilab/fedilabtube/VideosTimelineActivity.java b/app/src/main/java/app/fedilab/fedilabtube/VideosTimelineActivity.java
index 211b336..3aff82b 100644
--- a/app/src/main/java/app/fedilab/fedilabtube/VideosTimelineActivity.java
+++ b/app/src/main/java/app/fedilab/fedilabtube/VideosTimelineActivity.java
@@ -33,7 +33,7 @@ import java.util.GregorianCalendar;
import java.util.Locale;
import app.fedilab.fedilabtube.client.APIResponse;
-import app.fedilab.fedilabtube.databinding.ActivitySearchResultBinding;
+import app.fedilab.fedilabtube.databinding.ActivityVideosTimelineBinding;
import app.fedilab.fedilabtube.fragment.DisplayVideosFragment;
import app.fedilab.fedilabtube.helper.Helper;
import app.fedilab.fedilabtube.viewmodel.TimelineVM;
@@ -50,7 +50,7 @@ public class VideosTimelineActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- ActivitySearchResultBinding binding = ActivitySearchResultBinding.inflate(getLayoutInflater());
+ ActivityVideosTimelineBinding binding = ActivityVideosTimelineBinding.inflate(getLayoutInflater());
View mainView = binding.getRoot();
setContentView(mainView);
@@ -131,6 +131,11 @@ public class VideosTimelineActivity extends AppCompatActivity {
}
+ @Override
+ public void onBackPressed() {
+ super.onBackPressed();
+ finish();
+ }
@Override
public boolean onOptionsItemSelected(MenuItem item) {
diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/MenuItemVideo.java b/app/src/main/java/app/fedilab/fedilabtube/client/MenuItemVideo.java
new file mode 100644
index 0000000..1c5465b
--- /dev/null
+++ b/app/src/main/java/app/fedilab/fedilabtube/client/MenuItemVideo.java
@@ -0,0 +1,53 @@
+package app.fedilab.fedilabtube.client;
+/* Copyright 2020 Thomas Schneider
+ *
+ * This file is a part of TubeLab
+ *
+ * This program is free software; you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with TubeLab; if not,
+ * see . */
+
+public class MenuItemVideo {
+
+ int icon;
+ String title;
+ actionType action;
+
+ public int getIcon() {
+ return icon;
+ }
+
+ public void setIcon(int icon) {
+ this.icon = icon;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public actionType getAction() {
+ return action;
+ }
+
+ public void setAction(actionType action) {
+ this.action = action;
+ }
+
+ public enum actionType {
+ RESOLUTION,
+ SPEED,
+ CAPTION,
+ AUTONEXT
+ }
+}
diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeService.java b/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeService.java
index 7592ad8..6286f7b 100644
--- a/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeService.java
+++ b/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeService.java
@@ -60,7 +60,11 @@ import retrofit2.http.QueryMap;
public interface PeertubeService {
@GET("instances")
- Call getInstances(@QueryMap Map params, @Query("nsfwPolicy[]") String nsfwPolicy, @Query("categoriesOr[]") List categories, @Query("languagesOr[]") List languages);
+ Call getInstances(
+ @QueryMap Map params,
+ @Query("nsfwPolicy[]") String nsfwPolicy,
+ @Query("categoriesOr[]") List categories,
+ @Query("languagesOr[]") List languages);
//Server settings
@GET(".well-known/nodeinfo")
@@ -70,6 +74,10 @@ public interface PeertubeService {
@GET("config/about")
Call configAbout();
+ //Instance config
+ @GET("config")
+ Call config();
+
@GET("{nodeInfoPath}")
Call getNodeinfo(@Path(value = "nodeInfoPath", encoded = true) String nodeInfoPath);
@@ -120,6 +128,9 @@ public interface PeertubeService {
Call verifyCredentials(@Header("Authorization") String credentials);
+ @GET("users/me/video-quota-used")
+ Call getVideoQuota(@Header("Authorization") String credentials);
+
@FormUrlEncoded
@PUT("videos/{id}/watching")
Call addToHistory(
@@ -142,6 +153,13 @@ public interface PeertubeService {
@Field("nsfwPolicy") String nsfwPolicy
);
+ @Multipart
+ @POST("video-channels/{channelHandle}/avatar/pick")
+ Call updateChannelProfilePicture(
+ @Header("Authorization") String credentials,
+ @Path("channelHandle") String channelHandle,
+ @Part MultipartBody.Part avatarfile);
+
@Multipart
@POST("users/me/avatar/pick")
Call updateProfilePicture(
@@ -187,7 +205,7 @@ public interface PeertubeService {
Call deleteHistory(
@Header("Authorization") String credentials);
- //Search
+ //Search videos
@GET("search/videos")
Call searchVideos(
@Header("Authorization") String credentials,
@@ -195,6 +213,14 @@ public interface PeertubeService {
@Query("start") String maxId,
@Query("count") String count);
+ //Search channels
+ @GET("search/video-channels")
+ Call searchChannels(
+ @Header("Authorization") String credentials,
+ @Query("search") String search,
+ @Query("searcharget") String searchTarget,
+ @Query("start") String maxId,
+ @Query("count") String count);
//Search
@GET("search/videos")
diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitPeertubeAPI.java b/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitPeertubeAPI.java
index 1e4f41b..846e8d4 100644
--- a/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitPeertubeAPI.java
+++ b/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitPeertubeAPI.java
@@ -19,12 +19,18 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
+import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.webkit.MimeTypeMap;
+import androidx.documentfile.provider.DocumentFile;
+
+import org.jetbrains.annotations.NotNull;
+import org.json.JSONException;
+import org.json.JSONObject;
+
import java.io.ByteArrayOutputStream;
-import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
@@ -68,6 +74,7 @@ import app.fedilab.fedilabtube.client.entities.UserSettings;
import app.fedilab.fedilabtube.client.entities.VideoParams;
import app.fedilab.fedilabtube.client.entities.WellKnownNodeinfo;
import app.fedilab.fedilabtube.helper.Helper;
+import app.fedilab.fedilabtube.helper.HelperInstance;
import app.fedilab.fedilabtube.sqlite.AccountDAO;
import app.fedilab.fedilabtube.sqlite.Sqlite;
import app.fedilab.fedilabtube.viewmodel.ChannelsVM;
@@ -95,8 +102,8 @@ public class RetrofitPeertubeAPI {
public RetrofitPeertubeAPI(Context context) {
_context = context;
- instance = Helper.getLiveInstance(context);
- finalUrl = "https://" + Helper.getLiveInstance(context) + "/api/v1/";
+ instance = HelperInstance.getLiveInstance(context);
+ finalUrl = "https://" + HelperInstance.getLiveInstance(context) + "/api/v1/";
SharedPreferences sharedpreferences = _context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
count = String.valueOf(sharedpreferences.getInt(Helper.SET_VIDEOS_PER_PAGE, Helper.VIDEOS_PER_PAGE));
}
@@ -118,7 +125,7 @@ public class RetrofitPeertubeAPI {
if (host.startsWith("tube") || BuildConfig.full_instances) {
instance = host;
} else {
- instance = Helper.getPeertubeUrl(host);
+ instance = HelperInstance.getPeertubeUrl(host);
}
try {
UserMe userMe = new RetrofitPeertubeAPI(activity, instance, token).verifyCredentials();
@@ -559,22 +566,7 @@ public class RetrofitPeertubeAPI {
throw error;
}
if (userSettings.getAvatarfile() != null) {
- InputStream inputStream = _context.getContentResolver().openInputStream(userSettings.getAvatarfile());
- ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
- int bufferSize = 1024;
- byte[] buffer = new byte[bufferSize];
-
- int len;
- while ((len = inputStream.read(buffer)) != -1) {
- byteBuffer.write(buffer, 0, len);
- }
- byte[] imageBytes = byteBuffer.toByteArray();
- String mime = MimeTypeMap.getFileExtensionFromUrl(userSettings.getAvatarfile().toString());
- if (mime == null || mime.trim().length() == 0) {
- mime = "png";
- }
- RequestBody requestFile = RequestBody.create(MediaType.parse("image/" + mime), imageBytes);
- MultipartBody.Part bodyThumbnail = MultipartBody.Part.createFormData("avatarfile", userSettings.getFileName(), requestFile);
+ MultipartBody.Part bodyThumbnail = createFile("avatarfile", userSettings.getAvatarfile(), userSettings.getFileName());
Call updateProfilePicture = peertubeService.updateProfilePicture(getToken(), bodyThumbnail);
Response responseAvatar = updateProfilePicture.execute();
if (response.isSuccessful()) {
@@ -594,6 +586,29 @@ public class RetrofitPeertubeAPI {
return avatarResponse;
}
+ private MultipartBody.Part createFile(@NotNull String paramName, @NotNull Uri uri, String filename) throws IOException {
+
+ InputStream inputStream = _context.getContentResolver().openInputStream(uri);
+ ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
+ int bufferSize = 1024;
+ byte[] buffer = new byte[bufferSize];
+
+ int len;
+ while ((len = inputStream.read(buffer)) != -1) {
+ byteBuffer.write(buffer, 0, len);
+ }
+ byte[] imageBytes = byteBuffer.toByteArray();
+ String mime = MimeTypeMap.getFileExtensionFromUrl(uri.toString());
+ if (mime == null || mime.trim().length() == 0) {
+ mime = "png";
+ }
+ if (filename == null) {
+ filename = "my_image." + mime;
+ }
+ RequestBody requestFile = RequestBody.create(imageBytes, MediaType.parse("image/" + mime));
+ return MultipartBody.Part.createFormData(paramName, filename, requestFile);
+ }
+
/**
* Check if users via their uris are following the authenticated user
*
@@ -662,6 +677,47 @@ public class RetrofitPeertubeAPI {
return null;
}
+ /**
+ * Config of the instance
+ *
+ * @return InstanceConfig
+ */
+ public InstanceData.InstanceConfig getConfigInstance() {
+
+ PeertubeService peertubeService = init();
+ Call config = peertubeService.config();
+ try {
+ Response response = config.execute();
+ if (response.isSuccessful() && response.body() != null) {
+ return response.body();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+
+ /**
+ * Get video quota
+ *
+ * @return UserMe.VideoQuota
+ */
+ public UserMe.VideoQuota getVideoQuota() {
+
+ PeertubeService peertubeService = init();
+ Call videoQuotaCall = peertubeService.getVideoQuota(getToken());
+ try {
+ Response response = videoQuotaCall.execute();
+ if (response.isSuccessful() && response.body() != null) {
+ return response.body();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
/**
* Returns informations about Peertube such privacies, licenses, etc.
*
@@ -815,7 +871,7 @@ public class RetrofitPeertubeAPI {
params.put("count", "250");
params.put("healthy", "true");
params.put("signup", "true");
- params.put("minUserQuota", instanceParams.getMinUserQuota());
+ params.put("sort", "-totalUsers");
Call instancesCall = peertubeService.getInstances(params, instanceParams.getNsfwPolicy(), instanceParams.getCategoriesOr(), instanceParams.getLanguagesOr());
APIResponse apiResponse = new APIResponse();
try {
@@ -876,6 +932,7 @@ public class RetrofitPeertubeAPI {
APIResponse apiResponse = new APIResponse();
try {
Response response = searchVideosCall.execute();
+
if (response.isSuccessful() && response.body() != null) {
apiResponse.setPeertubes(response.body().data);
} else {
@@ -890,6 +947,34 @@ public class RetrofitPeertubeAPI {
return apiResponse;
}
+
+ /**
+ * Retrieves channels search *synchronously*
+ *
+ * @param query String search
+ * @return APIResponse
+ */
+ public APIResponse searchChannels(String query, String max_id) {
+ PeertubeService peertubeService = init();
+ Call searchChannelsCall = peertubeService.searchChannels(getToken(), query, "local", max_id, count);
+ APIResponse apiResponse = new APIResponse();
+ try {
+ Response response = searchChannelsCall.execute();
+ if (response.isSuccessful() && response.body() != null) {
+ apiResponse.setChannels(response.body().data);
+ } else {
+ setError(apiResponse, response.code(), response.errorBody());
+ }
+ } catch (IOException e) {
+ Error error = new Error();
+ error.setError(_context.getString(R.string.toast_error));
+ apiResponse.setError(error);
+ e.printStackTrace();
+ }
+ return apiResponse;
+ }
+
+
/***
* Verifiy credential of the authenticated user *synchronously*
* @return Account
@@ -949,34 +1034,47 @@ public class RetrofitPeertubeAPI {
* @param previewfile File preview
* @return APIResponse
*/
- public APIResponse updateVideo(String videoId, VideoParams videoParams, File thumbnail, File previewfile) {
+ public APIResponse updateVideo(String videoId, VideoParams videoParams, Uri thumbnail, Uri previewfile) {
PeertubeService peertubeService = init();
+
MultipartBody.Part bodyThumbnail = null;
MultipartBody.Part bodyPreviewfile = null;
- if (thumbnail != null) {
- RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), thumbnail);
- bodyThumbnail = MultipartBody.Part.createFormData("image", thumbnail.getName(), requestFile);
+ try {
+ if (thumbnail != null) {
+ DocumentFile documentFile = DocumentFile.fromSingleUri(_context, thumbnail);
+ String thumbnailName = null;
+ if (documentFile != null) {
+ thumbnailName = documentFile.getName();
+ }
+ bodyThumbnail = createFile("avatarfile", thumbnail, thumbnailName);
+ }
+ if (previewfile != null && thumbnail != null) {
+ DocumentFile documentFile = DocumentFile.fromSingleUri(_context, thumbnail);
+ String previewfileName = null;
+ if (documentFile != null) {
+ previewfileName = documentFile.getName();
+ }
+ bodyPreviewfile = createFile("image", previewfile, previewfileName);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
}
- if (previewfile != null) {
- RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), previewfile);
- bodyPreviewfile = MultipartBody.Part.createFormData("image", previewfile.getName(), requestFile);
- }
- RequestBody channelId = RequestBody.create(MediaType.parse("text/plain"), videoParams.getChannelId());
- RequestBody description = RequestBody.create(MediaType.parse("text/plain"), videoParams.getDescription());
- RequestBody language = RequestBody.create(MediaType.parse("text/plain"), videoParams.getLanguage());
- RequestBody license = RequestBody.create(MediaType.parse("text/plain"), videoParams.getLicence());
- RequestBody name = RequestBody.create(MediaType.parse("text/plain"), videoParams.getName());
+ RequestBody channelId = RequestBody.create(videoParams.getChannelId(), MediaType.parse("text/plain"));
+ RequestBody description = RequestBody.create(videoParams.getDescription(), MediaType.parse("text/plain"));
+ RequestBody language = RequestBody.create(videoParams.getLanguage(), MediaType.parse("text/plain"));
+ RequestBody license = RequestBody.create(videoParams.getLicence(), MediaType.parse("text/plain"));
+ RequestBody name = RequestBody.create(videoParams.getName(), MediaType.parse("text/plain"));
List tags = null;
if (videoParams.getTags() != null && videoParams.getTags().size() > 0) {
tags = new ArrayList<>();
for (String tag : videoParams.getTags()) {
- tags.add(RequestBody.create(MediaType.parse("text/plain"), tag));
+ tags.add(RequestBody.create(tag, MediaType.parse("text/plain")));
}
}
RequestBody support = null;
if (videoParams.getSupport() != null) {
- support = RequestBody.create(MediaType.parse("text/plain"), videoParams.getSupport());
+ support = RequestBody.create(videoParams.getSupport(), MediaType.parse("text/plain"));
}
@@ -1187,7 +1285,7 @@ public class RetrofitPeertubeAPI {
* @param channelParams PlaylistParams
* @return APIResponse
*/
- public APIResponse createOrUpdateChannel(ChannelsVM.action apiAction, String channelId, ChannelParams channelParams) {
+ public APIResponse createOrUpdateChannel(ChannelsVM.action apiAction, String channelId, ChannelParams channelParams, Uri avatar) {
PeertubeService peertubeService = init();
APIResponse apiResponse = new APIResponse();
@@ -1210,6 +1308,21 @@ public class RetrofitPeertubeAPI {
setError(apiResponse, response.code(), response.errorBody());
}
}
+ if (avatar != null) {
+ DocumentFile documentFile = DocumentFile.fromSingleUri(_context, avatar);
+ String avatarfileName = null;
+ if (documentFile != null) {
+ avatarfileName = documentFile.getName();
+ }
+ MultipartBody.Part bodyThumbnail = createFile("avatarfile", avatar, avatarfileName);
+ Call updateProfilePicture = peertubeService.updateChannelProfilePicture(getToken(), channelId, bodyThumbnail);
+ Response responseAvatar = updateProfilePicture.execute();
+ if (responseAvatar.isSuccessful()) {
+ UserMe.AvatarResponse avatarResponse = responseAvatar.body();
+ } else {
+ setError(apiResponse, responseAvatar.code(), responseAvatar.errorBody());
+ }
+ }
} catch (IOException e) {
Error error = new Error();
error.setError(_context.getString(R.string.toast_error));
@@ -1333,21 +1446,31 @@ public class RetrofitPeertubeAPI {
* @param playlistParams PlaylistParams
* @return APIResponse
*/
- public APIResponse createOrUpdatePlaylist(PlaylistsVM.action apiAction, String playlistId, PlaylistParams playlistParams, File thumbnail) {
+ public APIResponse createOrUpdatePlaylist(PlaylistsVM.action apiAction, String playlistId, PlaylistParams playlistParams, Uri thumbnail) {
PeertubeService peertubeService = init();
APIResponse apiResponse = new APIResponse();
MultipartBody.Part body = null;
+
+ MultipartBody.Part bodyThumbnail = null;
if (thumbnail != null) {
- RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), thumbnail);
- body = MultipartBody.Part.createFormData("image", thumbnail.getName(), requestFile);
+ DocumentFile documentFile = DocumentFile.fromSingleUri(_context, thumbnail);
+ String avatarfileName = null;
+ if (documentFile != null) {
+ avatarfileName = documentFile.getName();
+ }
+ try {
+ bodyThumbnail = createFile("thumbnailfile", thumbnail, avatarfileName);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
}
try {
- RequestBody displayName = RequestBody.create(MediaType.parse("text/plain"), playlistParams.getDisplayName());
- RequestBody description = RequestBody.create(MediaType.parse("text/plain"), playlistParams.getDescription());
- RequestBody channelId = RequestBody.create(MediaType.parse("text/plain"), playlistParams.getVideoChannelId());
+ RequestBody displayName = RequestBody.create(playlistParams.getDisplayName(), MediaType.parse("text/plain"));
+ RequestBody description = RequestBody.create(playlistParams.getDescription(), MediaType.parse("text/plain"));
+ RequestBody channelId = RequestBody.create(playlistParams.getVideoChannelId(), MediaType.parse("text/plain"));
if (apiAction == PlaylistsVM.action.CREATE_PLAYLIST) {
- Call stringCall = peertubeService.addPlaylist(getToken(), displayName, description, playlistParams.getPrivacy(), channelId, body);
+ Call stringCall = peertubeService.addPlaylist(getToken(), displayName, description, playlistParams.getPrivacy(), channelId, bodyThumbnail);
Response response = stringCall.execute();
if (response.isSuccessful() && response.body() != null) {
apiResponse.setActionReturn(response.body().getVideoPlaylist().getId());
@@ -1356,7 +1479,7 @@ public class RetrofitPeertubeAPI {
}
} else if (apiAction == PlaylistsVM.action.UPDATE_PLAYLIST) {
- Call stringCall = peertubeService.updatePlaylist(getToken(), playlistId, displayName, description, playlistParams.getPrivacy(), channelId, body);
+ Call stringCall = peertubeService.updatePlaylist(getToken(), playlistId, displayName, description, playlistParams.getPrivacy(), channelId, bodyThumbnail);
Response response = stringCall.execute();
if (response.isSuccessful()) {
apiResponse.setActionReturn(response.body());
@@ -1621,10 +1744,10 @@ public class RetrofitPeertubeAPI {
* @param id String id
* @return APIResponse
*/
- public APIResponse getVideos(String id, boolean myVideo) {
+ public APIResponse getVideos(String id, boolean myVideo, boolean canUseToken) {
PeertubeService peertubeService = init();
Call video;
- if (myVideo) {
+ if (myVideo || canUseToken) {
video = peertubeService.getMyVideo(getToken(), id);
} else {
video = peertubeService.getVideo(id);
@@ -1632,19 +1755,49 @@ public class RetrofitPeertubeAPI {
APIResponse apiResponse = new APIResponse();
try {
Response response = video.execute();
-
if (response.isSuccessful()) {
List videos = new ArrayList<>();
videos.add(response.body());
apiResponse.setPeertubes(videos);
} else {
- Error error = new Error();
- error.setStatusCode(response.code());
+
if (response.errorBody() != null) {
- error.setError(response.errorBody().string());
+
+ String error = response.errorBody().string();
+ if (error.contains("originUrl")) {
+ try {
+ JSONObject jsonObject = new JSONObject(error);
+ List videos = new ArrayList<>();
+ VideoData.Video videoRedirect = new VideoData.Video();
+ videoRedirect.setErrorCode(jsonObject.getInt("errorCode"));
+ videoRedirect.setOriginUrl(jsonObject.getString("originUrl"));
+ videos.add(videoRedirect);
+ apiResponse.setPeertubes(videos);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ } else if (error.contains("error")) {
+ try {
+ JSONObject jsonObject = new JSONObject(error);
+ List videos = new ArrayList<>();
+ VideoData.Video videoErrorMessage = new VideoData.Video();
+ videoErrorMessage.setErrorMessage(jsonObject.getString("error"));
+ videos.add(videoErrorMessage);
+ apiResponse.setPeertubes(videos);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
} else {
- error.setError(_context.getString(R.string.toast_error));
+ Error error = new Error();
+ error.setStatusCode(response.code());
+ if (response.errorBody() != null) {
+ error.setError(response.errorBody().string());
+ } else {
+ error.setError(_context.getString(R.string.toast_error));
+ }
}
+
}
} catch (IOException e) {
Error error = new Error();
diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/data/InstanceData.java b/app/src/main/java/app/fedilab/fedilabtube/client/data/InstanceData.java
index 59eff4c..d802489 100644
--- a/app/src/main/java/app/fedilab/fedilabtube/client/data/InstanceData.java
+++ b/app/src/main/java/app/fedilab/fedilabtube/client/data/InstanceData.java
@@ -64,6 +64,7 @@ public class InstanceData {
@SerializedName("isNSFW")
private boolean isNSFW;
private SpannableStringBuilder spannableStringBuilder;
+ private boolean truncatedDescription = true;
public boolean isAutoBlacklistUserVideosEnabled() {
return autoBlacklistUserVideosEnabled;
@@ -240,6 +241,14 @@ public class InstanceData {
public void setCategories(List categories) {
this.categories = categories;
}
+
+ public boolean isTruncatedDescription() {
+ return truncatedDescription;
+ }
+
+ public void setTruncatedDescription(boolean truncatedDescription) {
+ this.truncatedDescription = truncatedDescription;
+ }
}
public static class InstanceInfo {
@@ -277,6 +286,7 @@ public class InstanceData {
@SerializedName("terms")
private String terms;
private String host;
+ private boolean truncatedDescription = true;
public AboutInstance() {
}
@@ -329,6 +339,14 @@ public class InstanceData {
this.host = host;
}
+ public boolean isTruncatedDescription() {
+ return truncatedDescription;
+ }
+
+ public void setTruncatedDescription(boolean truncatedDescription) {
+ this.truncatedDescription = truncatedDescription;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -343,5 +361,42 @@ public class InstanceData {
parcel.writeString(host);
}
}
+
+
+ public static class InstanceConfig {
+ @SerializedName("user")
+ private User user;
+
+ public User getUser() {
+ return user;
+ }
+
+ public void setUser(User user) {
+ this.user = user;
+ }
+ }
+
+ public static class User {
+ @SerializedName("videoQuota")
+ private long videoQuota;
+ @SerializedName("videoQuotaDaily")
+ private long videoQuotaDaily;
+
+ public long getVideoQuota() {
+ return videoQuota;
+ }
+
+ public void setVideoQuota(long videoQuota) {
+ this.videoQuota = videoQuota;
+ }
+
+ public long getVideoQuotaDaily() {
+ return videoQuotaDaily;
+ }
+
+ public void setVideoQuotaDaily(long videoQuotaDaily) {
+ this.videoQuotaDaily = videoQuotaDaily;
+ }
+ }
}
diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/data/VideoData.java b/app/src/main/java/app/fedilab/fedilabtube/client/data/VideoData.java
index 2a8676e..7bf47d4 100644
--- a/app/src/main/java/app/fedilab/fedilabtube/client/data/VideoData.java
+++ b/app/src/main/java/app/fedilab/fedilabtube/client/data/VideoData.java
@@ -43,6 +43,7 @@ public class VideoData {
@SerializedName("data")
public List