Compare commits
96 commits
transcodin
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
e009b86153 | ||
|
d669dcb618 | ||
|
ff5bce074e | ||
|
d85684317b | ||
|
3cc52938f2 | ||
|
3ff71ae489 | ||
|
b511b26aa1 | ||
|
059b17af9a | ||
|
c293c906d4 | ||
|
b5d31a6c72 | ||
|
89d5a332d1 | ||
|
4e8ee15d0a | ||
|
36dd8480e1 | ||
|
a6c1ef15b7 | ||
|
75ea1dc43a | ||
|
2b2e6ce58b | ||
|
09427e1de0 | ||
|
fbf4c185f0 | ||
|
c84ec082be | ||
|
5a8403f6a9 | ||
|
362201eddf | ||
|
afbf68937d | ||
|
8139119c35 | ||
|
ab090a01d7 | ||
|
2253780903 | ||
|
3340ce4e58 | ||
|
ce66bbc0b2 | ||
|
e122ef303e | ||
|
dedb99b73d | ||
|
4bf8e6b697 | ||
|
89fb969d67 | ||
|
eac3eaa3f3 | ||
|
e6c49ea660 | ||
|
44c1b51553 | ||
|
e18e73cca8 | ||
|
5156333a95 | ||
|
eface29638 | ||
|
44b6e915ba | ||
|
a1cbea0b92 | ||
|
e987ac477d | ||
|
9baa84e1e7 | ||
|
ed69473e26 | ||
|
73d1b7c099 | ||
|
f269bea184 | ||
|
5c283982bb | ||
|
cb4518c86e | ||
|
2d141b6f0f | ||
|
ab19866899 | ||
|
168cfcd19f | ||
|
288c96709e | ||
|
8b5c19b957 | ||
|
be1da2eb7b | ||
|
61af530c89 | ||
|
7b508fa456 | ||
|
fcb58ef8ad | ||
|
09f3d218c1 | ||
|
350afaa8a9 | ||
|
ba2f9d9708 | ||
|
e74a86da24 | ||
|
5ab65062e6 | ||
|
6095c97704 | ||
|
91cccc55a7 | ||
|
df984fb24b | ||
|
9f3be43eac | ||
|
0999823d6d | ||
|
e10ae9c487 | ||
|
ce9eed6344 | ||
|
d4e6351a2d | ||
|
f75079f720 | ||
|
4a3afe62ef | ||
|
50b39d6658 | ||
|
3c6e03db89 | ||
|
05730a513c | ||
|
674699aeab | ||
|
f9454029f7 | ||
|
2b9831af56 | ||
|
6402a6a0c4 | ||
|
a740d3fc71 | ||
|
9711f4c4fb | ||
|
916d71a085 | ||
|
bdef58d433 | ||
|
4a3a22de37 | ||
|
6a917be93f | ||
|
7f02f3de0a | ||
|
14eb313b1e | ||
|
85ff16d843 | ||
|
92eaefe6e1 | ||
|
216092888a | ||
|
a972832aae | ||
|
722267ced2 | ||
|
da64c968bc | ||
|
b5f5a6eaed | ||
|
49d52f9713 | ||
|
5b38bdb1c1 | ||
|
689c5cff3f | ||
|
3db0f57437 |
350 changed files with 6692 additions and 2996 deletions
113
.github/workflows/build.yaml
vendored
113
.github/workflows/build.yaml
vendored
|
@ -5,26 +5,27 @@ on:
|
|||
pull_request:
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Validate Gradle Wrapper
|
||||
uses: gradle/actions/wrapper-validation@v3
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: temurin
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew lintDebug ktlintCheck
|
||||
# lint:
|
||||
# name: Lint
|
||||
# runs-on: ubuntu-22.04
|
||||
# steps:
|
||||
# - name: Checkout repository
|
||||
# uses: actions/checkout@v4
|
||||
# - name: Validate Gradle Wrapper
|
||||
# uses: gradle/actions/wrapper-validation@v3
|
||||
# - name: Set up JDK 17
|
||||
# uses: actions/setup-java@v4
|
||||
# with:
|
||||
# java-version: 17
|
||||
# distribution: temurin
|
||||
# - name: Setup Gradle
|
||||
# uses: gradle/actions/setup-gradle@v3
|
||||
# - name: Build with Gradle
|
||||
# run: ./gradlew lintDebug ktlintCheck
|
||||
assemble:
|
||||
name: Assemble
|
||||
runs-on: ubuntu-22.04
|
||||
if: startsWith(github.event.head_commit.message, 'build:')
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
@ -38,45 +39,45 @@ jobs:
|
|||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew assembleDebug
|
||||
run: ./gradlew assemble
|
||||
# Upload all build artifacts in separate steps. This can be shortened once https://github.com/actions/upload-artifact/pull/354 is merged.
|
||||
- name: Upload artifact phone-libre-arm64-v8a-debug.apk
|
||||
- name: Upload artifact ananas-v0.10.3-0.14.2-libre-arm64-v8a.apk
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: phone-libre-arm64-v8a-debug.apk
|
||||
path: ./app/phone/build/outputs/apk/libre/debug/phone-libre-arm64-v8a-debug.apk
|
||||
- name: Upload artifact phone-libre-armeabi-v7a-debug.apk
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: phone-libre-armeabi-v7a-debug.apk
|
||||
path: ./app/phone/build/outputs/apk/libre/debug/phone-libre-armeabi-v7a-debug.apk
|
||||
- name: Upload artifact phone-libre-x86_64-debug.apk
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: phone-libre-x86_64-debug.apk
|
||||
path: ./app/phone/build/outputs/apk/libre/debug/phone-libre-x86_64-debug.apk
|
||||
- name: Upload artifact phone-libre-x86-debug.apk
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: phone-libre-x86-debug.apk
|
||||
path: ./app/phone/build/outputs/apk/libre/debug/phone-libre-x86-debug.apk
|
||||
- name: Upload artifact tv-libre-arm64-v8a-debug.apk
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: tv-libre-arm64-v8a-debug.apk
|
||||
path: ./app/tv/build/outputs/apk/libre/debug/tv-libre-arm64-v8a-debug.apk
|
||||
- name: Upload artifact tv-libre-armeabi-v7a-debug.apk
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: tv-libre-armeabi-v7a-debug.apk
|
||||
path: ./app/tv/build/outputs/apk/libre/debug/tv-libre-armeabi-v7a-debug.apk
|
||||
- name: Upload artifact tv-libre-x86_64-debug.apk
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: tv-libre-x86_64-debug.apk
|
||||
path: ./app/tv/build/outputs/apk/libre/debug/tv-libre-x86_64-debug.apk
|
||||
- name: Upload artifact tv-libre-x86-debug.apk
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: tv-libre-x86-debug.apk
|
||||
path: ./app/tv/build/outputs/apk/libre/debug/tv-libre-x86-debug.apk
|
||||
name: phone-libre-arm64-v8a.apk
|
||||
path: ./app/phone/build/outputs/apk/libre/release/ananas-v0.10.3-0.14.2-libre-arm64-v8a.apk
|
||||
# - name: Upload artifact phone-libre-armeabi-v7a-debug.apk
|
||||
# uses: actions/upload-artifact@v4
|
||||
# with:
|
||||
# name: phone-libre-armeabi-v7a-debug.apk
|
||||
# path: ./app/phone/build/outputs/apk/libre/debug/phone-libre-armeabi-v7a-debug.apk
|
||||
# - name: Upload artifact phone-libre-x86_64-debug.apk
|
||||
# uses: actions/upload-artifact@v4
|
||||
# with:
|
||||
# name: phone-libre-x86_64-debug.apk
|
||||
# path: ./app/phone/build/outputs/apk/libre/debug/phone-libre-x86_64-debug.apk
|
||||
# - name: Upload artifact phone-libre-x86-debug.apk
|
||||
# uses: actions/upload-artifact@v4
|
||||
# with:
|
||||
# name: phone-libre-x86-debug.apk
|
||||
# path: ./app/phone/build/outputs/apk/libre/debug/phone-libre-x86-debug.apk
|
||||
# - name: Upload artifact tv-libre-arm64-v8a-debug.apk
|
||||
# uses: actions/upload-artifact@v4
|
||||
# with:
|
||||
# name: tv-libre-arm64-v8a-debug.apk
|
||||
# path: ./app/tv/build/outputs/apk/libre/debug/tv-libre-arm64-v8a-debug.apk
|
||||
# - name: Upload artifact tv-libre-armeabi-v7a-debug.apk
|
||||
# uses: actions/upload-artifact@v4
|
||||
# with:
|
||||
# name: tv-libre-armeabi-v7a-debug.apk
|
||||
# path: ./app/tv/build/outputs/apk/libre/debug/tv-libre-armeabi-v7a-debug.apk
|
||||
# - name: Upload artifact tv-libre-x86_64-debug.apk
|
||||
# uses: actions/upload-artifact@v4
|
||||
# with:
|
||||
# name: tv-libre-x86_64-debug.apk
|
||||
# path: ./app/tv/build/outputs/apk/libre/debug/tv-libre-x86_64-debug.apk
|
||||
# - name: Upload artifact tv-libre-x86-debug.apk
|
||||
# uses: actions/upload-artifact@v4
|
||||
# with:
|
||||
# name: tv-libre-x86-debug.apk
|
||||
# path: ./app/tv/build/outputs/apk/libre/debug/tv-libre-x86-debug.apk
|
||||
|
|
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -10,10 +10,14 @@ local.properties
|
|||
|
||||
# Android Studio generated files and folders
|
||||
captures/
|
||||
app/phone/libre/release/
|
||||
.kotlin
|
||||
.externalNativeBuild/
|
||||
.cxx/
|
||||
*.apk
|
||||
*.dm
|
||||
output.json
|
||||
app/phone/libre/release/output-metadata.json
|
||||
|
||||
# IntelliJ
|
||||
*.iml
|
||||
|
@ -37,3 +41,4 @@ fastlane/report.xml
|
|||
fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
fastlane/test_output
|
||||
push.sh
|
||||
|
|
7
PRIVACY
7
PRIVACY
|
@ -1,7 +1,6 @@
|
|||
This privacy policy pertains the Findroid app.
|
||||
This privacy policy pertains the Ananas app.
|
||||
|
||||
Findroid does not collect or access any personal information. No identifying information or user data of any kind is made available to third-parties.
|
||||
Ananas does not collect or access any personal information. No identifying information or user data of any kind is made available to third-parties.
|
||||
|
||||
This Privacy Policy is effective as of Feb 8th, 2023 and will remain in effect except with respect to any changes in its provisions in the future, which will be in effect immediately after being posted on this page. We reserve the right to update or change our Privacy Policy at any time and you should check this Privacy Policy periodically. Your continued use of the Service after we post any modifications to the Privacy Policy on this page will constitute your acknowledgment of the modifications and your consent to abide and be bound by the modified Privacy Policy.
|
||||
This Privacy Policy is effective as of Jun 24th, 2024 and will remain in effect except with respect to any changes in its provisions in the future, which will be in effect immediately after being posted on this page. We reserve the right to update or change our Privacy Policy at any time and you should check this Privacy Policy periodically. Your continued use of the Service after we post any modifications to the Privacy Policy on this page will constitute your acknowledgment of the modifications and your consent to abide and be bound by the modified Privacy Policy.
|
||||
|
||||
Findroid is published by Jarne Demeulemeester. Inquiries can be submitted to jarnedemeulemeester@gmail.com.
|
||||
|
|
36
README.md
36
README.md
|
@ -1,21 +1,6 @@
|
|||

|
||||
|
||||
# Findroid
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
Findroid is third-party Android application for Jellyfin that provides a native user interface to browse and play movies and series.
|
||||
|
||||
I am developing this application in my spare time.
|
||||
|
||||
**This project is in its early stages so expect bugs.**
|
||||
|
||||
<a href='https://play.google.com/store/apps/details?id=dev.jdtech.jellyfin'><img alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png' height="80"/></a><a href='http://www.amazon.com/gp/product/B0BTWC8DNZ'><img alt='Available at Amazon Appstore' src='https://user-images.githubusercontent.com/32322857/219019331-027a6775-7362-44bb-a026-281f71e9b37b.png' height="80"/></a><a href='https://apt.izzysoft.de/fdroid/index/apk/dev.jdtech.jellyfin'><img alt='Get it on IzzyOnDroid' src='https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png' height="80"/></a>
|
||||
|
||||
# Ananas
|
||||
Personal fork
|
||||
## Screenshots
|
||||
| Home | Library | Movie | Season | Episode |
|
||||
|-------------------------------------|-------------------------------------|---------------------------------|-----------------------------------|-------------------------------------|
|
||||
|
@ -24,8 +9,9 @@ I am developing this application in my spare time.
|
|||
## Features
|
||||
- Completely native interface
|
||||
- Supported media items: movies, series, seasons, episodes
|
||||
- Direct play only, (no transcoding)
|
||||
- Offline playback / downloads
|
||||
- Direct play and Transcoding
|
||||
- Offline playback / downloads
|
||||
- Transcoding Downloads (Original - 720p - 480p - 360p)
|
||||
- ExoPlayer
|
||||
- Video codecs: H.263, H.264, H.265, VP8, VP9, AV1
|
||||
- Support depends on Android device
|
||||
|
@ -49,20 +35,8 @@ I am developing this application in my spare time.
|
|||
- Websocket connection (Syncplay)
|
||||
- Chromecast support
|
||||
|
||||
## Translating
|
||||
[JDTech Weblate](https://weblate.jdtech.dev) is a selfhosted instance of Weblate where you can translate this project and future projects of mine.
|
||||
|
||||
## Questions?
|
||||
[](https://discord.gg/tg5VvTFwTV)\
|
||||
We have a Discord server to discuss future development or ask general questions.
|
||||
|
||||
## License
|
||||
This project is licensed under [GPLv3](LICENSE).
|
||||
|
||||
The logo is a combination of the Jellyfin logo and the Android robot.
|
||||
|
||||
The Android robot is reproduced or modified from work created and shared by Google and used according to terms described in the Creative Commons 3.0 Attribution License.
|
||||
|
||||
Android is a trademark of Google LLC.
|
||||
|
||||
Google Play and the Google Play logo are trademarks of Google LLC.
|
||||
|
|
87
app/phone/Ananas/release/output-metadata.json
Normal file
87
app/phone/Ananas/release/output-metadata.json
Normal file
|
@ -0,0 +1,87 @@
|
|||
{
|
||||
"version": 3,
|
||||
"artifactType": {
|
||||
"type": "APK",
|
||||
"kind": "Directory"
|
||||
},
|
||||
"applicationId": "com.nomadics9.ananas",
|
||||
"variantName": "AnanasRelease",
|
||||
"elements": [
|
||||
{
|
||||
"type": "ONE_OF_MANY",
|
||||
"filters": [
|
||||
{
|
||||
"filterType": "ABI",
|
||||
"value": "armeabi-v7a"
|
||||
}
|
||||
],
|
||||
"attributes": [],
|
||||
"versionCode": 16,
|
||||
"versionName": "0.10.6-0.14.2",
|
||||
"outputFile": "ananas-v0.10.6-0.14.2-Ananas-armeabi-v7a.apk"
|
||||
},
|
||||
{
|
||||
"type": "ONE_OF_MANY",
|
||||
"filters": [
|
||||
{
|
||||
"filterType": "ABI",
|
||||
"value": "arm64-v8a"
|
||||
}
|
||||
],
|
||||
"attributes": [],
|
||||
"versionCode": 16,
|
||||
"versionName": "0.10.6-0.14.2",
|
||||
"outputFile": "ananas-v0.10.6-0.14.2-Ananas-arm64-v8a.apk"
|
||||
},
|
||||
{
|
||||
"type": "ONE_OF_MANY",
|
||||
"filters": [
|
||||
{
|
||||
"filterType": "ABI",
|
||||
"value": "x86_64"
|
||||
}
|
||||
],
|
||||
"attributes": [],
|
||||
"versionCode": 16,
|
||||
"versionName": "0.10.6-0.14.2",
|
||||
"outputFile": "ananas-v0.10.6-0.14.2-Ananas-x86_64.apk"
|
||||
},
|
||||
{
|
||||
"type": "ONE_OF_MANY",
|
||||
"filters": [
|
||||
{
|
||||
"filterType": "ABI",
|
||||
"value": "x86"
|
||||
}
|
||||
],
|
||||
"attributes": [],
|
||||
"versionCode": 16,
|
||||
"versionName": "0.10.6-0.14.2",
|
||||
"outputFile": "ananas-v0.10.6-0.14.2-Ananas-x86.apk"
|
||||
}
|
||||
],
|
||||
"elementType": "File",
|
||||
"baselineProfiles": [
|
||||
{
|
||||
"minApi": 28,
|
||||
"maxApi": 30,
|
||||
"baselineProfiles": [
|
||||
"baselineProfiles/1/ananas-v0.10.6-0.14.2-Ananas-armeabi-v7a.dm",
|
||||
"baselineProfiles/1/ananas-v0.10.6-0.14.2-Ananas-arm64-v8a.dm",
|
||||
"baselineProfiles/1/ananas-v0.10.6-0.14.2-Ananas-x86_64.dm",
|
||||
"baselineProfiles/1/ananas-v0.10.6-0.14.2-Ananas-x86.dm"
|
||||
]
|
||||
},
|
||||
{
|
||||
"minApi": 31,
|
||||
"maxApi": 2147483647,
|
||||
"baselineProfiles": [
|
||||
"baselineProfiles/0/ananas-v0.10.6-0.14.2-Ananas-armeabi-v7a.dm",
|
||||
"baselineProfiles/0/ananas-v0.10.6-0.14.2-Ananas-arm64-v8a.dm",
|
||||
"baselineProfiles/0/ananas-v0.10.6-0.14.2-Ananas-x86_64.dm",
|
||||
"baselineProfiles/0/ananas-v0.10.6-0.14.2-Ananas-x86.dm"
|
||||
]
|
||||
}
|
||||
],
|
||||
"minSdkVersionForDexing": 28
|
||||
}
|
|
@ -10,19 +10,23 @@ plugins {
|
|||
}
|
||||
|
||||
android {
|
||||
namespace = "dev.jdtech.jellyfin"
|
||||
namespace = "com.nomadics9.ananas"
|
||||
compileSdk = Versions.compileSdk
|
||||
buildToolsVersion = Versions.buildTools
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "dev.jdtech.jellyfin"
|
||||
applicationId = "com.nomadics9.ananas"
|
||||
minSdk = Versions.minSdk
|
||||
targetSdk = Versions.targetSdk
|
||||
|
||||
versionCode = Versions.appCode
|
||||
versionName = Versions.appName
|
||||
|
||||
testInstrumentationRunner = "dev.jdtech.jellyfin.HiltTestRunner"
|
||||
testInstrumentationRunner = "com.nomadics9.ananas.HiltTestRunner"
|
||||
buildConfigField( "String", "DEFAULT_SERVER_ADDRESS", "\" \"")
|
||||
buildConfigField( "String", "REQUEST_SERVER_ADDRESS", "\" \"")
|
||||
buildConfigField("String", "FORGET_PASSWORD_ADDRESS", "\" \"")
|
||||
buildConfigField("String", "UPDATE_ADDRESS", "\" \"")
|
||||
}
|
||||
|
||||
applicationVariants.all {
|
||||
|
@ -31,7 +35,7 @@ android {
|
|||
.map { it as com.android.build.gradle.internal.api.BaseVariantOutputImpl }
|
||||
.forEach { output ->
|
||||
if (variant.buildType.name == "release") {
|
||||
val outputFileName = "findroid-v${variant.versionName}-${variant.flavorName}-${output.getFilter("ABI")}.apk"
|
||||
val outputFileName = "ananas-v${variant.versionName}-${variant.flavorName}-${output.getFilter("ABI")}.apk"
|
||||
output.outputFileName = outputFileName
|
||||
}
|
||||
}
|
||||
|
@ -57,10 +61,18 @@ android {
|
|||
|
||||
flavorDimensions += "variant"
|
||||
productFlavors {
|
||||
register("libre") {
|
||||
create("libre") {
|
||||
dimension = "variant"
|
||||
isDefault = true
|
||||
}
|
||||
create("Ananas") {
|
||||
dimension = "variant"
|
||||
isDefault = false
|
||||
buildConfigField( "String", "DEFAULT_SERVER_ADDRESS", "\"https://askar.tv\"")
|
||||
buildConfigField( "String", "REQUEST_SERVER_ADDRESS", "\"https://r.askar.tv\"")
|
||||
buildConfigField("String", "FORGET_PASSWORD_ADDRESS", "\"https://user.askar.tv/my/account\"")
|
||||
buildConfigField("String", "UPDATE_ADDRESS", "\"https://fs.nmd.mov/p/ananas.apk\"")
|
||||
}
|
||||
}
|
||||
|
||||
splits {
|
||||
|
@ -122,6 +134,7 @@ dependencies {
|
|||
implementation(libs.material)
|
||||
implementation(libs.media3.ffmpeg.decoder)
|
||||
implementation(libs.timber)
|
||||
implementation(libs.markwon)
|
||||
|
||||
coreLibraryDesugaring(libs.android.desugar.jdk)
|
||||
|
||||
|
|
87
app/phone/libre/release/output-metadata.json
Normal file
87
app/phone/libre/release/output-metadata.json
Normal file
|
@ -0,0 +1,87 @@
|
|||
{
|
||||
"version": 3,
|
||||
"artifactType": {
|
||||
"type": "APK",
|
||||
"kind": "Directory"
|
||||
},
|
||||
"applicationId": "com.nomadics9.ananas",
|
||||
"variantName": "libreRelease",
|
||||
"elements": [
|
||||
{
|
||||
"type": "ONE_OF_MANY",
|
||||
"filters": [
|
||||
{
|
||||
"filterType": "ABI",
|
||||
"value": "armeabi-v7a"
|
||||
}
|
||||
],
|
||||
"attributes": [],
|
||||
"versionCode": 11,
|
||||
"versionName": "0.10.1-0.14.2",
|
||||
"outputFile": "ananas-v0.10.1-0.14.2-libre-armeabi-v7a.apk"
|
||||
},
|
||||
{
|
||||
"type": "ONE_OF_MANY",
|
||||
"filters": [
|
||||
{
|
||||
"filterType": "ABI",
|
||||
"value": "x86_64"
|
||||
}
|
||||
],
|
||||
"attributes": [],
|
||||
"versionCode": 11,
|
||||
"versionName": "0.10.1-0.14.2",
|
||||
"outputFile": "ananas-v0.10.1-0.14.2-libre-x86_64.apk"
|
||||
},
|
||||
{
|
||||
"type": "ONE_OF_MANY",
|
||||
"filters": [
|
||||
{
|
||||
"filterType": "ABI",
|
||||
"value": "arm64-v8a"
|
||||
}
|
||||
],
|
||||
"attributes": [],
|
||||
"versionCode": 11,
|
||||
"versionName": "0.10.1-0.14.2",
|
||||
"outputFile": "ananas-v0.10.1-0.14.2-libre-arm64-v8a.apk"
|
||||
},
|
||||
{
|
||||
"type": "ONE_OF_MANY",
|
||||
"filters": [
|
||||
{
|
||||
"filterType": "ABI",
|
||||
"value": "x86"
|
||||
}
|
||||
],
|
||||
"attributes": [],
|
||||
"versionCode": 11,
|
||||
"versionName": "0.10.1-0.14.2",
|
||||
"outputFile": "ananas-v0.10.1-0.14.2-libre-x86.apk"
|
||||
}
|
||||
],
|
||||
"elementType": "File",
|
||||
"baselineProfiles": [
|
||||
{
|
||||
"minApi": 28,
|
||||
"maxApi": 30,
|
||||
"baselineProfiles": [
|
||||
"baselineProfiles/1/ananas-v0.10.1-0.14.2-libre-armeabi-v7a.dm",
|
||||
"baselineProfiles/1/ananas-v0.10.1-0.14.2-libre-x86_64.dm",
|
||||
"baselineProfiles/1/ananas-v0.10.1-0.14.2-libre-arm64-v8a.dm",
|
||||
"baselineProfiles/1/ananas-v0.10.1-0.14.2-libre-x86.dm"
|
||||
]
|
||||
},
|
||||
{
|
||||
"minApi": 31,
|
||||
"maxApi": 2147483647,
|
||||
"baselineProfiles": [
|
||||
"baselineProfiles/0/ananas-v0.10.1-0.14.2-libre-armeabi-v7a.dm",
|
||||
"baselineProfiles/0/ananas-v0.10.1-0.14.2-libre-x86_64.dm",
|
||||
"baselineProfiles/0/ananas-v0.10.1-0.14.2-libre-arm64-v8a.dm",
|
||||
"baselineProfiles/0/ananas-v0.10.1-0.14.2-libre-x86.dm"
|
||||
]
|
||||
}
|
||||
],
|
||||
"minSdkVersionForDexing": 28
|
||||
}
|
16
app/phone/proguard-rules.pro
vendored
16
app/phone/proguard-rules.pro
vendored
|
@ -20,16 +20,16 @@
|
|||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
||||
-keepnames class dev.jdtech.jellyfin.models.PlayerItem
|
||||
-keepnames class com.nomadics9.ananas.models.PlayerItem
|
||||
|
||||
# ProGuard thinks all SettingsFragments are unused
|
||||
-keep class dev.jdtech.jellyfin.fragments.SettingsLanguageFragment
|
||||
-keep class dev.jdtech.jellyfin.fragments.SettingsAppearanceFragment
|
||||
-keep class dev.jdtech.jellyfin.fragments.SettingsDownloadsFragment
|
||||
-keep class dev.jdtech.jellyfin.fragments.SettingsPlayerFragment
|
||||
-keep class dev.jdtech.jellyfin.fragments.SettingsDeviceFragment
|
||||
-keep class dev.jdtech.jellyfin.fragments.SettingsCacheFragment
|
||||
-keep class dev.jdtech.jellyfin.fragments.SettingsNetworkFragment
|
||||
-keep class com.nomadics9.ananas.fragments.SettingsLanguageFragment
|
||||
-keep class com.nomadics9.ananas.fragments.SettingsAppearanceFragment
|
||||
-keep class com.nomadics9.ananas.fragments.SettingsDownloadsFragment
|
||||
-keep class com.nomadics9.ananas.fragments.SettingsPlayerFragment
|
||||
-keep class com.nomadics9.ananas.fragments.SettingsDeviceFragment
|
||||
-keep class com.nomadics9.ananas.fragments.SettingsCacheFragment
|
||||
-keep class com.nomadics9.ananas.fragments.SettingsNetworkFragment
|
||||
|
||||
# These classes are from okhttp and are not used in Android
|
||||
-dontwarn org.bouncycastle.jsse.BCSSLSocket
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin
|
||||
package com.nomadics9.ananas
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin
|
||||
package com.nomadics9.ananas
|
||||
|
||||
import android.util.Log
|
||||
import androidx.hilt.work.HiltWorkerFactory
|
||||
|
@ -19,7 +19,7 @@ import androidx.work.testing.WorkManagerTestInitHelper
|
|||
import dagger.hilt.android.testing.HiltAndroidRule
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import dagger.hilt.android.testing.UninstallModules
|
||||
import dev.jdtech.jellyfin.di.DatabaseModule
|
||||
import com.nomadics9.ananas.di.DatabaseModule
|
||||
import org.hamcrest.CoreMatchers.allOf
|
||||
import org.hamcrest.CoreMatchers.not
|
||||
import org.junit.Before
|
||||
|
@ -76,9 +76,9 @@ class MainActivityTest {
|
|||
waitForElement(allOf(withText("Movies"), isDisplayed()))
|
||||
onView(withText("Movies")).perform(click())
|
||||
|
||||
// Navigate to The Boy in the Plastic Bubble
|
||||
waitForElement(allOf(withText("The Boy in the Plastic Bubble"), isDisplayed()))
|
||||
onView(withText("The Boy in the Plastic Bubble")).perform(click())
|
||||
// Navigate to Battle of the Stars
|
||||
waitForElement(allOf(withText("Battle of the Stars"), isDisplayed()))
|
||||
onView(withText("Battle of the Stars")).perform(click())
|
||||
|
||||
// Play the movie
|
||||
waitForElement(allOf(withId(R.id.play_button), isEnabled()))
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin
|
||||
package com.nomadics9.ananas
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewTreeObserver
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.di
|
||||
package com.nomadics9.ananas.di
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Room
|
||||
|
@ -7,8 +7,8 @@ import dagger.Provides
|
|||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import dev.jdtech.jellyfin.database.ServerDatabase
|
||||
import dev.jdtech.jellyfin.database.ServerDatabaseDao
|
||||
import com.nomadics9.ananas.database.ServerDatabase
|
||||
import com.nomadics9.ananas.database.ServerDatabaseDao
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin
|
||||
package com.nomadics9.ananas
|
||||
|
||||
import android.app.Application
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
|
@ -14,7 +14,7 @@ import com.google.android.material.color.DynamicColorsOptions
|
|||
import dagger.hilt.android.HiltAndroidApp
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
@HiltAndroidApp
|
||||
class BaseApplication : Application(), Configuration.Provider, ImageLoaderFactory {
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin
|
||||
package com.nomadics9.ananas
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
|
@ -9,7 +9,7 @@ import androidx.core.view.WindowInsetsCompat
|
|||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.media3.session.MediaSession
|
||||
import dev.jdtech.jellyfin.viewmodels.PlayerActivityViewModel
|
||||
import com.nomadics9.ananas.viewmodels.PlayerActivityViewModel
|
||||
|
||||
abstract class BasePlayerActivity : AppCompatActivity() {
|
||||
|
|
@ -1,20 +1,20 @@
|
|||
package dev.jdtech.jellyfin
|
||||
package com.nomadics9.ananas
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import androidx.annotation.DrawableRes
|
||||
import coil.load
|
||||
import dev.jdtech.jellyfin.api.JellyfinApi
|
||||
import dev.jdtech.jellyfin.models.FindroidEpisode
|
||||
import dev.jdtech.jellyfin.models.FindroidItem
|
||||
import dev.jdtech.jellyfin.models.FindroidMovie
|
||||
import dev.jdtech.jellyfin.models.User
|
||||
import com.nomadics9.ananas.api.JellyfinApi
|
||||
import com.nomadics9.ananas.models.FindroidEpisode
|
||||
import com.nomadics9.ananas.models.FindroidItem
|
||||
import com.nomadics9.ananas.models.FindroidMovie
|
||||
import com.nomadics9.ananas.models.User
|
||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||
import org.jellyfin.sdk.model.api.BaseItemPerson
|
||||
import org.jellyfin.sdk.model.api.ImageType
|
||||
import java.util.UUID
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
fun bindItemImage(imageView: ImageView, item: BaseItemDto) {
|
||||
val itemId =
|
|
@ -1,12 +1,10 @@
|
|||
package dev.jdtech.jellyfin
|
||||
package com.nomadics9.ananas
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavGraph
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
|
@ -21,12 +19,16 @@ import androidx.work.OneTimeWorkRequestBuilder
|
|||
import androidx.work.WorkManager
|
||||
import com.google.android.material.navigation.NavigationBarView
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.database.ServerDatabaseDao
|
||||
import dev.jdtech.jellyfin.databinding.ActivityMainBinding
|
||||
import dev.jdtech.jellyfin.viewmodels.MainViewModel
|
||||
import dev.jdtech.jellyfin.work.SyncWorker
|
||||
import com.nomadics9.ananas.database.ServerDatabaseDao
|
||||
import com.nomadics9.ananas.databinding.ActivityMainBinding
|
||||
import com.nomadics9.ananas.viewmodels.MainViewModel
|
||||
import com.nomadics9.ananas.work.SyncWorker
|
||||
import com.nomadics9.ananas.repository.JellyfinRepository
|
||||
import com.nomadics9.ananas.utils.restart
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
@ -38,6 +40,9 @@ class MainActivity : AppCompatActivity() {
|
|||
@Inject
|
||||
lateinit var database: ServerDatabaseDao
|
||||
|
||||
@Inject
|
||||
lateinit var jellyfinRepository: JellyfinRepository
|
||||
|
||||
@Inject
|
||||
lateinit var appPreferences: AppPreferences
|
||||
|
||||
|
@ -48,21 +53,6 @@ class MainActivity : AppCompatActivity() {
|
|||
scheduleUserDataSync()
|
||||
applyTheme()
|
||||
setupActivity()
|
||||
|
||||
// Temp fix insets because SDK 35 enables edge to edge by default. This will probably be removed once we move to compose
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets ->
|
||||
val bars = insets.getInsets(
|
||||
WindowInsetsCompat.Type.systemBars()
|
||||
or WindowInsetsCompat.Type.displayCutout(),
|
||||
)
|
||||
v.updatePadding(
|
||||
left = bars.left,
|
||||
top = bars.top,
|
||||
right = bars.right,
|
||||
bottom = bars.bottom,
|
||||
)
|
||||
WindowInsetsCompat.CONSUMED
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(NavigationUiSaveStateControl::class)
|
||||
|
@ -86,10 +76,18 @@ class MainActivity : AppCompatActivity() {
|
|||
val navView: NavigationBarView = binding.navView as NavigationBarView
|
||||
|
||||
if (appPreferences.offlineMode) {
|
||||
appPreferences.isOffline = true
|
||||
}
|
||||
|
||||
if (appPreferences.isOffline) {
|
||||
navView.menu.clear()
|
||||
navView.inflateMenu(CoreR.menu.bottom_nav_menu_offline)
|
||||
}
|
||||
|
||||
if (!appPreferences.isOffline && appPreferences.autoOffline) {
|
||||
testServerConnection()
|
||||
}
|
||||
|
||||
setSupportActionBar(binding.mainToolbar)
|
||||
|
||||
// Passing each menu ID as a set of Ids because each
|
||||
|
@ -110,7 +108,7 @@ class MainActivity : AppCompatActivity() {
|
|||
|
||||
navController.addOnDestinationChangedListener { _, destination, _ ->
|
||||
binding.navView.visibility = when (destination.id) {
|
||||
R.id.twoPaneSettingsFragment, R.id.serverSelectFragment, R.id.addServerFragment, R.id.loginFragment, com.mikepenz.aboutlibraries.R.id.about_libraries_dest, R.id.usersFragment, R.id.serverAddressesFragment -> View.GONE
|
||||
R.id.twoPaneSettingsFragment, R.id.serverSelectFragment, R.id.addServerFragment, R.id.loginFragment, com.mikepenz.aboutlibraries.R.id.about_libraries_dest, R.id.usersFragment, R.id.serverAddressesFragment, R.id.requestsWebFragment -> View.GONE
|
||||
else -> View.VISIBLE
|
||||
}
|
||||
if (destination.id == com.mikepenz.aboutlibraries.R.id.about_libraries_dest) {
|
||||
|
@ -170,4 +168,18 @@ class MainActivity : AppCompatActivity() {
|
|||
setTheme(CoreR.style.ThemeOverlay_Findroid_Amoled)
|
||||
}
|
||||
}
|
||||
|
||||
private fun testServerConnection() {
|
||||
val activity = this
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
jellyfinRepository.getPublicSystemInfo()
|
||||
// Give the UI a chance to load
|
||||
delay(100)
|
||||
} catch (e: Exception) {
|
||||
appPreferences.isOffline = true
|
||||
activity.restart()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
package dev.jdtech.jellyfin
|
||||
package com.nomadics9.ananas
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.AppOpsManager
|
||||
import android.app.PictureInPictureParams
|
||||
import android.content.Context
|
||||
|
@ -35,25 +34,25 @@ import androidx.media3.ui.PlayerControlView
|
|||
import androidx.media3.ui.PlayerView
|
||||
import androidx.navigation.navArgs
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.nomadics9.ananas.databinding.ActivityPlayerBinding
|
||||
import com.nomadics9.ananas.dialogs.SpeedSelectionDialogFragment
|
||||
import com.nomadics9.ananas.dialogs.TrackSelectionDialogFragment
|
||||
import com.nomadics9.ananas.models.FindroidSegment
|
||||
import com.nomadics9.ananas.utils.PlayerGestureHelper
|
||||
import com.nomadics9.ananas.utils.PreviewScrubListener
|
||||
import com.nomadics9.ananas.viewmodels.PlayerActivityViewModel
|
||||
import com.nomadics9.ananas.viewmodels.PlayerEvents
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.databinding.ActivityPlayerBinding
|
||||
import dev.jdtech.jellyfin.dialogs.SpeedSelectionDialogFragment
|
||||
import dev.jdtech.jellyfin.dialogs.TrackSelectionDialogFragment
|
||||
import dev.jdtech.jellyfin.models.VideoQuality
|
||||
import dev.jdtech.jellyfin.utils.PlayerGestureHelper
|
||||
import dev.jdtech.jellyfin.utils.PreviewScrubListener
|
||||
import dev.jdtech.jellyfin.viewmodels.PlayerActivityViewModel
|
||||
import dev.jdtech.jellyfin.viewmodels.PlayerEvents
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
import com.nomadics9.ananas.models.VideoQuality
|
||||
|
||||
var isControlsLocked: Boolean = false
|
||||
|
||||
@AndroidEntryPoint
|
||||
class PlayerActivity : BasePlayerActivity() {
|
||||
|
||||
@Inject
|
||||
lateinit var appPreferences: AppPreferences
|
||||
|
||||
|
@ -62,6 +61,8 @@ class PlayerActivity : BasePlayerActivity() {
|
|||
override val viewModel: PlayerActivityViewModel by viewModels()
|
||||
private var previewScrubListener: PreviewScrubListener? = null
|
||||
private var wasZoom: Boolean = false
|
||||
private var oldSegment: FindroidSegment? = null
|
||||
private var buttonPressed: Boolean = false
|
||||
|
||||
private val isPipSupported by lazy {
|
||||
// Check if device has PiP feature
|
||||
|
@ -110,12 +111,13 @@ class PlayerActivity : BasePlayerActivity() {
|
|||
configureInsets(lockedControls)
|
||||
|
||||
if (appPreferences.playerGestures) {
|
||||
playerGestureHelper = PlayerGestureHelper(
|
||||
appPreferences,
|
||||
this,
|
||||
binding.playerView,
|
||||
getSystemService(Context.AUDIO_SERVICE) as AudioManager,
|
||||
)
|
||||
playerGestureHelper =
|
||||
PlayerGestureHelper(
|
||||
appPreferences,
|
||||
this,
|
||||
binding.playerView,
|
||||
getSystemService(AUDIO_SERVICE) as AudioManager,
|
||||
)
|
||||
}
|
||||
|
||||
binding.playerView.findViewById<View>(R.id.back_button).setOnClickListener {
|
||||
|
@ -127,7 +129,8 @@ class PlayerActivity : BasePlayerActivity() {
|
|||
val audioButton = binding.playerView.findViewById<ImageButton>(R.id.btn_audio_track)
|
||||
val subtitleButton = binding.playerView.findViewById<ImageButton>(R.id.btn_subtitle)
|
||||
val speedButton = binding.playerView.findViewById<ImageButton>(R.id.btn_speed)
|
||||
val skipIntroButton = binding.playerView.findViewById<Button>(R.id.btn_skip_intro)
|
||||
val skipButton = binding.playerView.findViewById<Button>(R.id.btn_skip_intro)
|
||||
val watchCreditsButton = binding.playerView.findViewById<Button>(R.id.btn_watch_credits)
|
||||
val pipButton = binding.playerView.findViewById<ImageButton>(R.id.btn_pip)
|
||||
val lockButton = binding.playerView.findViewById<ImageButton>(R.id.btn_lockview)
|
||||
val unlockButton = binding.playerView.findViewById<ImageButton>(R.id.btn_unlock)
|
||||
|
@ -141,19 +144,101 @@ class PlayerActivity : BasePlayerActivity() {
|
|||
// Title
|
||||
videoNameTextView.text = currentItemTitle
|
||||
|
||||
// Skip Intro button
|
||||
skipIntroButton.isVisible = !isInPictureInPictureMode && currentIntro != null
|
||||
skipIntroButton.setOnClickListener {
|
||||
currentIntro?.let {
|
||||
binding.playerView.player?.seekTo((it.introEnd * 1000).toLong())
|
||||
// Skip Button
|
||||
if (currentSegment != oldSegment) buttonPressed = false
|
||||
// Button Visibility and Text
|
||||
when (currentSegment?.type) {
|
||||
"intro" -> {
|
||||
skipButton.text =
|
||||
getString(CoreR.string.skip_intro_button)
|
||||
skipButton.isVisible =
|
||||
!isInPictureInPictureMode &&
|
||||
!buttonPressed &&
|
||||
(
|
||||
showSkip == true ||
|
||||
(binding.playerView.isControllerFullyVisible && currentSegment?.skip == true)
|
||||
)
|
||||
watchCreditsButton.isVisible = false
|
||||
}
|
||||
|
||||
"credit" -> {
|
||||
skipButton.text =
|
||||
if (binding.playerView.player?.hasNextMediaItem() == true) {
|
||||
getString(CoreR.string.skip_credit_button)
|
||||
} else {
|
||||
getString(CoreR.string.skip_credit_button_last)
|
||||
}
|
||||
skipButton.isVisible =
|
||||
!isInPictureInPictureMode &&
|
||||
!buttonPressed &&
|
||||
currentSegment?.skip == true &&
|
||||
!binding.playerView.isControllerFullyVisible
|
||||
watchCreditsButton.isVisible = skipButton.isVisible
|
||||
}
|
||||
|
||||
else -> {
|
||||
skipButton.isVisible = false
|
||||
watchCreditsButton.isVisible = false
|
||||
}
|
||||
}
|
||||
binding.playerView.setControllerVisibilityListener(
|
||||
PlayerView.ControllerVisibilityListener { visibility ->
|
||||
when (currentSegment?.type) {
|
||||
"intro" -> {
|
||||
skipButton.isVisible =
|
||||
!buttonPressed &&
|
||||
(showSkip == true || (visibility == View.VISIBLE && currentSegment?.skip == true))
|
||||
}
|
||||
|
||||
"credit" -> {
|
||||
skipButton.isVisible =
|
||||
!buttonPressed &&
|
||||
currentSegment?.skip == true &&
|
||||
visibility == View.GONE
|
||||
watchCreditsButton.isVisible = skipButton.isVisible
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
// onClick
|
||||
if (currentSegment?.type == "credit") {
|
||||
watchCreditsButton.setOnClickListener {
|
||||
buttonPressed = true
|
||||
skipButton.isVisible = false
|
||||
watchCreditsButton.isVisible = false
|
||||
}
|
||||
}
|
||||
skipButton.setOnClickListener {
|
||||
when (currentSegment?.type) {
|
||||
"intro" -> {
|
||||
currentSegment?.let {
|
||||
binding.playerView.player?.seekTo((it.endTime * 1000).toLong())
|
||||
}
|
||||
}
|
||||
|
||||
"credit" -> {
|
||||
if (binding.playerView.player?.hasNextMediaItem() == true) {
|
||||
binding.playerView.player?.seekToNext()
|
||||
} else {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
buttonPressed = true
|
||||
skipButton.isVisible = false
|
||||
watchCreditsButton.isVisible = false
|
||||
}
|
||||
oldSegment = currentSegment
|
||||
|
||||
// Trickplay
|
||||
previewScrubListener?.let {
|
||||
it.currentTrickplay = currentTrickplay
|
||||
}
|
||||
|
||||
playerGestureHelper?.let {
|
||||
it.currentTrickplay = currentTrickplay
|
||||
}
|
||||
|
||||
// Chapters
|
||||
if (appPreferences.showChapterMarkers && currentChapters != null) {
|
||||
currentChapters?.let { chapters ->
|
||||
|
@ -191,7 +276,8 @@ class PlayerActivity : BasePlayerActivity() {
|
|||
if (appPreferences.playerPipGesture) {
|
||||
try {
|
||||
setPictureInPictureParams(pipParams(event.isPlaying))
|
||||
} catch (_: IllegalArgumentException) { }
|
||||
} catch (_: IllegalArgumentException) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -290,7 +376,6 @@ class PlayerActivity : BasePlayerActivity() {
|
|||
viewModel.initializePlayer(args.items)
|
||||
}
|
||||
|
||||
@SuppressLint("MissingSuperCall")
|
||||
override fun onUserLeaveHint() {
|
||||
super.onUserLeaveHint()
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S &&
|
||||
|
@ -305,34 +390,38 @@ class PlayerActivity : BasePlayerActivity() {
|
|||
private fun pipParams(enableAutoEnter: Boolean = viewModel.player.isPlaying): PictureInPictureParams {
|
||||
val displayAspectRatio = Rational(binding.playerView.width, binding.playerView.height)
|
||||
|
||||
val aspectRatio = binding.playerView.player?.videoSize?.let {
|
||||
Rational(
|
||||
it.width.coerceAtMost((it.height * 2.39f).toInt()),
|
||||
it.height.coerceAtMost((it.width * 2.39f).toInt()),
|
||||
)
|
||||
}
|
||||
val aspectRatio =
|
||||
binding.playerView.player?.videoSize?.let {
|
||||
Rational(
|
||||
it.width.coerceAtMost((it.height * 2.39f).toInt()),
|
||||
it.height.coerceAtMost((it.width * 2.39f).toInt()),
|
||||
)
|
||||
}
|
||||
|
||||
val sourceRectHint = if (displayAspectRatio < aspectRatio!!) {
|
||||
val space = ((binding.playerView.height - (binding.playerView.width.toFloat() / aspectRatio.toFloat())) / 2).toInt()
|
||||
Rect(
|
||||
0,
|
||||
space,
|
||||
binding.playerView.width,
|
||||
(binding.playerView.width.toFloat() / aspectRatio.toFloat()).toInt() + space,
|
||||
)
|
||||
} else {
|
||||
val space = ((binding.playerView.width - (binding.playerView.height.toFloat() * aspectRatio.toFloat())) / 2).toInt()
|
||||
Rect(
|
||||
space,
|
||||
0,
|
||||
(binding.playerView.height.toFloat() * aspectRatio.toFloat()).toInt() + space,
|
||||
binding.playerView.height,
|
||||
)
|
||||
}
|
||||
val sourceRectHint =
|
||||
if (displayAspectRatio < aspectRatio!!) {
|
||||
val space = ((binding.playerView.height - (binding.playerView.width.toFloat() / aspectRatio.toFloat())) / 2).toInt()
|
||||
Rect(
|
||||
0,
|
||||
space,
|
||||
binding.playerView.width,
|
||||
(binding.playerView.width.toFloat() / aspectRatio.toFloat()).toInt() + space,
|
||||
)
|
||||
} else {
|
||||
val space = ((binding.playerView.width - (binding.playerView.height.toFloat() * aspectRatio.toFloat())) / 2).toInt()
|
||||
Rect(
|
||||
space,
|
||||
0,
|
||||
(binding.playerView.height.toFloat() * aspectRatio.toFloat()).toInt() + space,
|
||||
binding.playerView.height,
|
||||
)
|
||||
}
|
||||
|
||||
val builder = PictureInPictureParams.Builder()
|
||||
.setAspectRatio(aspectRatio)
|
||||
.setSourceRectHint(sourceRectHint)
|
||||
val builder =
|
||||
PictureInPictureParams
|
||||
.Builder()
|
||||
.setAspectRatio(aspectRatio)
|
||||
.setSourceRectHint(sourceRectHint)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
builder.setAutoEnterEnabled(enableAutoEnter)
|
||||
|
@ -390,25 +479,29 @@ class PlayerActivity : BasePlayerActivity() {
|
|||
playerGestureHelper?.updateZoomMode(false)
|
||||
|
||||
// Brightness mode Auto
|
||||
window.attributes = window.attributes.apply {
|
||||
screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
|
||||
}
|
||||
window.attributes =
|
||||
window.attributes.apply {
|
||||
screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
|
||||
}
|
||||
}
|
||||
false -> {
|
||||
binding.playerView.useController = true
|
||||
playerGestureHelper?.updateZoomMode(wasZoom)
|
||||
|
||||
// Override auto brightness
|
||||
window.attributes = window.attributes.apply {
|
||||
screenBrightness = if (appPreferences.playerBrightnessRemember) {
|
||||
appPreferences.playerBrightness
|
||||
} else {
|
||||
Settings.System.getInt(
|
||||
contentResolver,
|
||||
Settings.System.SCREEN_BRIGHTNESS,
|
||||
).toFloat() / 255
|
||||
window.attributes =
|
||||
window.attributes.apply {
|
||||
screenBrightness =
|
||||
if (appPreferences.playerBrightnessRemember) {
|
||||
appPreferences.playerBrightness
|
||||
} else {
|
||||
Settings.System
|
||||
.getInt(
|
||||
contentResolver,
|
||||
Settings.System.SCREEN_BRIGHTNESS,
|
||||
).toFloat() / 255
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
package dev.jdtech.jellyfin.adapters
|
||||
package com.nomadics9.ananas.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dev.jdtech.jellyfin.bindCardItemImage
|
||||
import dev.jdtech.jellyfin.databinding.CollectionItemBinding
|
||||
import dev.jdtech.jellyfin.models.FindroidCollection
|
||||
import com.nomadics9.ananas.bindCardItemImage
|
||||
import com.nomadics9.ananas.databinding.CollectionItemBinding
|
||||
import com.nomadics9.ananas.models.FindroidCollection
|
||||
|
||||
class CollectionListAdapter(
|
||||
private val onClickListener: (collection: FindroidCollection) -> Unit,
|
||||
|
@ -47,4 +47,4 @@ class CollectionListAdapter(
|
|||
}
|
||||
holder.bind(collection)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
package dev.jdtech.jellyfin.adapters
|
||||
package com.nomadics9.ananas.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dev.jdtech.jellyfin.databinding.DiscoveredServerItemBinding
|
||||
import dev.jdtech.jellyfin.models.DiscoveredServer
|
||||
import com.nomadics9.ananas.databinding.DiscoveredServerItemBinding
|
||||
import com.nomadics9.ananas.models.DiscoveredServer
|
||||
|
||||
class DiscoveredServerListAdapter(
|
||||
private val clickListener: (server: DiscoveredServer) -> Unit,
|
||||
|
@ -55,4 +55,4 @@ class DiscoveredServerListAdapter(
|
|||
holder.itemView.setOnClickListener { clickListener(server) }
|
||||
holder.bind(server)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.adapters
|
||||
package com.nomadics9.ananas.adapters
|
||||
|
||||
import android.text.Html.fromHtml
|
||||
import android.util.TypedValue
|
||||
|
@ -9,15 +9,15 @@ import androidx.core.view.isVisible
|
|||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dev.jdtech.jellyfin.bindCardItemImage
|
||||
import dev.jdtech.jellyfin.bindItemBackdropById
|
||||
import dev.jdtech.jellyfin.bindSeasonPoster
|
||||
import dev.jdtech.jellyfin.databinding.EpisodeItemBinding
|
||||
import dev.jdtech.jellyfin.databinding.SeasonHeaderBinding
|
||||
import dev.jdtech.jellyfin.models.EpisodeItem
|
||||
import dev.jdtech.jellyfin.models.FindroidEpisode
|
||||
import dev.jdtech.jellyfin.models.isDownloaded
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.bindCardItemImage
|
||||
import com.nomadics9.ananas.bindItemBackdropById
|
||||
import com.nomadics9.ananas.bindSeasonPoster
|
||||
import com.nomadics9.ananas.databinding.EpisodeItemBinding
|
||||
import com.nomadics9.ananas.databinding.SeasonHeaderBinding
|
||||
import com.nomadics9.ananas.models.EpisodeItem
|
||||
import com.nomadics9.ananas.models.FindroidEpisode
|
||||
import com.nomadics9.ananas.models.isDownloaded
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
private const val ITEM_VIEW_TYPE_HEADER = 0
|
||||
private const val ITEM_VIEW_TYPE_EPISODE = 1
|
||||
|
@ -123,4 +123,4 @@ class EpisodeListAdapter(
|
|||
is EpisodeItem.Episode -> ITEM_VIEW_TYPE_EPISODE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +1,14 @@
|
|||
package dev.jdtech.jellyfin.adapters
|
||||
package com.nomadics9.ananas.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dev.jdtech.jellyfin.Constants
|
||||
import dev.jdtech.jellyfin.databinding.FavoriteSectionBinding
|
||||
import dev.jdtech.jellyfin.models.FavoriteSection
|
||||
import dev.jdtech.jellyfin.models.FindroidItem
|
||||
import com.nomadics9.ananas.Constants
|
||||
import com.nomadics9.ananas.databinding.FavoriteSectionBinding
|
||||
import com.nomadics9.ananas.models.FavoriteSection
|
||||
import com.nomadics9.ananas.models.FindroidItem
|
||||
|
||||
class FavoritesListAdapter(
|
||||
private val onItemClickListener: (item: FindroidItem) -> Unit,
|
||||
|
@ -59,4 +59,4 @@ class FavoritesListAdapter(
|
|||
val collection = getItem(position)
|
||||
holder.bind(collection, onItemClickListener)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.adapters
|
||||
package com.nomadics9.ananas.adapters
|
||||
|
||||
import android.util.TypedValue
|
||||
import android.view.LayoutInflater
|
||||
|
@ -8,13 +8,13 @@ import androidx.core.view.isVisible
|
|||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dev.jdtech.jellyfin.bindCardItemImage
|
||||
import dev.jdtech.jellyfin.databinding.HomeEpisodeItemBinding
|
||||
import dev.jdtech.jellyfin.models.FindroidEpisode
|
||||
import dev.jdtech.jellyfin.models.FindroidItem
|
||||
import dev.jdtech.jellyfin.models.FindroidMovie
|
||||
import dev.jdtech.jellyfin.models.isDownloaded
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.bindCardItemImage
|
||||
import com.nomadics9.ananas.databinding.HomeEpisodeItemBinding
|
||||
import com.nomadics9.ananas.models.FindroidEpisode
|
||||
import com.nomadics9.ananas.models.FindroidItem
|
||||
import com.nomadics9.ananas.models.FindroidMovie
|
||||
import com.nomadics9.ananas.models.isDownloaded
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
class HomeEpisodeListAdapter(private val onClickListener: (item: FindroidItem) -> Unit) : ListAdapter<FindroidItem, HomeEpisodeListAdapter.EpisodeViewHolder>(DiffCallback) {
|
||||
class EpisodeViewHolder(
|
||||
|
@ -81,4 +81,4 @@ class HomeEpisodeListAdapter(private val onClickListener: (item: FindroidItem) -
|
|||
}
|
||||
holder.bind(item)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
package dev.jdtech.jellyfin.adapters
|
||||
package com.nomadics9.ananas.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dev.jdtech.jellyfin.bindPersonImage
|
||||
import dev.jdtech.jellyfin.databinding.PersonItemBinding
|
||||
import com.nomadics9.ananas.bindPersonImage
|
||||
import com.nomadics9.ananas.databinding.PersonItemBinding
|
||||
import org.jellyfin.sdk.model.api.BaseItemPerson
|
||||
|
||||
class PersonListAdapter(private val clickListener: (item: BaseItemPerson) -> Unit) : ListAdapter<BaseItemPerson, PersonListAdapter.PersonViewHolder>(DiffCallback) {
|
||||
|
@ -45,4 +45,4 @@ class PersonListAdapter(private val clickListener: (item: BaseItemPerson) -> Uni
|
|||
holder.bind(item)
|
||||
holder.itemView.setOnClickListener { clickListener(item) }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
package dev.jdtech.jellyfin.adapters
|
||||
package com.nomadics9.ananas.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dev.jdtech.jellyfin.databinding.ServerAddressListItemBinding
|
||||
import dev.jdtech.jellyfin.models.ServerAddress
|
||||
import com.nomadics9.ananas.databinding.ServerAddressListItemBinding
|
||||
import com.nomadics9.ananas.models.ServerAddress
|
||||
|
||||
class ServerAddressAdapter(
|
||||
private val clickListener: (address: ServerAddress) -> Unit,
|
||||
|
@ -48,4 +48,4 @@ class ServerAddressAdapter(
|
|||
holder.itemView.setOnLongClickListener { longClickListener(address) }
|
||||
holder.bind(address)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
package dev.jdtech.jellyfin.adapters
|
||||
package com.nomadics9.ananas.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dev.jdtech.jellyfin.databinding.ServerItemBinding
|
||||
import dev.jdtech.jellyfin.models.Server
|
||||
import com.nomadics9.ananas.databinding.ServerItemBinding
|
||||
import com.nomadics9.ananas.models.Server
|
||||
|
||||
class ServerGridAdapter(
|
||||
private val onClickListener: (server: Server) -> Unit,
|
||||
|
@ -46,4 +46,4 @@ class ServerGridAdapter(
|
|||
}
|
||||
holder.bind(server)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
package dev.jdtech.jellyfin.adapters
|
||||
package com.nomadics9.ananas.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dev.jdtech.jellyfin.bindUserImage
|
||||
import dev.jdtech.jellyfin.databinding.UserListItemBinding
|
||||
import dev.jdtech.jellyfin.models.User
|
||||
import com.nomadics9.ananas.bindUserImage
|
||||
import com.nomadics9.ananas.databinding.UserListItemBinding
|
||||
import com.nomadics9.ananas.models.User
|
||||
|
||||
class UserListAdapter(
|
||||
private val clickListener: (user: User) -> Unit,
|
||||
|
@ -50,4 +50,4 @@ class UserListAdapter(
|
|||
holder.itemView.setOnLongClickListener { longClickListener(user) }
|
||||
holder.bind(user)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
package dev.jdtech.jellyfin.adapters
|
||||
package com.nomadics9.ananas.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dev.jdtech.jellyfin.bindUserImage
|
||||
import dev.jdtech.jellyfin.databinding.UserItemBinding
|
||||
import dev.jdtech.jellyfin.models.User
|
||||
import com.nomadics9.ananas.bindUserImage
|
||||
import com.nomadics9.ananas.databinding.UserItemBinding
|
||||
import com.nomadics9.ananas.models.User
|
||||
|
||||
class UserLoginListAdapter(
|
||||
private val clickListener: (user: User) -> Unit,
|
||||
|
@ -48,4 +48,4 @@ class UserLoginListAdapter(
|
|||
holder.itemView.setOnClickListener { clickListener(user) }
|
||||
holder.bind(user)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.adapters
|
||||
package com.nomadics9.ananas.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
|
@ -7,12 +7,12 @@ import androidx.core.view.isVisible
|
|||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dev.jdtech.jellyfin.bindItemImage
|
||||
import dev.jdtech.jellyfin.databinding.BaseItemBinding
|
||||
import dev.jdtech.jellyfin.models.FindroidEpisode
|
||||
import dev.jdtech.jellyfin.models.FindroidItem
|
||||
import dev.jdtech.jellyfin.models.isDownloaded
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.bindItemImage
|
||||
import com.nomadics9.ananas.databinding.BaseItemBinding
|
||||
import com.nomadics9.ananas.models.FindroidEpisode
|
||||
import com.nomadics9.ananas.models.FindroidItem
|
||||
import com.nomadics9.ananas.models.isDownloaded
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
class ViewItemListAdapter(
|
||||
private val onClickListener: (item: FindroidItem) -> Unit,
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.adapters
|
||||
package com.nomadics9.ananas.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
|
@ -7,12 +7,12 @@ import androidx.core.view.isVisible
|
|||
import androidx.paging.PagingDataAdapter
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dev.jdtech.jellyfin.bindItemImage
|
||||
import dev.jdtech.jellyfin.databinding.BaseItemBinding
|
||||
import dev.jdtech.jellyfin.models.FindroidEpisode
|
||||
import dev.jdtech.jellyfin.models.FindroidItem
|
||||
import dev.jdtech.jellyfin.models.isDownloaded
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.bindItemImage
|
||||
import com.nomadics9.ananas.databinding.BaseItemBinding
|
||||
import com.nomadics9.ananas.models.FindroidEpisode
|
||||
import com.nomadics9.ananas.models.FindroidItem
|
||||
import com.nomadics9.ananas.models.isDownloaded
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
class ViewItemPagingAdapter(
|
||||
private val onClickListener: (item: FindroidItem) -> Unit,
|
||||
|
@ -70,4 +70,4 @@ class ViewItemPagingAdapter(
|
|||
holder.bind(item, fixedWidth)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +1,17 @@
|
|||
package dev.jdtech.jellyfin.adapters
|
||||
package com.nomadics9.ananas.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dev.jdtech.jellyfin.databinding.CardOfflineBinding
|
||||
import dev.jdtech.jellyfin.databinding.NextUpSectionBinding
|
||||
import dev.jdtech.jellyfin.databinding.ViewItemBinding
|
||||
import dev.jdtech.jellyfin.models.FindroidItem
|
||||
import dev.jdtech.jellyfin.models.HomeItem
|
||||
import dev.jdtech.jellyfin.models.View
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.databinding.CardOfflineBinding
|
||||
import com.nomadics9.ananas.databinding.NextUpSectionBinding
|
||||
import com.nomadics9.ananas.databinding.ViewItemBinding
|
||||
import com.nomadics9.ananas.models.FindroidItem
|
||||
import com.nomadics9.ananas.models.HomeItem
|
||||
import com.nomadics9.ananas.models.View
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
private const val ITEM_VIEW_TYPE_NEXT_UP = 0
|
||||
private const val ITEM_VIEW_TYPE_VIEW = 1
|
||||
|
@ -125,4 +125,4 @@ class ViewListAdapter(
|
|||
is HomeItem.ViewItem -> ITEM_VIEW_TYPE_VIEW
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.di
|
||||
package com.nomadics9.ananas.di
|
||||
|
||||
import android.content.Context
|
||||
import dagger.Module
|
||||
|
@ -6,7 +6,7 @@ import dagger.Provides
|
|||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import dev.jdtech.jellyfin.BaseApplication
|
||||
import com.nomadics9.ananas.BaseApplication
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
|
@ -1,11 +1,11 @@
|
|||
package dev.jdtech.jellyfin.dialogs
|
||||
package com.nomadics9.ananas.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Environment
|
||||
import android.os.StatFs
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
fun getStorageSelectionDialog(
|
||||
context: Context,
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.method.LinkMovementMethod
|
||||
|
@ -14,11 +14,12 @@ import androidx.lifecycle.Lifecycle
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.nomadics9.ananas.BuildConfig
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.adapters.DiscoveredServerListAdapter
|
||||
import dev.jdtech.jellyfin.databinding.FragmentAddServerBinding
|
||||
import dev.jdtech.jellyfin.viewmodels.AddServerEvent
|
||||
import dev.jdtech.jellyfin.viewmodels.AddServerViewModel
|
||||
import com.nomadics9.ananas.adapters.DiscoveredServerListAdapter
|
||||
import com.nomadics9.ananas.databinding.FragmentAddServerBinding
|
||||
import com.nomadics9.ananas.viewmodels.AddServerEvent
|
||||
import com.nomadics9.ananas.viewmodels.AddServerViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
|
@ -89,7 +90,12 @@ class AddServerFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (BuildConfig.FLAVOR == "Ananas") {
|
||||
fun connectToServerDirectly(serverAddress: String = BuildConfig.DEFAULT_SERVER_ADDRESS) {
|
||||
viewModel.checkServer(serverAddress.removeSuffix("/"))
|
||||
}
|
||||
connectToServerDirectly()
|
||||
}
|
||||
return binding.root
|
||||
}
|
||||
|
||||
|
@ -134,6 +140,16 @@ class AddServerFragment : Fragment() {
|
|||
viewModel.checkServer(serverAddress.removeSuffix("/"))
|
||||
}
|
||||
|
||||
|
||||
// private fun connectToServer() {
|
||||
// val serverAddress = (binding.editTextServerAddress as AppCompatEditText).text.toString()
|
||||
// if (serverAddress.isNotBlank()) {
|
||||
// viewModel.checkServer(serverAddress.removeSuffix("/"))
|
||||
// } else {
|
||||
// viewModel.checkServer(BuildConfig.DEFAULT_SERVER_ADDRESS.removeSuffix("/"))
|
||||
// }
|
||||
// }
|
||||
|
||||
private fun navigateToLoginFragment() {
|
||||
findNavController().navigate(AddServerFragmentDirections.actionAddServerFragmentToLoginFragment())
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
|
@ -13,18 +13,18 @@ import androidx.lifecycle.repeatOnLifecycle
|
|||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.adapters.FavoritesListAdapter
|
||||
import dev.jdtech.jellyfin.databinding.FragmentFavoriteBinding
|
||||
import dev.jdtech.jellyfin.dialogs.ErrorDialogFragment
|
||||
import dev.jdtech.jellyfin.models.FindroidEpisode
|
||||
import dev.jdtech.jellyfin.models.FindroidItem
|
||||
import dev.jdtech.jellyfin.models.FindroidMovie
|
||||
import dev.jdtech.jellyfin.models.FindroidShow
|
||||
import dev.jdtech.jellyfin.utils.checkIfLoginRequired
|
||||
import dev.jdtech.jellyfin.viewmodels.CollectionViewModel
|
||||
import com.nomadics9.ananas.adapters.FavoritesListAdapter
|
||||
import com.nomadics9.ananas.databinding.FragmentFavoriteBinding
|
||||
import com.nomadics9.ananas.dialogs.ErrorDialogFragment
|
||||
import com.nomadics9.ananas.models.FindroidEpisode
|
||||
import com.nomadics9.ananas.models.FindroidItem
|
||||
import com.nomadics9.ananas.models.FindroidMovie
|
||||
import com.nomadics9.ananas.models.FindroidShow
|
||||
import com.nomadics9.ananas.utils.checkIfLoginRequired
|
||||
import com.nomadics9.ananas.viewmodels.CollectionViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
@AndroidEntryPoint
|
||||
class CollectionFragment : Fragment() {
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
|
@ -13,19 +13,19 @@ import androidx.lifecycle.repeatOnLifecycle
|
|||
import androidx.navigation.fragment.findNavController
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.AppPreferences
|
||||
import dev.jdtech.jellyfin.adapters.FavoritesListAdapter
|
||||
import dev.jdtech.jellyfin.databinding.FragmentDownloadsBinding
|
||||
import dev.jdtech.jellyfin.models.FindroidItem
|
||||
import dev.jdtech.jellyfin.models.FindroidMovie
|
||||
import dev.jdtech.jellyfin.models.FindroidShow
|
||||
import dev.jdtech.jellyfin.utils.restart
|
||||
import dev.jdtech.jellyfin.viewmodels.DownloadsEvent
|
||||
import dev.jdtech.jellyfin.viewmodels.DownloadsViewModel
|
||||
import com.nomadics9.ananas.AppPreferences
|
||||
import com.nomadics9.ananas.adapters.FavoritesListAdapter
|
||||
import com.nomadics9.ananas.databinding.FragmentDownloadsBinding
|
||||
import com.nomadics9.ananas.models.FindroidItem
|
||||
import com.nomadics9.ananas.models.FindroidMovie
|
||||
import com.nomadics9.ananas.models.FindroidShow
|
||||
import com.nomadics9.ananas.utils.restart
|
||||
import com.nomadics9.ananas.viewmodels.DownloadsEvent
|
||||
import com.nomadics9.ananas.viewmodels.DownloadsViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
@AndroidEntryPoint
|
||||
class DownloadsFragment : Fragment() {
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.app.DownloadManager
|
||||
import android.os.Bundle
|
||||
|
@ -21,23 +21,23 @@ import com.google.android.material.bottomsheet.BottomSheetDialog
|
|||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.AppPreferences
|
||||
import dev.jdtech.jellyfin.R
|
||||
import dev.jdtech.jellyfin.bindCardItemImage
|
||||
import dev.jdtech.jellyfin.databinding.EpisodeBottomSheetBinding
|
||||
import dev.jdtech.jellyfin.dialogs.ErrorDialogFragment
|
||||
import dev.jdtech.jellyfin.dialogs.getStorageSelectionDialog
|
||||
import dev.jdtech.jellyfin.dialogs.getVideoVersionDialog
|
||||
import dev.jdtech.jellyfin.models.FindroidSourceType
|
||||
import dev.jdtech.jellyfin.models.PlayerItem
|
||||
import dev.jdtech.jellyfin.models.UiText
|
||||
import dev.jdtech.jellyfin.models.isDownloaded
|
||||
import dev.jdtech.jellyfin.models.isDownloading
|
||||
import dev.jdtech.jellyfin.utils.setIconTintColorAttribute
|
||||
import dev.jdtech.jellyfin.viewmodels.EpisodeBottomSheetEvent
|
||||
import dev.jdtech.jellyfin.viewmodels.EpisodeBottomSheetViewModel
|
||||
import dev.jdtech.jellyfin.viewmodels.PlayerItemsEvent
|
||||
import dev.jdtech.jellyfin.viewmodels.PlayerViewModel
|
||||
import com.nomadics9.ananas.AppPreferences
|
||||
import com.nomadics9.ananas.R
|
||||
import com.nomadics9.ananas.bindCardItemImage
|
||||
import com.nomadics9.ananas.databinding.EpisodeBottomSheetBinding
|
||||
import com.nomadics9.ananas.dialogs.ErrorDialogFragment
|
||||
import com.nomadics9.ananas.dialogs.getStorageSelectionDialog
|
||||
import com.nomadics9.ananas.dialogs.getVideoVersionDialog
|
||||
import com.nomadics9.ananas.models.FindroidSourceType
|
||||
import com.nomadics9.ananas.models.PlayerItem
|
||||
import com.nomadics9.ananas.models.UiText
|
||||
import com.nomadics9.ananas.models.isDownloaded
|
||||
import com.nomadics9.ananas.models.isDownloading
|
||||
import com.nomadics9.ananas.utils.setIconTintColorAttribute
|
||||
import com.nomadics9.ananas.viewmodels.EpisodeBottomSheetEvent
|
||||
import com.nomadics9.ananas.viewmodels.EpisodeBottomSheetViewModel
|
||||
import com.nomadics9.ananas.viewmodels.PlayerItemsEvent
|
||||
import com.nomadics9.ananas.viewmodels.PlayerViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jellyfin.sdk.model.DateTime
|
||||
import timber.log.Timber
|
||||
|
@ -48,7 +48,7 @@ import java.util.UUID
|
|||
import javax.inject.Inject
|
||||
import android.R as AndroidR
|
||||
import com.google.android.material.R as MaterialR
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
@AndroidEntryPoint
|
||||
class EpisodeBottomSheetFragment : BottomSheetDialogFragment() {
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
|
@ -12,15 +12,15 @@ import androidx.lifecycle.lifecycleScope
|
|||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.adapters.FavoritesListAdapter
|
||||
import dev.jdtech.jellyfin.databinding.FragmentFavoriteBinding
|
||||
import dev.jdtech.jellyfin.dialogs.ErrorDialogFragment
|
||||
import dev.jdtech.jellyfin.models.FindroidEpisode
|
||||
import dev.jdtech.jellyfin.models.FindroidItem
|
||||
import dev.jdtech.jellyfin.models.FindroidMovie
|
||||
import dev.jdtech.jellyfin.models.FindroidShow
|
||||
import dev.jdtech.jellyfin.utils.checkIfLoginRequired
|
||||
import dev.jdtech.jellyfin.viewmodels.FavoriteViewModel
|
||||
import com.nomadics9.ananas.adapters.FavoritesListAdapter
|
||||
import com.nomadics9.ananas.databinding.FragmentFavoriteBinding
|
||||
import com.nomadics9.ananas.dialogs.ErrorDialogFragment
|
||||
import com.nomadics9.ananas.models.FindroidEpisode
|
||||
import com.nomadics9.ananas.models.FindroidItem
|
||||
import com.nomadics9.ananas.models.FindroidMovie
|
||||
import com.nomadics9.ananas.models.FindroidShow
|
||||
import com.nomadics9.ananas.utils.checkIfLoginRequired
|
||||
import com.nomadics9.ananas.viewmodels.FavoriteViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
|
@ -19,21 +19,21 @@ import androidx.lifecycle.lifecycleScope
|
|||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.AppPreferences
|
||||
import dev.jdtech.jellyfin.adapters.ViewListAdapter
|
||||
import dev.jdtech.jellyfin.databinding.FragmentHomeBinding
|
||||
import dev.jdtech.jellyfin.dialogs.ErrorDialogFragment
|
||||
import dev.jdtech.jellyfin.models.FindroidEpisode
|
||||
import dev.jdtech.jellyfin.models.FindroidItem
|
||||
import dev.jdtech.jellyfin.models.FindroidMovie
|
||||
import dev.jdtech.jellyfin.models.FindroidShow
|
||||
import dev.jdtech.jellyfin.utils.checkIfLoginRequired
|
||||
import dev.jdtech.jellyfin.utils.restart
|
||||
import dev.jdtech.jellyfin.viewmodels.HomeViewModel
|
||||
import com.nomadics9.ananas.AppPreferences
|
||||
import com.nomadics9.ananas.adapters.ViewListAdapter
|
||||
import com.nomadics9.ananas.databinding.FragmentHomeBinding
|
||||
import com.nomadics9.ananas.dialogs.ErrorDialogFragment
|
||||
import com.nomadics9.ananas.models.FindroidEpisode
|
||||
import com.nomadics9.ananas.models.FindroidItem
|
||||
import com.nomadics9.ananas.models.FindroidMovie
|
||||
import com.nomadics9.ananas.models.FindroidShow
|
||||
import com.nomadics9.ananas.utils.checkIfLoginRequired
|
||||
import com.nomadics9.ananas.utils.restart
|
||||
import com.nomadics9.ananas.viewmodels.HomeViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
@AndroidEntryPoint
|
||||
class HomeFragment : Fragment() {
|
||||
|
@ -74,6 +74,12 @@ class HomeFragment : Fragment() {
|
|||
val searchView = search.actionView as SearchView
|
||||
searchView.queryHint = getString(CoreR.string.search_hint)
|
||||
|
||||
val requests = menu.findItem(CoreR.id.action_requests)
|
||||
requests.setOnMenuItemClickListener{
|
||||
navigateToRequestsWebViewFragment()
|
||||
true
|
||||
}
|
||||
|
||||
search.setOnActionExpandListener(
|
||||
object : MenuItem.OnActionExpandListener {
|
||||
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
|
||||
|
@ -202,7 +208,7 @@ class HomeFragment : Fragment() {
|
|||
checkIfLoginRequired(uiState.error.message)
|
||||
}
|
||||
|
||||
private fun navigateToLibraryFragment(view: dev.jdtech.jellyfin.models.View) {
|
||||
private fun navigateToLibraryFragment(view: com.nomadics9.ananas.models.View) {
|
||||
findNavController().navigate(
|
||||
HomeFragmentDirections.actionNavigationHomeToLibraryFragment(
|
||||
libraryId = view.id,
|
||||
|
@ -251,4 +257,10 @@ class HomeFragment : Fragment() {
|
|||
HomeFragmentDirections.actionHomeFragmentToSearchResultFragment(query),
|
||||
)
|
||||
}
|
||||
|
||||
private fun navigateToRequestsWebViewFragment() {
|
||||
findNavController().navigate(
|
||||
HomeFragmentDirections.actionHomeFragmentToRequestsWebFragment()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
|
@ -19,24 +19,25 @@ import androidx.navigation.fragment.findNavController
|
|||
import androidx.navigation.fragment.navArgs
|
||||
import androidx.paging.LoadState
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.AppPreferences
|
||||
import dev.jdtech.jellyfin.adapters.ViewItemPagingAdapter
|
||||
import dev.jdtech.jellyfin.databinding.FragmentLibraryBinding
|
||||
import dev.jdtech.jellyfin.dialogs.ErrorDialogFragment
|
||||
import dev.jdtech.jellyfin.dialogs.SortDialogFragment
|
||||
import dev.jdtech.jellyfin.models.FindroidBoxSet
|
||||
import dev.jdtech.jellyfin.models.FindroidFolder
|
||||
import dev.jdtech.jellyfin.models.FindroidItem
|
||||
import dev.jdtech.jellyfin.models.FindroidMovie
|
||||
import dev.jdtech.jellyfin.models.FindroidShow
|
||||
import dev.jdtech.jellyfin.models.SortBy
|
||||
import dev.jdtech.jellyfin.utils.checkIfLoginRequired
|
||||
import dev.jdtech.jellyfin.viewmodels.LibraryViewModel
|
||||
import com.nomadics9.ananas.AppPreferences
|
||||
import com.nomadics9.ananas.adapters.ViewItemPagingAdapter
|
||||
import com.nomadics9.ananas.databinding.FragmentLibraryBinding
|
||||
import com.nomadics9.ananas.dialogs.ErrorDialogFragment
|
||||
import com.nomadics9.ananas.dialogs.SortDialogFragment
|
||||
import com.nomadics9.ananas.models.FindroidBoxSet
|
||||
import com.nomadics9.ananas.models.FindroidFolder
|
||||
import com.nomadics9.ananas.models.FindroidItem
|
||||
import com.nomadics9.ananas.models.FindroidMovie
|
||||
import com.nomadics9.ananas.models.FindroidShow
|
||||
import com.nomadics9.ananas.models.SortBy
|
||||
import com.nomadics9.ananas.utils.checkIfLoginRequired
|
||||
import com.nomadics9.ananas.viewmodels.LibraryViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jellyfin.sdk.model.api.SortOrder
|
||||
import java.lang.IllegalArgumentException
|
||||
import javax.inject.Inject
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
|
||||
@AndroidEntryPoint
|
||||
class LibraryFragment : Fragment() {
|
||||
|
@ -62,6 +63,11 @@ class LibraryFragment : Fragment() {
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
binding.itemsRecyclerView.layoutManager =
|
||||
GridLayoutManager(context, preferences.spanCount)
|
||||
|
||||
|
||||
|
||||
val menuHost: MenuHost = requireActivity()
|
||||
menuHost.addMenuProvider(
|
||||
object : MenuProvider {
|
|
@ -1,5 +1,7 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.text.Html.fromHtml
|
||||
import android.view.LayoutInflater
|
||||
|
@ -16,16 +18,18 @@ import androidx.lifecycle.repeatOnLifecycle
|
|||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.AppPreferences
|
||||
import dev.jdtech.jellyfin.adapters.UserLoginListAdapter
|
||||
import dev.jdtech.jellyfin.database.ServerDatabaseDao
|
||||
import dev.jdtech.jellyfin.databinding.FragmentLoginBinding
|
||||
import dev.jdtech.jellyfin.viewmodels.LoginEvent
|
||||
import dev.jdtech.jellyfin.viewmodels.LoginViewModel
|
||||
import com.nomadics9.ananas.AppPreferences
|
||||
import com.nomadics9.ananas.BuildConfig
|
||||
import com.nomadics9.ananas.adapters.UserLoginListAdapter
|
||||
import com.nomadics9.ananas.database.ServerDatabaseDao
|
||||
import com.nomadics9.ananas.databinding.FragmentLoginBinding
|
||||
import com.nomadics9.ananas.viewmodels.LoginEvent
|
||||
import com.nomadics9.ananas.viewmodels.LoginViewModel
|
||||
import io.noties.markwon.Markwon
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
@AndroidEntryPoint
|
||||
class LoginFragment : Fragment() {
|
||||
|
@ -78,6 +82,17 @@ class LoginFragment : Fragment() {
|
|||
(binding.editTextPassword as AppCompatEditText).requestFocus()
|
||||
}
|
||||
|
||||
|
||||
if (BuildConfig.FLAVOR == "Ananas") {
|
||||
binding.buttonForgetPassword.setOnClickListener {
|
||||
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(BuildConfig.FORGET_PASSWORD_ADDRESS))
|
||||
startActivity(browserIntent)
|
||||
}
|
||||
binding.buttonForgetPassword.isVisible = true
|
||||
} else {
|
||||
binding.buttonForgetPassword.isVisible = false
|
||||
}
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
viewModel.uiState.collect { uiState ->
|
||||
|
@ -143,7 +158,21 @@ class LoginFragment : Fragment() {
|
|||
binding.editTextPasswordLayout.isEnabled = true
|
||||
|
||||
uiState.disclaimer?.let { disclaimer ->
|
||||
binding.loginDisclaimer.text = fromHtml(disclaimer, 0)
|
||||
if (BuildConfig.FLAVOR == "Ananas") {
|
||||
val lines = disclaimer.lines()
|
||||
val lineToRemoveIndex = 3
|
||||
val filteredLines = lines.toMutableList().apply {
|
||||
if (size > lineToRemoveIndex) {
|
||||
removeAt(lineToRemoveIndex)
|
||||
}
|
||||
}
|
||||
val filteredDisclaimer = filteredLines.joinToString("\n")
|
||||
val markwon = Markwon.create(requireContext())
|
||||
markwon.setMarkdown(binding.loginDisclaimer, filteredDisclaimer)
|
||||
} else {
|
||||
val markwon = Markwon.create(requireContext())
|
||||
markwon.setMarkdown(binding.loginDisclaimer, disclaimer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
|
@ -19,15 +19,15 @@ import androidx.lifecycle.lifecycleScope
|
|||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.adapters.CollectionListAdapter
|
||||
import dev.jdtech.jellyfin.databinding.FragmentMediaBinding
|
||||
import dev.jdtech.jellyfin.dialogs.ErrorDialogFragment
|
||||
import dev.jdtech.jellyfin.models.FindroidCollection
|
||||
import dev.jdtech.jellyfin.utils.checkIfLoginRequired
|
||||
import dev.jdtech.jellyfin.viewmodels.MediaViewModel
|
||||
import com.nomadics9.ananas.adapters.CollectionListAdapter
|
||||
import com.nomadics9.ananas.databinding.FragmentMediaBinding
|
||||
import com.nomadics9.ananas.dialogs.ErrorDialogFragment
|
||||
import com.nomadics9.ananas.models.FindroidCollection
|
||||
import com.nomadics9.ananas.utils.checkIfLoginRequired
|
||||
import com.nomadics9.ananas.viewmodels.MediaViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MediaFragment : Fragment() {
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.app.DownloadManager
|
||||
import android.content.Intent
|
||||
|
@ -21,32 +21,32 @@ import androidx.navigation.fragment.findNavController
|
|||
import androidx.navigation.fragment.navArgs
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.AppPreferences
|
||||
import dev.jdtech.jellyfin.R
|
||||
import dev.jdtech.jellyfin.adapters.PersonListAdapter
|
||||
import dev.jdtech.jellyfin.bindItemBackdropImage
|
||||
import dev.jdtech.jellyfin.databinding.FragmentMovieBinding
|
||||
import dev.jdtech.jellyfin.dialogs.ErrorDialogFragment
|
||||
import dev.jdtech.jellyfin.dialogs.getStorageSelectionDialog
|
||||
import dev.jdtech.jellyfin.dialogs.getVideoVersionDialog
|
||||
import dev.jdtech.jellyfin.models.AudioCodec
|
||||
import dev.jdtech.jellyfin.models.DisplayProfile
|
||||
import dev.jdtech.jellyfin.models.FindroidSourceType
|
||||
import dev.jdtech.jellyfin.models.PlayerItem
|
||||
import dev.jdtech.jellyfin.models.UiText
|
||||
import dev.jdtech.jellyfin.models.isDownloaded
|
||||
import dev.jdtech.jellyfin.models.isDownloading
|
||||
import dev.jdtech.jellyfin.utils.checkIfLoginRequired
|
||||
import dev.jdtech.jellyfin.utils.setIconTintColorAttribute
|
||||
import dev.jdtech.jellyfin.viewmodels.MovieEvent
|
||||
import dev.jdtech.jellyfin.viewmodels.MovieViewModel
|
||||
import dev.jdtech.jellyfin.viewmodels.PlayerItemsEvent
|
||||
import dev.jdtech.jellyfin.viewmodels.PlayerViewModel
|
||||
import com.nomadics9.ananas.AppPreferences
|
||||
import com.nomadics9.ananas.R
|
||||
import com.nomadics9.ananas.adapters.PersonListAdapter
|
||||
import com.nomadics9.ananas.bindItemBackdropImage
|
||||
import com.nomadics9.ananas.databinding.FragmentMovieBinding
|
||||
import com.nomadics9.ananas.dialogs.ErrorDialogFragment
|
||||
import com.nomadics9.ananas.dialogs.getStorageSelectionDialog
|
||||
import com.nomadics9.ananas.dialogs.getVideoVersionDialog
|
||||
import com.nomadics9.ananas.models.AudioCodec
|
||||
import com.nomadics9.ananas.models.DisplayProfile
|
||||
import com.nomadics9.ananas.models.FindroidSourceType
|
||||
import com.nomadics9.ananas.models.PlayerItem
|
||||
import com.nomadics9.ananas.models.UiText
|
||||
import com.nomadics9.ananas.models.isDownloaded
|
||||
import com.nomadics9.ananas.models.isDownloading
|
||||
import com.nomadics9.ananas.utils.checkIfLoginRequired
|
||||
import com.nomadics9.ananas.utils.setIconTintColorAttribute
|
||||
import com.nomadics9.ananas.viewmodels.MovieEvent
|
||||
import com.nomadics9.ananas.viewmodels.MovieViewModel
|
||||
import com.nomadics9.ananas.viewmodels.PlayerItemsEvent
|
||||
import com.nomadics9.ananas.viewmodels.PlayerViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MovieFragment : Fragment() {
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
|
@ -15,18 +15,18 @@ import androidx.lifecycle.repeatOnLifecycle
|
|||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.adapters.ViewItemListAdapter
|
||||
import dev.jdtech.jellyfin.bindItemImage
|
||||
import dev.jdtech.jellyfin.databinding.FragmentPersonDetailBinding
|
||||
import dev.jdtech.jellyfin.dialogs.ErrorDialogFragment
|
||||
import dev.jdtech.jellyfin.models.FindroidItem
|
||||
import dev.jdtech.jellyfin.models.FindroidMovie
|
||||
import dev.jdtech.jellyfin.models.FindroidShow
|
||||
import dev.jdtech.jellyfin.utils.checkIfLoginRequired
|
||||
import dev.jdtech.jellyfin.viewmodels.PersonDetailViewModel
|
||||
import com.nomadics9.ananas.adapters.ViewItemListAdapter
|
||||
import com.nomadics9.ananas.bindItemImage
|
||||
import com.nomadics9.ananas.databinding.FragmentPersonDetailBinding
|
||||
import com.nomadics9.ananas.dialogs.ErrorDialogFragment
|
||||
import com.nomadics9.ananas.models.FindroidItem
|
||||
import com.nomadics9.ananas.models.FindroidMovie
|
||||
import com.nomadics9.ananas.models.FindroidShow
|
||||
import com.nomadics9.ananas.utils.checkIfLoginRequired
|
||||
import com.nomadics9.ananas.viewmodels.PersonDetailViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
@AndroidEntryPoint
|
||||
internal class PersonDetailFragment : Fragment() {
|
|
@ -0,0 +1,72 @@
|
|||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.webkit.WebSettings
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import android.widget.ProgressBar
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.nomadics9.ananas.BuildConfig
|
||||
import com.nomadics9.ananas.R
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@AndroidEntryPoint
|
||||
class RequestsWebViewFragment : Fragment() {
|
||||
private lateinit var webView: WebView
|
||||
private lateinit var progressBar: ProgressBar
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
val rootView = inflater.inflate(R.layout.fragment_webview, container, false)
|
||||
|
||||
webView = rootView.findViewById(R.id.webview)
|
||||
progressBar = rootView.findViewById(R.id.progressBar)
|
||||
|
||||
val webSettings: WebSettings = webView.settings
|
||||
webSettings.javaScriptEnabled = true // Enable JavaScript if required
|
||||
|
||||
// Set WebViewClient to handle loading URLs within the WebView
|
||||
webView.webViewClient = object : WebViewClient() {
|
||||
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
|
||||
// Return false to indicate that the WebView should load the URL
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Set up WebView client to handle page loading events
|
||||
webView.webViewClient = object : WebViewClient() {
|
||||
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
|
||||
super.onPageStarted(view, url, favicon)
|
||||
progressBar.visibility = View.VISIBLE // Show progress bar when page starts loading
|
||||
}
|
||||
|
||||
override fun onPageFinished(view: WebView?, url: String?) {
|
||||
super.onPageFinished(view, url)
|
||||
progressBar.visibility = View.GONE // Hide progress bar when page finishes loading
|
||||
}
|
||||
}
|
||||
|
||||
// Load your URL here
|
||||
webView.loadUrl(BuildConfig.REQUEST_SERVER_ADDRESS)
|
||||
|
||||
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
if (webView.canGoBack()) {
|
||||
webView.goBack()
|
||||
} else {
|
||||
isEnabled = false
|
||||
requireActivity().onBackPressed()
|
||||
}
|
||||
}
|
||||
})
|
||||
return rootView
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
|
@ -13,15 +13,15 @@ import androidx.lifecycle.repeatOnLifecycle
|
|||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.adapters.FavoritesListAdapter
|
||||
import dev.jdtech.jellyfin.databinding.FragmentSearchResultBinding
|
||||
import dev.jdtech.jellyfin.dialogs.ErrorDialogFragment
|
||||
import dev.jdtech.jellyfin.models.FindroidEpisode
|
||||
import dev.jdtech.jellyfin.models.FindroidItem
|
||||
import dev.jdtech.jellyfin.models.FindroidMovie
|
||||
import dev.jdtech.jellyfin.models.FindroidShow
|
||||
import dev.jdtech.jellyfin.utils.checkIfLoginRequired
|
||||
import dev.jdtech.jellyfin.viewmodels.SearchResultViewModel
|
||||
import com.nomadics9.ananas.adapters.FavoritesListAdapter
|
||||
import com.nomadics9.ananas.databinding.FragmentSearchResultBinding
|
||||
import com.nomadics9.ananas.dialogs.ErrorDialogFragment
|
||||
import com.nomadics9.ananas.models.FindroidEpisode
|
||||
import com.nomadics9.ananas.models.FindroidItem
|
||||
import com.nomadics9.ananas.models.FindroidMovie
|
||||
import com.nomadics9.ananas.models.FindroidShow
|
||||
import com.nomadics9.ananas.utils.checkIfLoginRequired
|
||||
import com.nomadics9.ananas.viewmodels.SearchResultViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
|
@ -0,0 +1,266 @@
|
|||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.MenuHost
|
||||
import androidx.core.view.MenuProvider
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import com.nomadics9.ananas.adapters.EpisodeListAdapter
|
||||
import com.nomadics9.ananas.databinding.FragmentSeasonBinding
|
||||
import com.nomadics9.ananas.dialogs.ErrorDialogFragment
|
||||
import com.nomadics9.ananas.dialogs.getStorageSelectionDialog
|
||||
import com.nomadics9.ananas.models.FindroidEpisode
|
||||
import com.nomadics9.ananas.utils.checkIfLoginRequired
|
||||
import com.nomadics9.ananas.viewmodels.SeasonEvent
|
||||
import com.nomadics9.ananas.viewmodels.SeasonViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.nomadics9.ananas.AppPreferences
|
||||
import com.nomadics9.ananas.models.UiText
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
@AndroidEntryPoint
|
||||
class SeasonFragment : Fragment() {
|
||||
|
||||
private lateinit var binding: FragmentSeasonBinding
|
||||
private val viewModel: SeasonViewModel by viewModels()
|
||||
private val args: SeasonFragmentArgs by navArgs()
|
||||
|
||||
private lateinit var errorDialog: ErrorDialogFragment
|
||||
private lateinit var downloadPreparingDialog: AlertDialog
|
||||
|
||||
@Inject
|
||||
lateinit var appPreferences: AppPreferences
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
binding = FragmentSeasonBinding.inflate(inflater, container, false)
|
||||
val menuHost: MenuHost = requireActivity()
|
||||
menuHost.addMenuProvider(
|
||||
object : MenuProvider {
|
||||
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
||||
menuInflater.inflate(com.nomadics9.ananas.core.R.menu.season_menu, menu)
|
||||
}
|
||||
|
||||
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
|
||||
return when (menuItem.itemId) {
|
||||
com.nomadics9.ananas.core.R.id.action_download_season -> {
|
||||
if (requireContext().getExternalFilesDirs(null).filterNotNull().size > 1) {
|
||||
val storageDialog = getStorageSelectionDialog(
|
||||
requireContext(),
|
||||
onItemSelected = { storageIndex ->
|
||||
createEpisodesToDownloadDialog(storageIndex)
|
||||
},
|
||||
onCancel = {
|
||||
},
|
||||
)
|
||||
viewModel.download()
|
||||
return true
|
||||
}
|
||||
createEpisodesToDownloadDialog()
|
||||
return true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
viewLifecycleOwner,
|
||||
Lifecycle.State.RESUMED,
|
||||
)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
launch {
|
||||
viewModel.uiState.collect { uiState ->
|
||||
Timber.d("$uiState")
|
||||
when (uiState) {
|
||||
is SeasonViewModel.UiState.Normal -> bindUiStateNormal(uiState)
|
||||
is SeasonViewModel.UiState.Loading -> bindUiStateLoading()
|
||||
is SeasonViewModel.UiState.Error -> bindUiStateError(uiState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
launch {
|
||||
|
||||
viewModel.downloadStatus.collect { (status, progress) ->
|
||||
when (status) {
|
||||
10 -> {
|
||||
downloadPreparingDialog.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
launch {
|
||||
viewModel.downloadError.collect { uiText ->
|
||||
createErrorDialog(uiText)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
launch {
|
||||
viewModel.eventsChannelFlow.collect { event ->
|
||||
when (event) {
|
||||
is SeasonEvent.NavigateBack -> findNavController().navigateUp()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding.errorLayout.errorRetryButton.setOnClickListener {
|
||||
viewModel.loadEpisodes(args.seriesId, args.seasonId, args.offline)
|
||||
}
|
||||
|
||||
binding.errorLayout.errorDetailsButton.setOnClickListener {
|
||||
errorDialog.show(parentFragmentManager, ErrorDialogFragment.TAG)
|
||||
}
|
||||
|
||||
binding.episodesRecyclerView.adapter =
|
||||
EpisodeListAdapter { episode ->
|
||||
navigateToEpisodeBottomSheetFragment(episode)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
viewModel.loadEpisodes(args.seriesId, args.seasonId, args.offline)
|
||||
}
|
||||
|
||||
private fun bindUiStateNormal(uiState: SeasonViewModel.UiState.Normal) {
|
||||
uiState.apply {
|
||||
val adapter = binding.episodesRecyclerView.adapter as EpisodeListAdapter
|
||||
adapter.submitList(uiState.episodes)
|
||||
}
|
||||
binding.loadingIndicator.isVisible = false
|
||||
binding.episodesRecyclerView.isVisible = true
|
||||
binding.errorLayout.errorPanel.isVisible = false
|
||||
}
|
||||
|
||||
private fun bindUiStateLoading() {
|
||||
binding.loadingIndicator.isVisible = true
|
||||
binding.errorLayout.errorPanel.isVisible = false
|
||||
}
|
||||
|
||||
private fun bindUiStateError(uiState: SeasonViewModel.UiState.Error) {
|
||||
errorDialog = ErrorDialogFragment.newInstance(uiState.error)
|
||||
binding.loadingIndicator.isVisible = false
|
||||
binding.episodesRecyclerView.isVisible = false
|
||||
binding.errorLayout.errorPanel.isVisible = true
|
||||
checkIfLoginRequired(uiState.error.message)
|
||||
}
|
||||
|
||||
private fun createDownloadPreparingDialog() {
|
||||
val builder = MaterialAlertDialogBuilder(requireContext())
|
||||
downloadPreparingDialog = builder
|
||||
.setTitle(com.nomadics9.ananas.core.R.string.preparing_download)
|
||||
.setView(com.nomadics9.ananas.R.layout.preparing_download_dialog)
|
||||
.setCancelable(false)
|
||||
.create()
|
||||
downloadPreparingDialog.show()
|
||||
}
|
||||
|
||||
private fun createErrorDialog(uiText: UiText) {
|
||||
val builder = MaterialAlertDialogBuilder(requireContext())
|
||||
builder
|
||||
.setTitle(com.nomadics9.ananas.core.R.string.downloading_error)
|
||||
.setMessage(uiText.asString(requireContext().resources))
|
||||
.setPositiveButton(getString(com.nomadics9.ananas.core.R.string.close)) { _, _ ->
|
||||
}
|
||||
builder.show()
|
||||
}
|
||||
|
||||
private fun createEpisodesToDownloadDialog(storageIndex: Int = 0) {
|
||||
if (!appPreferences.downloadQualityDefault)
|
||||
createPickQualityDialog {
|
||||
showDownloadDialog(storageIndex)
|
||||
} else {
|
||||
showDownloadDialog(storageIndex)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showDownloadDialog(storageIndex: Int = 0) {
|
||||
val builder = MaterialAlertDialogBuilder(requireContext())
|
||||
val dialog = builder
|
||||
.setTitle(com.nomadics9.ananas.core.R.string.download_season_dialog_title)
|
||||
.setMessage(com.nomadics9.ananas.core.R.string.download_season_dialog_question)
|
||||
.setPositiveButton(com.nomadics9.ananas.core.R.string.download_season_dialog_download_all) { _, _ ->
|
||||
createDownloadPreparingDialog()
|
||||
viewModel.download(storageIndex = storageIndex, downloadWatched = true)
|
||||
}
|
||||
.setNegativeButton(com.nomadics9.ananas.core.R.string.download_season_dialog_download_unwatched) { _, _ ->
|
||||
createDownloadPreparingDialog()
|
||||
viewModel.download(storageIndex = storageIndex, downloadWatched = false)
|
||||
}
|
||||
.create()
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
private fun createPickQualityDialog(onQualitySelected: () -> Unit) {
|
||||
val qualityEntries = resources.getStringArray(com.nomadics9.ananas.core.R.array.download_quality_entries)
|
||||
val qualityValues = resources.getStringArray(com.nomadics9.ananas.core.R.array.download_quality_values)
|
||||
val quality = appPreferences.downloadQuality
|
||||
val currentQualityIndex = qualityValues.indexOf(quality)
|
||||
|
||||
var selectedQuality = quality
|
||||
|
||||
val builder = MaterialAlertDialogBuilder(requireContext())
|
||||
builder.setTitle("Download Quality")
|
||||
builder.setSingleChoiceItems(qualityEntries, currentQualityIndex) { _, which ->
|
||||
selectedQuality = qualityValues[which]
|
||||
}
|
||||
builder.setPositiveButton("Download") { dialog, _ ->
|
||||
appPreferences.downloadQuality = selectedQuality
|
||||
onQualitySelected()
|
||||
dialog.dismiss()
|
||||
}
|
||||
builder.setNegativeButton("Cancel") { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
}
|
||||
|
||||
val dialog = builder.create()
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private fun navigateToEpisodeBottomSheetFragment(episode: FindroidEpisode) {
|
||||
findNavController().navigate(
|
||||
SeasonFragmentDirections.actionSeasonFragmentToEpisodeBottomSheetFragment(
|
||||
episode.id,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
|
@ -12,12 +12,12 @@ import androidx.lifecycle.repeatOnLifecycle
|
|||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.adapters.ServerAddressAdapter
|
||||
import dev.jdtech.jellyfin.databinding.FragmentServerAddressesBinding
|
||||
import dev.jdtech.jellyfin.dialogs.AddServerAddressDialog
|
||||
import dev.jdtech.jellyfin.dialogs.DeleteServerAddressDialog
|
||||
import dev.jdtech.jellyfin.viewmodels.ServerAddressesEvent
|
||||
import dev.jdtech.jellyfin.viewmodels.ServerAddressesViewModel
|
||||
import com.nomadics9.ananas.adapters.ServerAddressAdapter
|
||||
import com.nomadics9.ananas.databinding.FragmentServerAddressesBinding
|
||||
import com.nomadics9.ananas.dialogs.AddServerAddressDialog
|
||||
import com.nomadics9.ananas.dialogs.DeleteServerAddressDialog
|
||||
import com.nomadics9.ananas.viewmodels.ServerAddressesEvent
|
||||
import com.nomadics9.ananas.viewmodels.ServerAddressesViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
|
@ -11,11 +11,11 @@ import androidx.lifecycle.lifecycleScope
|
|||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.adapters.ServerGridAdapter
|
||||
import dev.jdtech.jellyfin.databinding.FragmentServerSelectBinding
|
||||
import dev.jdtech.jellyfin.dialogs.DeleteServerDialogFragment
|
||||
import dev.jdtech.jellyfin.viewmodels.ServerSelectEvent
|
||||
import dev.jdtech.jellyfin.viewmodels.ServerSelectViewModel
|
||||
import com.nomadics9.ananas.adapters.ServerGridAdapter
|
||||
import com.nomadics9.ananas.databinding.FragmentServerSelectBinding
|
||||
import com.nomadics9.ananas.dialogs.DeleteServerDialogFragment
|
||||
import com.nomadics9.ananas.viewmodels.ServerSelectEvent
|
||||
import com.nomadics9.ananas.viewmodels.ServerSelectViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
class SettingsAppearanceFragment : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
|
@ -1,10 +1,10 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.InputType
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
class SettingsCacheFragment : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
|
@ -1,12 +1,12 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.viewmodels.SettingsDeviceViewModel
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.viewmodels.SettingsDeviceViewModel
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
@AndroidEntryPoint
|
||||
class SettingsDeviceFragment : PreferenceFragmentCompat() {
|
|
@ -1,8 +1,8 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
class SettingsDownloadsFragment : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
|
@ -0,0 +1,175 @@
|
|||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import com.nomadics9.ananas.AppPreferences
|
||||
import com.nomadics9.ananas.BuildConfig
|
||||
import com.nomadics9.ananas.utils.restart
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.URL
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
@AndroidEntryPoint
|
||||
class SettingsFragment : PreferenceFragmentCompat() {
|
||||
@Inject
|
||||
lateinit var appPreferences: AppPreferences
|
||||
|
||||
private val updateUrl = BuildConfig.UPDATE_ADDRESS
|
||||
private var isUpdateAvailable: Boolean = false
|
||||
private var newLastModifiedDate: Date? = null
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(CoreR.xml.fragment_settings, rootKey)
|
||||
|
||||
findPreference<Preference>("switchServer")?.setOnPreferenceClickListener {
|
||||
findNavController().navigate(TwoPaneSettingsFragmentDirections.actionNavigationSettingsToServerSelectFragment())
|
||||
true
|
||||
}
|
||||
|
||||
findPreference<Preference>("switchUser")?.setOnPreferenceClickListener {
|
||||
val serverId = appPreferences.currentServer!!
|
||||
findNavController().navigate(
|
||||
TwoPaneSettingsFragmentDirections.actionNavigationSettingsToUsersFragment(
|
||||
serverId
|
||||
)
|
||||
)
|
||||
true
|
||||
}
|
||||
|
||||
findPreference<Preference>("switchAddress")?.setOnPreferenceClickListener {
|
||||
val serverId = appPreferences.currentServer!!
|
||||
findNavController().navigate(
|
||||
TwoPaneSettingsFragmentDirections.actionNavigationSettingsToServerAddressesFragment(
|
||||
serverId
|
||||
)
|
||||
)
|
||||
true
|
||||
}
|
||||
|
||||
findPreference<Preference>("pref_offline_mode")?.setOnPreferenceClickListener {
|
||||
activity?.restart()
|
||||
true
|
||||
}
|
||||
|
||||
findPreference<Preference>("privacyPolicy")?.setOnPreferenceClickListener {
|
||||
val intent = Intent(
|
||||
Intent.ACTION_VIEW,
|
||||
Uri.parse("https://github.com/nomadics9/ananas/blob/main/PRIVACY"),
|
||||
)
|
||||
startActivity(intent)
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
findPreference<Preference>("appInfo")?.setOnPreferenceClickListener {
|
||||
if (isUpdateAvailable && newLastModifiedDate != null) {
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(updateUrl))
|
||||
startActivity(intent)
|
||||
storeDate(newLastModifiedDate!!)
|
||||
true
|
||||
} else {
|
||||
findNavController().navigate(TwoPaneSettingsFragmentDirections.actionSettingsFragmentToAboutLibraries())
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
findPreference<Preference>("requests")?.setOnPreferenceClickListener {
|
||||
findNavController().navigate(TwoPaneSettingsFragmentDirections.actionNavigationSettingsToRequestsWebFragment())
|
||||
true
|
||||
}
|
||||
|
||||
// Check for updates when the settings screen is opened
|
||||
checkForUpdates()
|
||||
}
|
||||
|
||||
private fun checkForUpdates() {
|
||||
lifecycleScope.launch {
|
||||
val lastModifiedDate = fetchLastModifiedDate(updateUrl)
|
||||
if (lastModifiedDate != null) {
|
||||
Timber.d("Fetched Last-Modified date: $lastModifiedDate")
|
||||
val storedDate = getStoredDate()
|
||||
Timber.d("Stored date: $storedDate")
|
||||
if (storedDate == Date(0L) || lastModifiedDate.after(storedDate)) {
|
||||
Timber.d("Update available")
|
||||
isUpdateAvailable = true
|
||||
newLastModifiedDate = lastModifiedDate
|
||||
showUpdateAvailable()
|
||||
} else {
|
||||
Timber.d("No update available")
|
||||
isUpdateAvailable = false
|
||||
}
|
||||
} else {
|
||||
Timber.d("Failed to fetch Last-Modified date")
|
||||
isUpdateAvailable = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun fetchLastModifiedDate(urlString: String): Date? {
|
||||
return withContext(Dispatchers.IO) {
|
||||
var urlConnection: HttpURLConnection? = null
|
||||
try {
|
||||
val url = URL(urlString)
|
||||
urlConnection = url.openConnection() as HttpURLConnection
|
||||
urlConnection.requestMethod = "HEAD"
|
||||
val lastModified = urlConnection.getHeaderField("Last-Modified")
|
||||
if (lastModified != null) {
|
||||
val dateFormat = SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US)
|
||||
dateFormat.parse(lastModified)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Error fetching Last-Modified date")
|
||||
null
|
||||
} finally {
|
||||
urlConnection?.disconnect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getStoredDate(): Date {
|
||||
val sharedPreferences = preferenceManager.sharedPreferences
|
||||
val storedDateString = sharedPreferences?.getString("stored_date", null)
|
||||
Timber.d("Retrieved stored date string: $storedDateString")
|
||||
return if (storedDateString != null) {
|
||||
try {
|
||||
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US).parse(storedDateString) ?: Date(0)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Error parsing stored date string")
|
||||
Date(0)
|
||||
}
|
||||
} else {
|
||||
Date(0)
|
||||
}
|
||||
}
|
||||
|
||||
private fun storeDate(date: Date) {
|
||||
val dateString = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US).format(date)
|
||||
preferenceManager.sharedPreferences?.edit()?.putString("stored_date", dateString)?.apply()
|
||||
Timber.d("Stored new date: $dateString")
|
||||
}
|
||||
|
||||
private fun showUpdateAvailable() {
|
||||
val appInfoPreference = findPreference<Preference>("appInfo")
|
||||
appInfoPreference?.let {
|
||||
it.summary = "Update available!"
|
||||
it.icon = ResourcesCompat.getDrawable(resources, CoreR.drawable.ic_download, null) // Ensure this drawable exists
|
||||
Timber.d("Update available UI shown")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
|
@ -7,7 +7,7 @@ import android.os.Bundle
|
|||
import android.provider.Settings
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
class SettingsLanguageFragment : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
|
@ -1,11 +1,11 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.InputType
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import dev.jdtech.jellyfin.Constants
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.Constants
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
class SettingsNetworkFragment : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
|
@ -7,7 +7,7 @@ import android.text.InputType
|
|||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
class SettingsPlayerFragment : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
|
@ -18,29 +18,29 @@ import androidx.navigation.fragment.findNavController
|
|||
import androidx.navigation.fragment.navArgs
|
||||
import com.google.android.material.R
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.AppPreferences
|
||||
import dev.jdtech.jellyfin.adapters.PersonListAdapter
|
||||
import dev.jdtech.jellyfin.adapters.ViewItemListAdapter
|
||||
import dev.jdtech.jellyfin.bindCardItemImage
|
||||
import dev.jdtech.jellyfin.bindItemBackdropImage
|
||||
import dev.jdtech.jellyfin.databinding.FragmentShowBinding
|
||||
import dev.jdtech.jellyfin.dialogs.ErrorDialogFragment
|
||||
import dev.jdtech.jellyfin.models.FindroidItem
|
||||
import dev.jdtech.jellyfin.models.FindroidSeason
|
||||
import dev.jdtech.jellyfin.models.FindroidSourceType
|
||||
import dev.jdtech.jellyfin.models.PlayerItem
|
||||
import dev.jdtech.jellyfin.models.isDownloaded
|
||||
import dev.jdtech.jellyfin.utils.checkIfLoginRequired
|
||||
import dev.jdtech.jellyfin.utils.setIconTintColorAttribute
|
||||
import dev.jdtech.jellyfin.viewmodels.PlayerItemsEvent
|
||||
import dev.jdtech.jellyfin.viewmodels.PlayerViewModel
|
||||
import dev.jdtech.jellyfin.viewmodels.ShowEvent
|
||||
import dev.jdtech.jellyfin.viewmodels.ShowViewModel
|
||||
import com.nomadics9.ananas.AppPreferences
|
||||
import com.nomadics9.ananas.adapters.PersonListAdapter
|
||||
import com.nomadics9.ananas.adapters.ViewItemListAdapter
|
||||
import com.nomadics9.ananas.bindCardItemImage
|
||||
import com.nomadics9.ananas.bindItemBackdropImage
|
||||
import com.nomadics9.ananas.databinding.FragmentShowBinding
|
||||
import com.nomadics9.ananas.dialogs.ErrorDialogFragment
|
||||
import com.nomadics9.ananas.models.FindroidItem
|
||||
import com.nomadics9.ananas.models.FindroidSeason
|
||||
import com.nomadics9.ananas.models.FindroidSourceType
|
||||
import com.nomadics9.ananas.models.PlayerItem
|
||||
import com.nomadics9.ananas.models.isDownloaded
|
||||
import com.nomadics9.ananas.utils.checkIfLoginRequired
|
||||
import com.nomadics9.ananas.utils.setIconTintColorAttribute
|
||||
import com.nomadics9.ananas.viewmodels.PlayerItemsEvent
|
||||
import com.nomadics9.ananas.viewmodels.PlayerViewModel
|
||||
import com.nomadics9.ananas.viewmodels.ShowEvent
|
||||
import com.nomadics9.ananas.viewmodels.ShowViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
@AndroidEntryPoint
|
||||
class ShowFragment : Fragment() {
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceHeaderFragmentCompat
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
package com.nomadics9.ananas.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
|
@ -12,12 +12,12 @@ import androidx.lifecycle.repeatOnLifecycle
|
|||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.AppNavigationDirections
|
||||
import dev.jdtech.jellyfin.adapters.UserListAdapter
|
||||
import dev.jdtech.jellyfin.databinding.FragmentUsersBinding
|
||||
import dev.jdtech.jellyfin.dialogs.DeleteUserDialogFragment
|
||||
import dev.jdtech.jellyfin.viewmodels.UsersEvent
|
||||
import dev.jdtech.jellyfin.viewmodels.UsersViewModel
|
||||
import com.nomadics9.ananas.AppNavigationDirections
|
||||
import com.nomadics9.ananas.adapters.UserListAdapter
|
||||
import com.nomadics9.ananas.databinding.FragmentUsersBinding
|
||||
import com.nomadics9.ananas.dialogs.DeleteUserDialogFragment
|
||||
import com.nomadics9.ananas.viewmodels.UsersEvent
|
||||
import com.nomadics9.ananas.viewmodels.UsersViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
package dev.jdtech.jellyfin.utils
|
||||
package com.nomadics9.ananas.utils
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import dev.jdtech.jellyfin.AppNavigationDirections
|
||||
import com.nomadics9.ananas.AppNavigationDirections
|
||||
import timber.log.Timber
|
||||
|
||||
fun Fragment.checkIfLoginRequired(error: String?) {
|
|
@ -1,7 +1,8 @@
|
|||
package dev.jdtech.jellyfin.utils
|
||||
package com.nomadics9.ananas.utils
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Bitmap
|
||||
import android.media.AudioManager
|
||||
import android.os.Build
|
||||
import android.os.SystemClock
|
||||
|
@ -19,15 +20,20 @@ import android.view.animation.DecelerateInterpolator
|
|||
import android.widget.ImageView
|
||||
import androidx.media3.ui.AspectRatioFrameLayout
|
||||
import androidx.media3.ui.PlayerView
|
||||
import dev.jdtech.jellyfin.AppPreferences
|
||||
import dev.jdtech.jellyfin.Constants
|
||||
import dev.jdtech.jellyfin.PlayerActivity
|
||||
import dev.jdtech.jellyfin.isControlsLocked
|
||||
import dev.jdtech.jellyfin.models.PlayerChapter
|
||||
import dev.jdtech.jellyfin.mpv.MPVPlayer
|
||||
import coil.transform.RoundedCornersTransformation
|
||||
import com.nomadics9.ananas.AppPreferences
|
||||
import com.nomadics9.ananas.Constants
|
||||
import com.nomadics9.ananas.PlayerActivity
|
||||
import com.nomadics9.ananas.isControlsLocked
|
||||
import com.nomadics9.ananas.models.PlayerChapter
|
||||
import com.nomadics9.ananas.models.Trickplay
|
||||
import com.nomadics9.ananas.mpv.MPVPlayer
|
||||
import timber.log.Timber
|
||||
import kotlin.math.abs
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import coil.load
|
||||
|
||||
class PlayerGestureHelper(
|
||||
private val appPreferences: AppPreferences,
|
||||
private val activity: PlayerActivity,
|
||||
|
@ -62,6 +68,10 @@ class PlayerGestureHelper(
|
|||
private val screenWidth = Resources.getSystem().displayMetrics.widthPixels
|
||||
private val screenHeight = Resources.getSystem().displayMetrics.heightPixels
|
||||
|
||||
var currentTrickplay: Trickplay? = null
|
||||
private val roundedCorners = RoundedCornersTransformation(10f)
|
||||
private var currentBitMap: Bitmap? = null
|
||||
|
||||
private var currentNumberOfPointers: Int = 0
|
||||
|
||||
private val tapGestureDetector = GestureDetector(
|
||||
|
@ -265,6 +275,13 @@ class PlayerGestureHelper(
|
|||
activity.binding.progressScrubberLayout.visibility = View.VISIBLE
|
||||
activity.binding.progressScrubberText.text = "${longToTimestamp(difference)} [${longToTimestamp(newPos, true)}]"
|
||||
swipeGestureValueTrackerProgress = newPos
|
||||
|
||||
if (currentTrickplay != null) {
|
||||
onMove(newPos)
|
||||
} else {
|
||||
activity.binding.imagePreviewGesture.visibility = View.GONE
|
||||
}
|
||||
|
||||
swipeGestureProgressOpen = true
|
||||
true
|
||||
} else {
|
||||
|
@ -471,11 +488,28 @@ class PlayerGestureHelper(
|
|||
return false
|
||||
}
|
||||
|
||||
fun onMove(position: Long) {
|
||||
val trickplay = currentTrickplay ?: return
|
||||
val image = trickplay.images[position.div(trickplay.interval).toInt()]
|
||||
|
||||
if (currentBitMap != image) {
|
||||
activity.binding.imagePreviewGesture.load(image) {
|
||||
dispatcher(Dispatchers.Main.immediate)
|
||||
transformations(roundedCorners)
|
||||
}
|
||||
currentBitMap = image
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
if (appPreferences.playerBrightnessRemember) {
|
||||
activity.window.attributes.screenBrightness = appPreferences.playerBrightness
|
||||
}
|
||||
|
||||
if (!appPreferences.playerTrickPlayGesture) {
|
||||
activity.binding.imagePreviewGesture.visibility = View.GONE
|
||||
}
|
||||
|
||||
updateZoomMode(appPreferences.playerStartMaximized)
|
||||
|
||||
@Suppress("ClickableViewAccessibility")
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.utils
|
||||
package com.nomadics9.ananas.utils
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.view.View
|
||||
|
@ -8,7 +8,7 @@ import androidx.media3.common.Player
|
|||
import androidx.media3.ui.TimeBar
|
||||
import coil.load
|
||||
import coil.transform.RoundedCornersTransformation
|
||||
import dev.jdtech.jellyfin.models.Trickplay
|
||||
import com.nomadics9.ananas.models.Trickplay
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import timber.log.Timber
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.adapters.EpisodeListAdapter
|
||||
import dev.jdtech.jellyfin.databinding.FragmentSeasonBinding
|
||||
import dev.jdtech.jellyfin.dialogs.ErrorDialogFragment
|
||||
import dev.jdtech.jellyfin.models.FindroidEpisode
|
||||
import dev.jdtech.jellyfin.utils.checkIfLoginRequired
|
||||
import dev.jdtech.jellyfin.viewmodels.SeasonEvent
|
||||
import dev.jdtech.jellyfin.viewmodels.SeasonViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
@AndroidEntryPoint
|
||||
class SeasonFragment : Fragment() {
|
||||
|
||||
private lateinit var binding: FragmentSeasonBinding
|
||||
private val viewModel: SeasonViewModel by viewModels()
|
||||
private val args: SeasonFragmentArgs by navArgs()
|
||||
|
||||
private lateinit var errorDialog: ErrorDialogFragment
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
binding = FragmentSeasonBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
launch {
|
||||
viewModel.uiState.collect { uiState ->
|
||||
Timber.d("$uiState")
|
||||
when (uiState) {
|
||||
is SeasonViewModel.UiState.Normal -> bindUiStateNormal(uiState)
|
||||
is SeasonViewModel.UiState.Loading -> bindUiStateLoading()
|
||||
is SeasonViewModel.UiState.Error -> bindUiStateError(uiState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
launch {
|
||||
viewModel.eventsChannelFlow.collect { event ->
|
||||
when (event) {
|
||||
is SeasonEvent.NavigateBack -> findNavController().navigateUp()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding.errorLayout.errorRetryButton.setOnClickListener {
|
||||
viewModel.loadEpisodes(args.seriesId, args.seasonId, args.offline)
|
||||
}
|
||||
|
||||
binding.errorLayout.errorDetailsButton.setOnClickListener {
|
||||
errorDialog.show(parentFragmentManager, ErrorDialogFragment.TAG)
|
||||
}
|
||||
|
||||
binding.episodesRecyclerView.adapter =
|
||||
EpisodeListAdapter { episode ->
|
||||
navigateToEpisodeBottomSheetFragment(episode)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
viewModel.loadEpisodes(args.seriesId, args.seasonId, args.offline)
|
||||
}
|
||||
|
||||
private fun bindUiStateNormal(uiState: SeasonViewModel.UiState.Normal) {
|
||||
uiState.apply {
|
||||
val adapter = binding.episodesRecyclerView.adapter as EpisodeListAdapter
|
||||
adapter.submitList(uiState.episodes)
|
||||
}
|
||||
binding.loadingIndicator.isVisible = false
|
||||
binding.episodesRecyclerView.isVisible = true
|
||||
binding.errorLayout.errorPanel.isVisible = false
|
||||
}
|
||||
|
||||
private fun bindUiStateLoading() {
|
||||
binding.loadingIndicator.isVisible = true
|
||||
binding.errorLayout.errorPanel.isVisible = false
|
||||
}
|
||||
|
||||
private fun bindUiStateError(uiState: SeasonViewModel.UiState.Error) {
|
||||
errorDialog = ErrorDialogFragment.newInstance(uiState.error)
|
||||
binding.loadingIndicator.isVisible = false
|
||||
binding.episodesRecyclerView.isVisible = false
|
||||
binding.errorLayout.errorPanel.isVisible = true
|
||||
checkIfLoginRequired(uiState.error.message)
|
||||
}
|
||||
|
||||
private fun navigateToEpisodeBottomSheetFragment(episode: FindroidEpisode) {
|
||||
findNavController().navigate(
|
||||
SeasonFragmentDirections.actionSeasonFragmentToEpisodeBottomSheetFragment(
|
||||
episode.id,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.AppPreferences
|
||||
import dev.jdtech.jellyfin.utils.restart
|
||||
import javax.inject.Inject
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
|
||||
@AndroidEntryPoint
|
||||
class SettingsFragment : PreferenceFragmentCompat() {
|
||||
@Inject
|
||||
lateinit var appPreferences: AppPreferences
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(CoreR.xml.fragment_settings, rootKey)
|
||||
|
||||
findPreference<Preference>("switchServer")?.setOnPreferenceClickListener {
|
||||
findNavController().navigate(TwoPaneSettingsFragmentDirections.actionNavigationSettingsToServerSelectFragment())
|
||||
true
|
||||
}
|
||||
|
||||
findPreference<Preference>("switchUser")?.setOnPreferenceClickListener {
|
||||
val serverId = appPreferences.currentServer!!
|
||||
findNavController().navigate(TwoPaneSettingsFragmentDirections.actionNavigationSettingsToUsersFragment(serverId))
|
||||
true
|
||||
}
|
||||
|
||||
findPreference<Preference>("switchAddress")?.setOnPreferenceClickListener {
|
||||
val serverId = appPreferences.currentServer!!
|
||||
findNavController().navigate(TwoPaneSettingsFragmentDirections.actionNavigationSettingsToServerAddressesFragment(serverId))
|
||||
true
|
||||
}
|
||||
|
||||
findPreference<Preference>("pref_offline_mode")?.setOnPreferenceClickListener {
|
||||
activity?.restart()
|
||||
true
|
||||
}
|
||||
|
||||
findPreference<Preference>("privacyPolicy")?.setOnPreferenceClickListener {
|
||||
val intent = Intent(
|
||||
Intent.ACTION_VIEW,
|
||||
Uri.parse("https://github.com/jarnedemeulemeester/findroid/blob/main/PRIVACY"),
|
||||
)
|
||||
startActivity(intent)
|
||||
true
|
||||
}
|
||||
|
||||
findPreference<Preference>("appInfo")?.setOnPreferenceClickListener {
|
||||
findNavController().navigate(TwoPaneSettingsFragmentDirections.actionSettingsFragmentToAboutLibraries())
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,7 +37,16 @@
|
|||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/main_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize" />
|
||||
android:layout_height="?attr/actionBarSize">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="65dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:contentDescription="@string/app_name"
|
||||
android:src="@drawable/ic_launcher_foreground" />
|
||||
|
||||
</com.google.android.material.appbar.MaterialToolbar>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
@ -39,8 +40,17 @@
|
|||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/main_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize" />
|
||||
android:layout_height="?attr/actionBarSize">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="65dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:contentDescription="@string/app_name"
|
||||
android:src="@drawable/ic_launcher_foreground" />
|
||||
|
||||
</com.google.android.material.appbar.MaterialToolbar>
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
@ -16,8 +16,11 @@
|
|||
|
||||
<LinearLayout
|
||||
android:id="@+id/progress_scrubber_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="64dp"
|
||||
android:padding="10dp"
|
||||
android:background="@drawable/overlay_background"
|
||||
android:clickable="false"
|
||||
android:gravity="center"
|
||||
|
@ -25,10 +28,20 @@
|
|||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image_preview_gesture"
|
||||
android:layout_width="272dp"
|
||||
android:layout_height="153dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="10dp"
|
||||
|
||||
android:contentDescription="@string/player_trickplay" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/progress_scrubber_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:textAppearance="@style/TextAppearance.Material3.HeadlineSmall"
|
||||
android:textColor="@android:color/white"
|
||||
tools:text="+00:00:10 [00:00:20]" />
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center">
|
||||
|
||||
|
||||
<!-- Video surface will be inserted as the first child of the content frame. -->
|
||||
|
||||
<View
|
||||
|
@ -48,24 +49,6 @@
|
|||
android:textColor="@android:color/white"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_skip_intro"
|
||||
style="@style/Widget.Material3.Button.OutlinedButton.Icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|bottom"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginBottom="64dp"
|
||||
android:text="@string/player_controls_skip_intro"
|
||||
android:textColor="@android:color/white"
|
||||
android:visibility="gone"
|
||||
app:backgroundTint="@color/player_background"
|
||||
app:icon="@drawable/ic_skip_forward"
|
||||
app:iconGravity="end"
|
||||
app:iconTint="@android:color/white"
|
||||
app:strokeColor="@android:color/white"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</androidx.media3.ui.AspectRatioFrameLayout>
|
||||
|
||||
<androidx.media3.ui.SubtitleView
|
||||
|
@ -89,4 +72,33 @@
|
|||
android:layout_height="match_parent"
|
||||
app:animation_enabled="false"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_gravity="end|bottom"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginBottom="64dp">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_watch_credits"
|
||||
style="@style/Widget.Material3.Button.TonalButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:text="@string/watch_credits"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_skip_intro"
|
||||
style="@style/Widget.Material3.Button.Icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_skip_forward"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</merge>
|
|
@ -141,10 +141,24 @@
|
|||
android:visibility="invisible" />
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="24dp">
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_forget_password"
|
||||
style="@style/Widget.Material3.Button.OutlinedButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/forget_password" />
|
||||
</RelativeLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/login_disclaimer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:layout_marginHorizontal="24dp"
|
||||
android:layout_margin="24dp"
|
||||
android:textSize="16sp"
|
||||
|
|
16
app/phone/src/main/res/layout/fragment_webview.xml
Normal file
16
app/phone/src/main/res/layout/fragment_webview.xml
Normal file
|
@ -0,0 +1,16 @@
|
|||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<WebView
|
||||
android:id="@+id/webview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
style="?android:attr/progressBarStyleLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true" />
|
||||
</RelativeLayout>
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/homeFragment"
|
||||
android:name="dev.jdtech.jellyfin.fragments.HomeFragment"
|
||||
android:name="com.nomadics9.ananas.fragments.HomeFragment"
|
||||
android:label="@string/title_home"
|
||||
tools:layout="@layout/fragment_home">
|
||||
<action
|
||||
|
@ -49,11 +49,14 @@
|
|||
<action
|
||||
android:id="@+id/action_homeFragment_to_searchResultFragment"
|
||||
app:destination="@id/searchResultFragment" />
|
||||
<action
|
||||
android:id="@+id/action_homeFragment_to_requestsWebFragment"
|
||||
app:destination="@id/requestsWebFragment" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/mediaFragment"
|
||||
android:name="dev.jdtech.jellyfin.fragments.MediaFragment"
|
||||
android:name="com.nomadics9.ananas.fragments.MediaFragment"
|
||||
android:label="@string/title_media"
|
||||
tools:layout="@layout/fragment_media">
|
||||
<action
|
||||
|
@ -70,7 +73,7 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/twoPaneSettingsFragment"
|
||||
android:name="dev.jdtech.jellyfin.fragments.TwoPaneSettingsFragment"
|
||||
android:name="com.nomadics9.ananas.fragments.TwoPaneSettingsFragment"
|
||||
android:label="@string/title_settings">
|
||||
<action
|
||||
android:id="@+id/action_navigation_settings_to_serverSelectFragment"
|
||||
|
@ -84,13 +87,23 @@
|
|||
<action
|
||||
android:id="@+id/action_settingsFragment_to_about_libraries"
|
||||
app:destination="@id/about_libraries" />
|
||||
<action
|
||||
android:id="@+id/action_navigation_settings_to_requestsWebFragment"
|
||||
app:destination="@id/requestsWebFragment" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/settingsFragment"
|
||||
android:name="dev.jdtech.jellyfin.fragments.SettingsFragment" />
|
||||
android:name="com.nomadics9.ananas.fragments.SettingsFragment">
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/requestsWebFragment"
|
||||
android:name="com.nomadics9.ananas.fragments.RequestsWebViewFragment"
|
||||
android:label="Requests"
|
||||
tools:layout="@layout/fragment_webview">
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/libraryFragment"
|
||||
android:name="dev.jdtech.jellyfin.fragments.LibraryFragment"
|
||||
android:name="com.nomadics9.ananas.fragments.LibraryFragment"
|
||||
android:label="{libraryName}"
|
||||
tools:layout="@layout/fragment_library">
|
||||
<argument
|
||||
|
@ -122,14 +135,14 @@
|
|||
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
|
||||
<argument
|
||||
android:name="libraryType"
|
||||
app:argType="dev.jdtech.jellyfin.models.CollectionType" />
|
||||
app:argType="com.nomadics9.ananas.models.CollectionType" />
|
||||
<action
|
||||
android:id="@+id/action_libraryFragment_self"
|
||||
app:destination="@id/libraryFragment" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/showFragment"
|
||||
android:name="dev.jdtech.jellyfin.fragments.ShowFragment"
|
||||
android:name="com.nomadics9.ananas.fragments.ShowFragment"
|
||||
android:label="{itemName}"
|
||||
tools:layout="@layout/fragment_show">
|
||||
<argument
|
||||
|
@ -158,7 +171,7 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/movieFragment"
|
||||
android:name="dev.jdtech.jellyfin.fragments.MovieFragment"
|
||||
android:name="com.nomadics9.ananas.fragments.MovieFragment"
|
||||
android:label="{itemName}"
|
||||
tools:layout="@layout/fragment_movie">
|
||||
<argument
|
||||
|
@ -179,7 +192,7 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/seasonFragment"
|
||||
android:name="dev.jdtech.jellyfin.fragments.SeasonFragment"
|
||||
android:name="com.nomadics9.ananas.fragments.SeasonFragment"
|
||||
android:label="{seasonName}"
|
||||
tools:layout="@layout/fragment_season">
|
||||
<argument
|
||||
|
@ -211,7 +224,7 @@
|
|||
</fragment>
|
||||
<dialog
|
||||
android:id="@+id/episodeBottomSheetFragment"
|
||||
android:name="dev.jdtech.jellyfin.fragments.EpisodeBottomSheetFragment"
|
||||
android:name="com.nomadics9.ananas.fragments.EpisodeBottomSheetFragment"
|
||||
android:label="EpisodeBottomSheetFragment"
|
||||
tools:layout="@layout/episode_bottom_sheet">
|
||||
<argument
|
||||
|
@ -226,7 +239,7 @@
|
|||
</dialog>
|
||||
<fragment
|
||||
android:id="@+id/favoriteFragment"
|
||||
android:name="dev.jdtech.jellyfin.fragments.FavoriteFragment"
|
||||
android:name="com.nomadics9.ananas.fragments.FavoriteFragment"
|
||||
android:label="@string/title_favorite"
|
||||
tools:layout="@layout/fragment_favorite">
|
||||
<action
|
||||
|
@ -241,7 +254,7 @@
|
|||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/collectionFragment"
|
||||
android:name="dev.jdtech.jellyfin.fragments.CollectionFragment"
|
||||
android:name="com.nomadics9.ananas.fragments.CollectionFragment"
|
||||
android:label="{collectionName}"
|
||||
tools:layout="@layout/fragment_favorite">
|
||||
<argument
|
||||
|
@ -264,7 +277,7 @@
|
|||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/searchResultFragment"
|
||||
android:name="dev.jdtech.jellyfin.fragments.SearchResultFragment"
|
||||
android:name="com.nomadics9.ananas.fragments.SearchResultFragment"
|
||||
android:label="{query}"
|
||||
tools:layout="@layout/fragment_search_result">
|
||||
<action
|
||||
|
@ -282,7 +295,7 @@
|
|||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/addServerFragment"
|
||||
android:name="dev.jdtech.jellyfin.fragments.AddServerFragment"
|
||||
android:name="com.nomadics9.ananas.fragments.AddServerFragment"
|
||||
android:label="@string/add_server"
|
||||
tools:layout="@layout/fragment_add_server">
|
||||
<action
|
||||
|
@ -291,7 +304,7 @@
|
|||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/serverSelectFragment"
|
||||
android:name="dev.jdtech.jellyfin.fragments.ServerSelectFragment"
|
||||
android:name="com.nomadics9.ananas.fragments.ServerSelectFragment"
|
||||
android:label="@string/select_server"
|
||||
tools:layout="@layout/fragment_server_select">
|
||||
<action
|
||||
|
@ -308,7 +321,7 @@
|
|||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/loginFragment"
|
||||
android:name="dev.jdtech.jellyfin.fragments.LoginFragment"
|
||||
android:name="com.nomadics9.ananas.fragments.LoginFragment"
|
||||
android:label="@string/login"
|
||||
tools:layout="@layout/fragment_login">
|
||||
<action
|
||||
|
@ -324,7 +337,7 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/personDetailFragment"
|
||||
android:name="dev.jdtech.jellyfin.fragments.PersonDetailFragment"
|
||||
android:name="com.nomadics9.ananas.fragments.PersonDetailFragment"
|
||||
android:label="@string/person_detail_title"
|
||||
tools:layout="@layout/fragment_person_detail">
|
||||
|
||||
|
@ -342,12 +355,12 @@
|
|||
|
||||
<activity
|
||||
android:id="@+id/playerActivity"
|
||||
android:name="dev.jdtech.jellyfin.PlayerActivity"
|
||||
android:name="com.nomadics9.ananas.PlayerActivity"
|
||||
android:label="activity_player"
|
||||
tools:layout="@layout/activity_player">
|
||||
<argument
|
||||
android:name="items"
|
||||
app:argType="dev.jdtech.jellyfin.models.PlayerItem[]" />
|
||||
app:argType="com.nomadics9.ananas.models.PlayerItem[]" />
|
||||
</activity>
|
||||
|
||||
<include app:graph="@navigation/aboutlibs_navigation" />
|
||||
|
@ -357,7 +370,7 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/usersFragment"
|
||||
android:name="dev.jdtech.jellyfin.fragments.UsersFragment"
|
||||
android:name="com.nomadics9.ananas.fragments.UsersFragment"
|
||||
android:label="@string/users"
|
||||
tools:layout="@layout/fragment_users">
|
||||
<action
|
||||
|
@ -375,7 +388,7 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/serverAddressesFragment"
|
||||
android:name="dev.jdtech.jellyfin.fragments.ServerAddressesFragment"
|
||||
android:name="com.nomadics9.ananas.fragments.ServerAddressesFragment"
|
||||
android:label="@string/addresses"
|
||||
tools:layout="@layout/fragment_server_addresses">
|
||||
<action
|
||||
|
@ -390,7 +403,7 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/downloadsFragment"
|
||||
android:name="dev.jdtech.jellyfin.fragments.DownloadsFragment"
|
||||
android:name="com.nomadics9.ananas.fragments.DownloadsFragment"
|
||||
android:label="@string/title_download"
|
||||
tools:layout="@layout/fragment_favorite">
|
||||
<action
|
||||
|
@ -409,4 +422,4 @@
|
|||
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
|
||||
</fragment>
|
||||
|
||||
</navigation>
|
||||
</navigation>
|
||||
|
|
4
app/phone/src/main/res/values/strings.xml
Normal file
4
app/phone/src/main/res/values/strings.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="watch_credits">Watch credits</string>
|
||||
</resources>
|
|
@ -9,12 +9,12 @@ plugins {
|
|||
}
|
||||
|
||||
android {
|
||||
namespace = "dev.jdtech.jellyfin"
|
||||
namespace = "com.nomadics9.ananas"
|
||||
compileSdk = Versions.compileSdk
|
||||
buildToolsVersion = Versions.buildTools
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "dev.jdtech.jellyfin"
|
||||
applicationId = "com.nomadics9.ananas"
|
||||
minSdk = Versions.minSdk
|
||||
targetSdk = Versions.targetSdk
|
||||
|
||||
|
@ -81,14 +81,15 @@ ktlint {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
val composeBom = platform(libs.androidx.compose.bom)
|
||||
|
||||
implementation(projects.core)
|
||||
implementation(projects.data)
|
||||
implementation(projects.preferences)
|
||||
implementation(projects.player.core)
|
||||
implementation(projects.player.video)
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(libs.androidx.compose.foundation)
|
||||
implementation(libs.androidx.compose.runtime)
|
||||
implementation(composeBom)
|
||||
implementation(libs.androidx.compose.ui.tooling.preview)
|
||||
implementation(libs.androidx.compose.material3)
|
||||
implementation(libs.androidx.core)
|
||||
|
@ -98,6 +99,7 @@ dependencies {
|
|||
implementation(libs.androidx.media3.ui)
|
||||
implementation(libs.androidx.media3.session)
|
||||
implementation(libs.androidx.paging.compose)
|
||||
implementation(libs.androidx.tv.foundation)
|
||||
implementation(libs.androidx.tv.material)
|
||||
implementation(libs.coil.compose)
|
||||
implementation(libs.coil.svg)
|
||||
|
|
65
app/tv/libre/debug/output-metadata.json
Normal file
65
app/tv/libre/debug/output-metadata.json
Normal file
|
@ -0,0 +1,65 @@
|
|||
{
|
||||
"version": 3,
|
||||
"artifactType": {
|
||||
"type": "APK",
|
||||
"kind": "Directory"
|
||||
},
|
||||
"applicationId": "com.nomadics9.ananas.debug",
|
||||
"variantName": "libreDebug",
|
||||
"elements": [
|
||||
{
|
||||
"type": "ONE_OF_MANY",
|
||||
"filters": [
|
||||
{
|
||||
"filterType": "ABI",
|
||||
"value": "armeabi-v7a"
|
||||
}
|
||||
],
|
||||
"attributes": [],
|
||||
"versionCode": 6,
|
||||
"versionName": "0.14.2",
|
||||
"outputFile": "tv-libre-armeabi-v7a-debug.apk"
|
||||
},
|
||||
{
|
||||
"type": "ONE_OF_MANY",
|
||||
"filters": [
|
||||
{
|
||||
"filterType": "ABI",
|
||||
"value": "x86_64"
|
||||
}
|
||||
],
|
||||
"attributes": [],
|
||||
"versionCode": 6,
|
||||
"versionName": "0.14.2",
|
||||
"outputFile": "tv-libre-x86_64-debug.apk"
|
||||
},
|
||||
{
|
||||
"type": "ONE_OF_MANY",
|
||||
"filters": [
|
||||
{
|
||||
"filterType": "ABI",
|
||||
"value": "arm64-v8a"
|
||||
}
|
||||
],
|
||||
"attributes": [],
|
||||
"versionCode": 6,
|
||||
"versionName": "0.14.2",
|
||||
"outputFile": "tv-libre-arm64-v8a-debug.apk"
|
||||
},
|
||||
{
|
||||
"type": "ONE_OF_MANY",
|
||||
"filters": [
|
||||
{
|
||||
"filterType": "ABI",
|
||||
"value": "x86"
|
||||
}
|
||||
],
|
||||
"attributes": [],
|
||||
"versionCode": 6,
|
||||
"versionName": "0.14.2",
|
||||
"outputFile": "tv-libre-x86-debug.apk"
|
||||
}
|
||||
],
|
||||
"elementType": "File",
|
||||
"minSdkVersionForDexing": 28
|
||||
}
|
Binary file not shown.
Binary file not shown.
BIN
app/tv/libre/release/baselineProfiles/0/tv-libre-x86-release.dm
Normal file
BIN
app/tv/libre/release/baselineProfiles/0/tv-libre-x86-release.dm
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
app/tv/libre/release/baselineProfiles/1/tv-libre-x86-release.dm
Normal file
BIN
app/tv/libre/release/baselineProfiles/1/tv-libre-x86-release.dm
Normal file
Binary file not shown.
Binary file not shown.
87
app/tv/libre/release/output-metadata.json
Normal file
87
app/tv/libre/release/output-metadata.json
Normal file
|
@ -0,0 +1,87 @@
|
|||
{
|
||||
"version": 3,
|
||||
"artifactType": {
|
||||
"type": "APK",
|
||||
"kind": "Directory"
|
||||
},
|
||||
"applicationId": "com.nomadics9.ananas",
|
||||
"variantName": "libreRelease",
|
||||
"elements": [
|
||||
{
|
||||
"type": "ONE_OF_MANY",
|
||||
"filters": [
|
||||
{
|
||||
"filterType": "ABI",
|
||||
"value": "armeabi-v7a"
|
||||
}
|
||||
],
|
||||
"attributes": [],
|
||||
"versionCode": 6,
|
||||
"versionName": "0.14.2",
|
||||
"outputFile": "tv-libre-armeabi-v7a-release.apk"
|
||||
},
|
||||
{
|
||||
"type": "ONE_OF_MANY",
|
||||
"filters": [
|
||||
{
|
||||
"filterType": "ABI",
|
||||
"value": "x86"
|
||||
}
|
||||
],
|
||||
"attributes": [],
|
||||
"versionCode": 6,
|
||||
"versionName": "0.14.2",
|
||||
"outputFile": "tv-libre-x86-release.apk"
|
||||
},
|
||||
{
|
||||
"type": "ONE_OF_MANY",
|
||||
"filters": [
|
||||
{
|
||||
"filterType": "ABI",
|
||||
"value": "arm64-v8a"
|
||||
}
|
||||
],
|
||||
"attributes": [],
|
||||
"versionCode": 6,
|
||||
"versionName": "0.14.2",
|
||||
"outputFile": "tv-libre-arm64-v8a-release.apk"
|
||||
},
|
||||
{
|
||||
"type": "ONE_OF_MANY",
|
||||
"filters": [
|
||||
{
|
||||
"filterType": "ABI",
|
||||
"value": "x86_64"
|
||||
}
|
||||
],
|
||||
"attributes": [],
|
||||
"versionCode": 6,
|
||||
"versionName": "0.14.2",
|
||||
"outputFile": "tv-libre-x86_64-release.apk"
|
||||
}
|
||||
],
|
||||
"elementType": "File",
|
||||
"baselineProfiles": [
|
||||
{
|
||||
"minApi": 28,
|
||||
"maxApi": 30,
|
||||
"baselineProfiles": [
|
||||
"baselineProfiles/1/tv-libre-armeabi-v7a-release.dm",
|
||||
"baselineProfiles/1/tv-libre-x86-release.dm",
|
||||
"baselineProfiles/1/tv-libre-arm64-v8a-release.dm",
|
||||
"baselineProfiles/1/tv-libre-x86_64-release.dm"
|
||||
]
|
||||
},
|
||||
{
|
||||
"minApi": 31,
|
||||
"maxApi": 2147483647,
|
||||
"baselineProfiles": [
|
||||
"baselineProfiles/0/tv-libre-armeabi-v7a-release.dm",
|
||||
"baselineProfiles/0/tv-libre-x86-release.dm",
|
||||
"baselineProfiles/0/tv-libre-arm64-v8a-release.dm",
|
||||
"baselineProfiles/0/tv-libre-x86_64-release.dm"
|
||||
]
|
||||
}
|
||||
],
|
||||
"minSdkVersionForDexing": 28
|
||||
}
|
Binary file not shown.
Binary file not shown.
BIN
app/tv/libre/staging/baselineProfiles/0/tv-libre-x86-staging.dm
Normal file
BIN
app/tv/libre/staging/baselineProfiles/0/tv-libre-x86-staging.dm
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
app/tv/libre/staging/baselineProfiles/1/tv-libre-x86-staging.dm
Normal file
BIN
app/tv/libre/staging/baselineProfiles/1/tv-libre-x86-staging.dm
Normal file
Binary file not shown.
Binary file not shown.
87
app/tv/libre/staging/output-metadata.json
Normal file
87
app/tv/libre/staging/output-metadata.json
Normal file
|
@ -0,0 +1,87 @@
|
|||
{
|
||||
"version": 3,
|
||||
"artifactType": {
|
||||
"type": "APK",
|
||||
"kind": "Directory"
|
||||
},
|
||||
"applicationId": "com.nomadics9.ananas.staging",
|
||||
"variantName": "libreStaging",
|
||||
"elements": [
|
||||
{
|
||||
"type": "ONE_OF_MANY",
|
||||
"filters": [
|
||||
{
|
||||
"filterType": "ABI",
|
||||
"value": "armeabi-v7a"
|
||||
}
|
||||
],
|
||||
"attributes": [],
|
||||
"versionCode": 1,
|
||||
"versionName": "0.14.2",
|
||||
"outputFile": "tv-libre-armeabi-v7a-staging.apk"
|
||||
},
|
||||
{
|
||||
"type": "ONE_OF_MANY",
|
||||
"filters": [
|
||||
{
|
||||
"filterType": "ABI",
|
||||
"value": "x86_64"
|
||||
}
|
||||
],
|
||||
"attributes": [],
|
||||
"versionCode": 1,
|
||||
"versionName": "0.14.2",
|
||||
"outputFile": "tv-libre-x86_64-staging.apk"
|
||||
},
|
||||
{
|
||||
"type": "ONE_OF_MANY",
|
||||
"filters": [
|
||||
{
|
||||
"filterType": "ABI",
|
||||
"value": "x86"
|
||||
}
|
||||
],
|
||||
"attributes": [],
|
||||
"versionCode": 1,
|
||||
"versionName": "0.14.2",
|
||||
"outputFile": "tv-libre-x86-staging.apk"
|
||||
},
|
||||
{
|
||||
"type": "ONE_OF_MANY",
|
||||
"filters": [
|
||||
{
|
||||
"filterType": "ABI",
|
||||
"value": "arm64-v8a"
|
||||
}
|
||||
],
|
||||
"attributes": [],
|
||||
"versionCode": 1,
|
||||
"versionName": "0.14.2",
|
||||
"outputFile": "tv-libre-arm64-v8a-staging.apk"
|
||||
}
|
||||
],
|
||||
"elementType": "File",
|
||||
"baselineProfiles": [
|
||||
{
|
||||
"minApi": 28,
|
||||
"maxApi": 30,
|
||||
"baselineProfiles": [
|
||||
"baselineProfiles/1/tv-libre-armeabi-v7a-staging.dm",
|
||||
"baselineProfiles/1/tv-libre-x86_64-staging.dm",
|
||||
"baselineProfiles/1/tv-libre-x86-staging.dm",
|
||||
"baselineProfiles/1/tv-libre-arm64-v8a-staging.dm"
|
||||
]
|
||||
},
|
||||
{
|
||||
"minApi": 31,
|
||||
"maxApi": 2147483647,
|
||||
"baselineProfiles": [
|
||||
"baselineProfiles/0/tv-libre-armeabi-v7a-staging.dm",
|
||||
"baselineProfiles/0/tv-libre-x86_64-staging.dm",
|
||||
"baselineProfiles/0/tv-libre-x86-staging.dm",
|
||||
"baselineProfiles/0/tv-libre-arm64-v8a-staging.dm"
|
||||
]
|
||||
}
|
||||
],
|
||||
"minSdkVersionForDexing": 28
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin
|
||||
package com.nomadics9.ananas
|
||||
|
||||
import android.app.Application
|
||||
import coil.ImageLoader
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin
|
||||
package com.nomadics9.ananas
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
|
@ -6,11 +6,11 @@ import androidx.activity.compose.setContent
|
|||
import androidx.activity.viewModels
|
||||
import com.ramcosta.composedestinations.DestinationsNavHost
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.database.ServerDatabaseDao
|
||||
import dev.jdtech.jellyfin.destinations.AddServerScreenDestination
|
||||
import dev.jdtech.jellyfin.destinations.LoginScreenDestination
|
||||
import dev.jdtech.jellyfin.ui.theme.FindroidTheme
|
||||
import dev.jdtech.jellyfin.viewmodels.MainViewModel
|
||||
import com.nomadics9.ananas.database.ServerDatabaseDao
|
||||
import com.nomadics9.ananas.destinations.AddServerScreenDestination
|
||||
import com.nomadics9.ananas.destinations.LoginScreenDestination
|
||||
import com.nomadics9.ananas.ui.theme.FindroidTheme
|
||||
import com.nomadics9.ananas.viewmodels.MainViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin
|
||||
package com.nomadics9.ananas
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.WindowManager
|
||||
|
@ -9,11 +9,11 @@ import com.ramcosta.composedestinations.annotation.ActivityDestination
|
|||
import com.ramcosta.composedestinations.manualcomposablecalls.composable
|
||||
import com.ramcosta.composedestinations.scope.resultRecipient
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.destinations.PlayerActivityDestination
|
||||
import dev.jdtech.jellyfin.destinations.PlayerScreenDestination
|
||||
import dev.jdtech.jellyfin.models.PlayerItem
|
||||
import dev.jdtech.jellyfin.ui.PlayerScreen
|
||||
import dev.jdtech.jellyfin.ui.theme.FindroidTheme
|
||||
import com.nomadics9.ananas.destinations.PlayerActivityDestination
|
||||
import com.nomadics9.ananas.destinations.PlayerScreenDestination
|
||||
import com.nomadics9.ananas.models.PlayerItem
|
||||
import com.nomadics9.ananas.ui.PlayerScreen
|
||||
import com.nomadics9.ananas.ui.theme.FindroidTheme
|
||||
|
||||
data class PlayerActivityNavArgs(
|
||||
val items: ArrayList<PlayerItem>,
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.ui
|
||||
package com.nomadics9.ananas.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
|
@ -38,13 +38,13 @@ import androidx.tv.material3.MaterialTheme
|
|||
import androidx.tv.material3.Text
|
||||
import com.ramcosta.composedestinations.annotation.Destination
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
import dev.jdtech.jellyfin.destinations.LoginScreenDestination
|
||||
import dev.jdtech.jellyfin.ui.theme.FindroidTheme
|
||||
import dev.jdtech.jellyfin.ui.theme.spacings
|
||||
import dev.jdtech.jellyfin.utils.ObserveAsEvents
|
||||
import dev.jdtech.jellyfin.viewmodels.AddServerEvent
|
||||
import dev.jdtech.jellyfin.viewmodels.AddServerViewModel
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.destinations.LoginScreenDestination
|
||||
import com.nomadics9.ananas.ui.theme.FindroidTheme
|
||||
import com.nomadics9.ananas.ui.theme.spacings
|
||||
import com.nomadics9.ananas.utils.ObserveAsEvents
|
||||
import com.nomadics9.ananas.viewmodels.AddServerEvent
|
||||
import com.nomadics9.ananas.viewmodels.AddServerViewModel
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
@Destination
|
||||
@Composable
|
||||
|
@ -115,7 +115,7 @@ private fun AddServerScreenLayout(
|
|||
},
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
autoCorrectEnabled = false,
|
||||
autoCorrect = false,
|
||||
keyboardType = KeyboardType.Uri,
|
||||
imeAction = ImeAction.Go,
|
||||
),
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.ui
|
||||
package com.nomadics9.ananas.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
|
@ -6,9 +6,6 @@ import androidx.compose.foundation.layout.Spacer
|
|||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
|
@ -22,28 +19,31 @@ import androidx.compose.ui.focus.focusRequester
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.tv.foundation.lazy.list.TvLazyColumn
|
||||
import androidx.tv.foundation.lazy.list.TvLazyRow
|
||||
import androidx.tv.foundation.lazy.list.items
|
||||
import androidx.tv.material3.MaterialTheme
|
||||
import androidx.tv.material3.Text
|
||||
import com.ramcosta.composedestinations.annotation.Destination
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
import dev.jdtech.jellyfin.destinations.MovieScreenDestination
|
||||
import dev.jdtech.jellyfin.destinations.PlayerActivityDestination
|
||||
import dev.jdtech.jellyfin.destinations.ShowScreenDestination
|
||||
import dev.jdtech.jellyfin.models.FindroidEpisode
|
||||
import dev.jdtech.jellyfin.models.FindroidItem
|
||||
import dev.jdtech.jellyfin.models.FindroidMovie
|
||||
import dev.jdtech.jellyfin.models.FindroidShow
|
||||
import dev.jdtech.jellyfin.models.HomeItem
|
||||
import dev.jdtech.jellyfin.ui.components.Direction
|
||||
import dev.jdtech.jellyfin.ui.components.ItemCard
|
||||
import dev.jdtech.jellyfin.ui.dummy.dummyHomeItems
|
||||
import dev.jdtech.jellyfin.ui.theme.FindroidTheme
|
||||
import dev.jdtech.jellyfin.ui.theme.spacings
|
||||
import dev.jdtech.jellyfin.utils.ObserveAsEvents
|
||||
import dev.jdtech.jellyfin.viewmodels.HomeViewModel
|
||||
import dev.jdtech.jellyfin.viewmodels.PlayerItemsEvent
|
||||
import dev.jdtech.jellyfin.viewmodels.PlayerViewModel
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.destinations.MovieScreenDestination
|
||||
import com.nomadics9.ananas.destinations.PlayerActivityDestination
|
||||
import com.nomadics9.ananas.destinations.ShowScreenDestination
|
||||
import com.nomadics9.ananas.models.FindroidEpisode
|
||||
import com.nomadics9.ananas.models.FindroidItem
|
||||
import com.nomadics9.ananas.models.FindroidMovie
|
||||
import com.nomadics9.ananas.models.FindroidShow
|
||||
import com.nomadics9.ananas.models.HomeItem
|
||||
import com.nomadics9.ananas.ui.components.Direction
|
||||
import com.nomadics9.ananas.ui.components.ItemCard
|
||||
import com.nomadics9.ananas.ui.dummy.dummyHomeItems
|
||||
import com.nomadics9.ananas.ui.theme.FindroidTheme
|
||||
import com.nomadics9.ananas.ui.theme.spacings
|
||||
import com.nomadics9.ananas.utils.ObserveAsEvents
|
||||
import com.nomadics9.ananas.viewmodels.HomeViewModel
|
||||
import com.nomadics9.ananas.viewmodels.PlayerItemsEvent
|
||||
import com.nomadics9.ananas.viewmodels.PlayerViewModel
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
@Destination
|
||||
@Composable
|
||||
|
@ -107,7 +107,7 @@ private fun HomeScreenLayout(
|
|||
}
|
||||
else -> Unit
|
||||
}
|
||||
LazyColumn(
|
||||
TvLazyColumn(
|
||||
contentPadding = PaddingValues(bottom = MaterialTheme.spacings.large),
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
|
@ -122,7 +122,7 @@ private fun HomeScreenLayout(
|
|||
modifier = Modifier.padding(start = MaterialTheme.spacings.large),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(MaterialTheme.spacings.medium))
|
||||
LazyRow(
|
||||
TvLazyRow(
|
||||
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.spacings.default),
|
||||
contentPadding = PaddingValues(horizontal = MaterialTheme.spacings.large),
|
||||
) {
|
||||
|
@ -145,7 +145,7 @@ private fun HomeScreenLayout(
|
|||
modifier = Modifier.padding(start = MaterialTheme.spacings.large),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(MaterialTheme.spacings.medium))
|
||||
LazyRow(
|
||||
TvLazyRow(
|
||||
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.spacings.default),
|
||||
contentPadding = PaddingValues(horizontal = MaterialTheme.spacings.large),
|
||||
) {
|
|
@ -1,10 +1,7 @@
|
|||
package dev.jdtech.jellyfin.ui
|
||||
package com.nomadics9.ananas.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
|
@ -17,18 +14,21 @@ import androidx.compose.ui.focus.FocusRequester
|
|||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.tv.foundation.lazy.grid.TvGridCells
|
||||
import androidx.tv.foundation.lazy.grid.TvLazyVerticalGrid
|
||||
import androidx.tv.foundation.lazy.grid.items
|
||||
import androidx.tv.material3.MaterialTheme
|
||||
import com.ramcosta.composedestinations.annotation.Destination
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
import dev.jdtech.jellyfin.destinations.LibraryScreenDestination
|
||||
import dev.jdtech.jellyfin.models.CollectionType
|
||||
import dev.jdtech.jellyfin.models.FindroidCollection
|
||||
import dev.jdtech.jellyfin.ui.components.Direction
|
||||
import dev.jdtech.jellyfin.ui.components.ItemCard
|
||||
import dev.jdtech.jellyfin.ui.dummy.dummyCollections
|
||||
import dev.jdtech.jellyfin.ui.theme.FindroidTheme
|
||||
import dev.jdtech.jellyfin.ui.theme.spacings
|
||||
import dev.jdtech.jellyfin.viewmodels.MediaViewModel
|
||||
import com.nomadics9.ananas.destinations.LibraryScreenDestination
|
||||
import com.nomadics9.ananas.models.CollectionType
|
||||
import com.nomadics9.ananas.models.FindroidCollection
|
||||
import com.nomadics9.ananas.ui.components.Direction
|
||||
import com.nomadics9.ananas.ui.components.ItemCard
|
||||
import com.nomadics9.ananas.ui.dummy.dummyCollections
|
||||
import com.nomadics9.ananas.ui.theme.FindroidTheme
|
||||
import com.nomadics9.ananas.ui.theme.spacings
|
||||
import com.nomadics9.ananas.viewmodels.MediaViewModel
|
||||
import java.util.UUID
|
||||
|
||||
@Destination
|
||||
|
@ -72,8 +72,8 @@ private fun LibrariesScreenLayout(
|
|||
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
|
||||
LazyVerticalGrid(
|
||||
columns = GridCells.Fixed(3),
|
||||
TvLazyVerticalGrid(
|
||||
columns = TvGridCells.Fixed(3),
|
||||
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.spacings.large),
|
||||
verticalArrangement = Arrangement.spacedBy(MaterialTheme.spacings.large),
|
||||
contentPadding = PaddingValues(
|
|
@ -1,11 +1,8 @@
|
|||
package dev.jdtech.jellyfin.ui
|
||||
package com.nomadics9.ananas.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.GridItemSpan
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
|
@ -18,24 +15,27 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import androidx.tv.foundation.lazy.grid.TvGridCells
|
||||
import androidx.tv.foundation.lazy.grid.TvGridItemSpan
|
||||
import androidx.tv.foundation.lazy.grid.TvLazyVerticalGrid
|
||||
import androidx.tv.material3.MaterialTheme
|
||||
import androidx.tv.material3.Text
|
||||
import com.ramcosta.composedestinations.annotation.Destination
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
import dev.jdtech.jellyfin.destinations.LibraryScreenDestination
|
||||
import dev.jdtech.jellyfin.destinations.MovieScreenDestination
|
||||
import dev.jdtech.jellyfin.destinations.ShowScreenDestination
|
||||
import dev.jdtech.jellyfin.models.CollectionType
|
||||
import dev.jdtech.jellyfin.models.FindroidFolder
|
||||
import dev.jdtech.jellyfin.models.FindroidItem
|
||||
import dev.jdtech.jellyfin.models.FindroidMovie
|
||||
import dev.jdtech.jellyfin.models.FindroidShow
|
||||
import dev.jdtech.jellyfin.ui.components.Direction
|
||||
import dev.jdtech.jellyfin.ui.components.ItemCard
|
||||
import dev.jdtech.jellyfin.ui.dummy.dummyMovies
|
||||
import dev.jdtech.jellyfin.ui.theme.FindroidTheme
|
||||
import dev.jdtech.jellyfin.ui.theme.spacings
|
||||
import dev.jdtech.jellyfin.viewmodels.LibraryViewModel
|
||||
import com.nomadics9.ananas.destinations.LibraryScreenDestination
|
||||
import com.nomadics9.ananas.destinations.MovieScreenDestination
|
||||
import com.nomadics9.ananas.destinations.ShowScreenDestination
|
||||
import com.nomadics9.ananas.models.CollectionType
|
||||
import com.nomadics9.ananas.models.FindroidFolder
|
||||
import com.nomadics9.ananas.models.FindroidItem
|
||||
import com.nomadics9.ananas.models.FindroidMovie
|
||||
import com.nomadics9.ananas.models.FindroidShow
|
||||
import com.nomadics9.ananas.ui.components.Direction
|
||||
import com.nomadics9.ananas.ui.components.ItemCard
|
||||
import com.nomadics9.ananas.ui.dummy.dummyMovies
|
||||
import com.nomadics9.ananas.ui.theme.FindroidTheme
|
||||
import com.nomadics9.ananas.ui.theme.spacings
|
||||
import com.nomadics9.ananas.viewmodels.LibraryViewModel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import java.util.UUID
|
||||
|
@ -86,8 +86,8 @@ private fun LibraryScreenLayout(
|
|||
is LibraryViewModel.UiState.Loading -> Text(text = "LOADING")
|
||||
is LibraryViewModel.UiState.Normal -> {
|
||||
val items = uiState.items.collectAsLazyPagingItems()
|
||||
LazyVerticalGrid(
|
||||
columns = GridCells.Fixed(5),
|
||||
TvLazyVerticalGrid(
|
||||
columns = TvGridCells.Fixed(5),
|
||||
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.spacings.default),
|
||||
verticalArrangement = Arrangement.spacedBy(MaterialTheme.spacings.default),
|
||||
contentPadding = PaddingValues(horizontal = MaterialTheme.spacings.default * 2, vertical = MaterialTheme.spacings.large),
|
||||
|
@ -95,7 +95,7 @@ private fun LibraryScreenLayout(
|
|||
.fillMaxSize()
|
||||
.focusRequester(focusRequester),
|
||||
) {
|
||||
item(span = { GridItemSpan(this.maxLineSpan) }) {
|
||||
item(span = { TvGridItemSpan(this.maxLineSpan) }) {
|
||||
Text(
|
||||
text = libraryName,
|
||||
style = MaterialTheme.typography.displayMedium,
|
|
@ -1,4 +1,4 @@
|
|||
package dev.jdtech.jellyfin.ui
|
||||
package com.nomadics9.ananas.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
|
@ -41,15 +41,15 @@ import androidx.tv.material3.Text
|
|||
import com.ramcosta.composedestinations.annotation.Destination
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
import com.ramcosta.composedestinations.navigation.popUpTo
|
||||
import dev.jdtech.jellyfin.NavGraphs
|
||||
import dev.jdtech.jellyfin.destinations.MainScreenDestination
|
||||
import dev.jdtech.jellyfin.models.UiText
|
||||
import dev.jdtech.jellyfin.ui.theme.FindroidTheme
|
||||
import dev.jdtech.jellyfin.ui.theme.spacings
|
||||
import dev.jdtech.jellyfin.utils.ObserveAsEvents
|
||||
import dev.jdtech.jellyfin.viewmodels.LoginEvent
|
||||
import dev.jdtech.jellyfin.viewmodels.LoginViewModel
|
||||
import dev.jdtech.jellyfin.core.R as CoreR
|
||||
import com.nomadics9.ananas.NavGraphs
|
||||
import com.nomadics9.ananas.destinations.MainScreenDestination
|
||||
import com.nomadics9.ananas.models.UiText
|
||||
import com.nomadics9.ananas.ui.theme.FindroidTheme
|
||||
import com.nomadics9.ananas.ui.theme.spacings
|
||||
import com.nomadics9.ananas.utils.ObserveAsEvents
|
||||
import com.nomadics9.ananas.viewmodels.LoginEvent
|
||||
import com.nomadics9.ananas.viewmodels.LoginViewModel
|
||||
import com.nomadics9.ananas.core.R as CoreR
|
||||
|
||||
@Destination
|
||||
@Composable
|
||||
|
@ -152,7 +152,7 @@ private fun LoginScreenLayout(
|
|||
label = { Text(text = stringResource(id = CoreR.string.edit_text_username_hint)) },
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
autoCorrectEnabled = false,
|
||||
autoCorrect = false,
|
||||
keyboardType = KeyboardType.Text,
|
||||
imeAction = ImeAction.Next,
|
||||
),
|
||||
|
@ -175,7 +175,7 @@ private fun LoginScreenLayout(
|
|||
label = { Text(text = stringResource(id = CoreR.string.edit_text_password_hint)) },
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
autoCorrectEnabled = false,
|
||||
autoCorrect = false,
|
||||
keyboardType = KeyboardType.Password,
|
||||
imeAction = ImeAction.Go,
|
||||
),
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue