diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 00000000..55b65a30 --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,65 @@ +name: Publish + +on: + push: + tags: + - v* + +jobs: + publish: + name: Publish + runs-on: ubuntu-22.04 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.3.0 + bundler-cache: true + + - name: Validate Gradle Wrapper + uses: gradle/wrapper-validation-action@v2 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: 17 + distribution: temurin + + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v3 + + - name: Decode keystore file + uses: timheuer/base64-to-file@v1 + id: findroid_keystore + with: + fileName: 'findroid-keystore.jks' + encodedString: ${{ secrets.FINDROID_KEYSTORE }} + + - name: Decode Play API credentials file + uses: timheuer/base64-to-file@v1 + id: findroid_play_api_credentials + with: + fileName: 'findroid-play-api-credentials.json' + encodedString: ${{ secrets.FINDROID_PLAY_API_CREDENTIALS }} + + - name: Build and publish + run: bundle exec fastlane publish + env: + FINDROID_KEYSTORE: ${{ steps.findroid_keystore.outputs.filePath }} + FINDROID_KEYSTORE_PASSWORD: ${{ secrets.FINDROID_KEYSTORE_PASSWORD }} + FINDROID_KEY_ALIAS: ${{ secrets.FINDROID_KEY_ALIAS }} + FINDROID_KEY_PASSWORD: ${{ secrets.FINDROID_KEY_PASSWORD }} + FINDROID_PLAY_API_CREDENTIALS: ${{ steps.findroid_play_api_credentials.outputs.filePath }} + + - name: Create release + uses: softprops/action-gh-release@v2 + with: + draft: true + files: | + ./app/phone/build/outputs/apk/libre/release/findroid-${{ github.ref_name }}-libre-arm64-v8a.apk + ./app/phone/build/outputs/apk/libre/release/findroid-${{ github.ref_name }}-libre-armeabi-v7a.apk + ./app/phone/build/outputs/apk/libre/release/findroid-${{ github.ref_name }}-libre-x86_64.apk + ./app/phone/build/outputs/apk/libre/release/findroid-${{ github.ref_name }}-libre-x86.apk diff --git a/.gitignore b/.gitignore index 16dcd122..69c4d737 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,10 @@ render.experimental.xml google-services.json # Android Profiling -*.hprof \ No newline at end of file +*.hprof + +# Fastlane +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots +fastlane/test_output diff --git a/Gemfile b/Gemfile new file mode 100644 index 00000000..adc90d98 --- /dev/null +++ b/Gemfile @@ -0,0 +1,3 @@ +source "https://rubygems.org" + +gem "fastlane" \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 00000000..712d595b --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,218 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.7) + base64 + nkf + rexml + addressable (2.8.6) + public_suffix (>= 2.0.2, < 6.0) + artifactory (3.0.17) + atomos (0.1.3) + aws-eventstream (1.3.0) + aws-partitions (1.913.0) + aws-sdk-core (3.191.6) + aws-eventstream (~> 1, >= 1.3.0) + aws-partitions (~> 1, >= 1.651.0) + aws-sigv4 (~> 1.8) + jmespath (~> 1, >= 1.6.1) + aws-sdk-kms (1.79.0) + aws-sdk-core (~> 3, >= 3.191.0) + aws-sigv4 (~> 1.1) + aws-sdk-s3 (1.146.1) + aws-sdk-core (~> 3, >= 3.191.0) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.8) + aws-sigv4 (1.8.0) + aws-eventstream (~> 1, >= 1.0.2) + babosa (1.0.4) + base64 (0.2.0) + claide (1.1.0) + colored (1.2) + colored2 (3.1.2) + commander (4.6.0) + highline (~> 2.0.0) + declarative (0.0.20) + digest-crc (0.6.5) + rake (>= 12.0.0, < 14.0.0) + domain_name (0.6.20240107) + dotenv (2.8.1) + emoji_regex (3.2.3) + excon (0.110.0) + faraday (1.10.3) + faraday-em_http (~> 1.0) + faraday-em_synchrony (~> 1.0) + faraday-excon (~> 1.1) + faraday-httpclient (~> 1.0) + faraday-multipart (~> 1.0) + faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.0) + faraday-patron (~> 1.0) + faraday-rack (~> 1.0) + faraday-retry (~> 1.0) + ruby2_keywords (>= 0.0.4) + faraday-cookie_jar (0.0.7) + faraday (>= 0.8.0) + http-cookie (~> 1.0.0) + faraday-em_http (1.0.0) + faraday-em_synchrony (1.0.0) + faraday-excon (1.1.0) + faraday-httpclient (1.0.1) + faraday-multipart (1.0.4) + multipart-post (~> 2) + faraday-net_http (1.0.1) + faraday-net_http_persistent (1.2.0) + faraday-patron (1.0.0) + faraday-rack (1.0.0) + faraday-retry (1.0.3) + faraday_middleware (1.2.0) + faraday (~> 1.0) + fastimage (2.3.1) + fastlane (2.220.0) + CFPropertyList (>= 2.3, < 4.0.0) + addressable (>= 2.8, < 3.0.0) + artifactory (~> 3.0) + aws-sdk-s3 (~> 1.0) + babosa (>= 1.0.3, < 2.0.0) + bundler (>= 1.12.0, < 3.0.0) + colored (~> 1.2) + commander (~> 4.6) + dotenv (>= 2.1.1, < 3.0.0) + emoji_regex (>= 0.1, < 4.0) + excon (>= 0.71.0, < 1.0.0) + faraday (~> 1.0) + faraday-cookie_jar (~> 0.0.6) + faraday_middleware (~> 1.0) + fastimage (>= 2.1.0, < 3.0.0) + gh_inspector (>= 1.1.2, < 2.0.0) + google-apis-androidpublisher_v3 (~> 0.3) + google-apis-playcustomapp_v1 (~> 0.1) + google-cloud-env (>= 1.6.0, < 2.0.0) + google-cloud-storage (~> 1.31) + highline (~> 2.0) + http-cookie (~> 1.0.5) + json (< 3.0.0) + jwt (>= 2.1.0, < 3) + mini_magick (>= 4.9.4, < 5.0.0) + multipart-post (>= 2.0.0, < 3.0.0) + naturally (~> 2.2) + optparse (>= 0.1.1, < 1.0.0) + plist (>= 3.1.0, < 4.0.0) + rubyzip (>= 2.0.0, < 3.0.0) + security (= 0.1.5) + simctl (~> 1.6.3) + terminal-notifier (>= 2.0.0, < 3.0.0) + terminal-table (~> 3) + tty-screen (>= 0.6.3, < 1.0.0) + tty-spinner (>= 0.8.0, < 1.0.0) + word_wrap (~> 1.0.0) + xcodeproj (>= 1.13.0, < 2.0.0) + xcpretty (~> 0.3.0) + xcpretty-travis-formatter (>= 0.0.3, < 2.0.0) + gh_inspector (1.1.3) + google-apis-androidpublisher_v3 (0.54.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-core (0.11.3) + addressable (~> 2.5, >= 2.5.1) + googleauth (>= 0.16.2, < 2.a) + httpclient (>= 2.8.1, < 3.a) + mini_mime (~> 1.0) + representable (~> 3.0) + retriable (>= 2.0, < 4.a) + rexml + google-apis-iamcredentials_v1 (0.17.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-playcustomapp_v1 (0.13.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-storage_v1 (0.31.0) + google-apis-core (>= 0.11.0, < 2.a) + google-cloud-core (1.7.0) + google-cloud-env (>= 1.0, < 3.a) + google-cloud-errors (~> 1.0) + google-cloud-env (1.6.0) + faraday (>= 0.17.3, < 3.0) + google-cloud-errors (1.4.0) + google-cloud-storage (1.47.0) + addressable (~> 2.8) + digest-crc (~> 0.4) + google-apis-iamcredentials_v1 (~> 0.1) + google-apis-storage_v1 (~> 0.31.0) + google-cloud-core (~> 1.6) + googleauth (>= 0.16.2, < 2.a) + mini_mime (~> 1.0) + googleauth (1.8.1) + faraday (>= 0.17.3, < 3.a) + jwt (>= 1.4, < 3.0) + multi_json (~> 1.11) + os (>= 0.9, < 2.0) + signet (>= 0.16, < 2.a) + highline (2.0.3) + http-cookie (1.0.5) + domain_name (~> 0.5) + httpclient (2.8.3) + jmespath (1.6.2) + json (2.7.2) + jwt (2.8.1) + base64 + mini_magick (4.12.0) + mini_mime (1.1.5) + multi_json (1.15.0) + multipart-post (2.4.0) + nanaimo (0.3.0) + naturally (2.2.1) + nkf (0.2.0) + optparse (0.4.0) + os (1.1.4) + plist (3.7.1) + public_suffix (5.0.5) + rake (13.2.1) + representable (3.2.0) + declarative (< 0.1.0) + trailblazer-option (>= 0.1.1, < 0.2.0) + uber (< 0.2.0) + retriable (3.1.2) + rexml (3.2.6) + rouge (2.0.7) + ruby2_keywords (0.0.5) + rubyzip (2.3.2) + security (0.1.5) + signet (0.19.0) + addressable (~> 2.8) + faraday (>= 0.17.5, < 3.a) + jwt (>= 1.5, < 3.0) + multi_json (~> 1.10) + simctl (1.6.10) + CFPropertyList + naturally + terminal-notifier (2.0.0) + terminal-table (3.0.2) + unicode-display_width (>= 1.1.1, < 3) + trailblazer-option (0.1.2) + tty-cursor (0.7.1) + tty-screen (0.8.2) + tty-spinner (0.9.3) + tty-cursor (~> 0.7) + uber (0.1.0) + unicode-display_width (2.5.0) + word_wrap (1.0.0) + xcodeproj (1.24.0) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.3.0) + rexml (~> 3.2.4) + xcpretty (0.3.0) + rouge (~> 2.0.7) + xcpretty-travis-formatter (1.0.1) + xcpretty (~> 0.2, >= 0.0.7) + +PLATFORMS + ruby + x86_64-linux + +DEPENDENCIES + fastlane + +BUNDLED WITH + 2.5.4 diff --git a/README.md b/README.md index 9c7f0390..10842fa3 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ I am developing this application in my spare time. **This project is in its early stages so expect bugs.** -Get it on Google PlayAvailable at Amazon AppstoreExplore it on Huawei AppGalleryGet it on IzzyOnDroid +Get it on Google PlayAvailable at Amazon AppstoreGet it on IzzyOnDroid ## Screenshots | Home | Library | Movie | Season | Episode | @@ -29,7 +29,7 @@ I am developing this application in my spare time. - ExoPlayer - Video codecs: H.263, H.264, H.265, VP8, VP9, AV1 - Support depends on Android device - - Audio codecs: Vorbis, Opus, FLAC, ALAC, PCM, MP3, AMR-NB, AMR-WB, AAC, AC-3, E-AC-3, DTS, DTS-HD, TrueHD + - Audio codecs: Vorbis, Opus, FLAC, ALAC, PCM, MP3, AAC, AC-3, E-AC-3, DTS, DTS-HD, TrueHD - Support provided by ExoPlayer FFmpeg extension - Subtitle codecs: SRT, VTT, SSA/ASS, PGSSUB - SSA/ASS has limited styling support see [this issue](https://github.com/google/ExoPlayer/issues/8435) diff --git a/app/phone/build.gradle.kts b/app/phone/build.gradle.kts index 2782a57a..b9a5e35e 100644 --- a/app/phone/build.gradle.kts +++ b/app/phone/build.gradle.kts @@ -21,6 +21,20 @@ android { versionCode = Versions.appCode versionName = Versions.appName + + testInstrumentationRunner = "dev.jdtech.jellyfin.HiltTestRunner" + } + + applicationVariants.all { + val variant = this + variant.outputs + .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" + output.outputFileName = outputFileName + } + } } buildTypes { @@ -47,9 +61,6 @@ android { dimension = "variant" isDefault = true } - register("huawei") { - dimension = "variant" - } } splits { @@ -61,6 +72,8 @@ android { } compileOptions { + isCoreLibraryDesugaringEnabled = true + sourceCompatibility = Versions.java targetCompatibility = Versions.java } @@ -109,7 +122,14 @@ dependencies { implementation(libs.jellyfin.core) compileOnly(libs.libmpv) implementation(libs.material) + implementation(libs.media3.ffmpeg.decoder) implementation(libs.timber) - implementation(rootProject.files("libs/lib-decoder-ffmpeg-release.aar")) + coreLibraryDesugaring(libs.android.desugar.jdk) + + androidTestImplementation(libs.androidx.room.runtime) + androidTestImplementation(libs.junit) + androidTestImplementation(libs.bundles.androidx.test) + androidTestImplementation(libs.hilt.android.testing) + kspTest(libs.hilt.android.compiler) } diff --git a/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/HiltTestRunner.kt b/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/HiltTestRunner.kt new file mode 100644 index 00000000..e7f52dcb --- /dev/null +++ b/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/HiltTestRunner.kt @@ -0,0 +1,16 @@ +package dev.jdtech.jellyfin + +import android.app.Application +import android.content.Context +import androidx.test.runner.AndroidJUnitRunner +import dagger.hilt.android.testing.HiltTestApplication + +class HiltTestRunner : AndroidJUnitRunner() { + override fun newApplication( + cl: ClassLoader?, + className: String?, + context: Context?, + ): Application { + return super.newApplication(cl, HiltTestApplication::class.java.name, context) + } +} diff --git a/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/MainActivityTest.kt b/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/MainActivityTest.kt new file mode 100644 index 00000000..486b6759 --- /dev/null +++ b/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/MainActivityTest.kt @@ -0,0 +1,95 @@ +package dev.jdtech.jellyfin + +import android.util.Log +import androidx.hilt.work.HiltWorkerFactory +import androidx.test.core.app.launchActivity +import androidx.test.espresso.Espresso +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.action.ViewActions.closeSoftKeyboard +import androidx.test.espresso.action.ViewActions.typeText +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.isEnabled +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText +import androidx.test.platform.app.InstrumentationRegistry +import androidx.work.Configuration +import androidx.work.testing.SynchronousExecutor +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 org.hamcrest.CoreMatchers.allOf +import org.hamcrest.CoreMatchers.not +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import javax.inject.Inject + +@HiltAndroidTest +@UninstallModules(DatabaseModule::class) +class MainActivityTest { + @get:Rule + var hiltRule = HiltAndroidRule(this) + + @Inject + lateinit var workerFactory: HiltWorkerFactory + + @Before + fun setUp() { + hiltRule.inject() + + val context = InstrumentationRegistry.getInstrumentation().targetContext + val config = Configuration.Builder() + .setWorkerFactory(workerFactory) + .setMinimumLoggingLevel(Log.DEBUG) + .setExecutor(SynchronousExecutor()) + .build() + + // Initialize WorkManager for instrumentation tests. + WorkManagerTestInitHelper.initializeTestWorkManager(context, config) + } + + @Test + fun testMainFlow() { + launchActivity().use { + // Wait for the app to load + waitForElement(allOf(withId(R.id.edit_text_server_address), isDisplayed())) + + // Connect to demo server + onView(withId(R.id.edit_text_server_address)).perform(typeText("https://demo.jellyfin.org/stable"), closeSoftKeyboard()) + onView(withId(R.id.button_connect)).perform(click()) + + // Connecting to the server + waitForElement(allOf(withId(R.id.edit_text_username), isDisplayed())) + + // Login + onView(withId(R.id.edit_text_username)).perform(typeText("demo"), closeSoftKeyboard()) + onView(withId(R.id.button_login)).perform(click()) + + // Navigate to My media + waitForElement(allOf(withText("Continue Watching"), isDisplayed())) + onView(withId(R.id.mediaFragment)).perform(click()) + + // Navigate to movies + waitForElement(allOf(withText("Movies"), isDisplayed())) + onView(withText("Movies")).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())) + onView(withId(R.id.play_button)).perform(click()) + + // Wait for movie to start playing + waitForElement(allOf(withId(androidx.media3.ui.R.id.exo_buffering), isDisplayed())) + waitForElement(allOf(withId(androidx.media3.ui.R.id.exo_buffering), not(isDisplayed()))) + + // Navigate back + Espresso.pressBack() + } + } +} diff --git a/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/ViewPropertyChangeCallback.kt b/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/ViewPropertyChangeCallback.kt new file mode 100644 index 00000000..a3a0c8b1 --- /dev/null +++ b/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/ViewPropertyChangeCallback.kt @@ -0,0 +1,64 @@ +package dev.jdtech.jellyfin + +import android.view.View +import android.view.ViewTreeObserver +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.IdlingRegistry +import androidx.test.espresso.IdlingResource +import androidx.test.espresso.UiController +import androidx.test.espresso.ViewAction +import androidx.test.espresso.matcher.ViewMatchers.hasDescendant +import androidx.test.espresso.matcher.ViewMatchers.isRoot +import org.hamcrest.CoreMatchers +import org.hamcrest.Matcher +import org.hamcrest.StringDescription + +private class ViewPropertyChangeCallback(private val matcher: Matcher, private val view: View) : IdlingResource, ViewTreeObserver.OnDrawListener { + private lateinit var callback: IdlingResource.ResourceCallback + private var matched = false + + override fun getName() = "View property change callback" + + override fun isIdleNow() = matched + + override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback) { + this.callback = callback + } + + override fun onDraw() { + matched = matcher.matches(view) + callback.onTransitionToIdle() + } +} + +fun waitUntil(matcher: Matcher): ViewAction = object : ViewAction { + override fun getConstraints(): Matcher { + return CoreMatchers.any(View::class.java) + } + + override fun getDescription(): String { + return StringDescription().let { + matcher.describeTo(it) + "wait until: $it" + } + } + + override fun perform(uiController: UiController, view: View) { + if (!matcher.matches(view)) { + ViewPropertyChangeCallback(matcher, view).run { + try { + IdlingRegistry.getInstance().register(this) + view.viewTreeObserver.addOnDrawListener(this) + uiController.loopMainThreadUntilIdle() + } finally { + view.viewTreeObserver.removeOnDrawListener(this) + IdlingRegistry.getInstance().unregister(this) + } + } + } + } +} + +fun waitForElement(matcher: Matcher) { + onView(isRoot()).perform(waitUntil(hasDescendant(matcher))) +} diff --git a/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/di/DatabaseTestModule.kt b/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/di/DatabaseTestModule.kt new file mode 100644 index 00000000..e5a367b1 --- /dev/null +++ b/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/di/DatabaseTestModule.kt @@ -0,0 +1,29 @@ +package dev.jdtech.jellyfin.di + +import android.content.Context +import androidx.room.Room +import dagger.Module +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 javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object DatabaseTestModule { + @Singleton + @Provides + fun provideServerDatabaseDao(@ApplicationContext app: Context): ServerDatabaseDao { + return Room.inMemoryDatabaseBuilder( + app.applicationContext, + ServerDatabase::class.java, + ) + .fallbackToDestructiveMigration() + .allowMainThreadQueries() + .build() + .getServerDatabaseDao() + } +} diff --git a/app/phone/src/main/java/dev/jdtech/jellyfin/PlayerActivity.kt b/app/phone/src/main/java/dev/jdtech/jellyfin/PlayerActivity.kt index d8aa8293..3919b1e5 100644 --- a/app/phone/src/main/java/dev/jdtech/jellyfin/PlayerActivity.kt +++ b/app/phone/src/main/java/dev/jdtech/jellyfin/PlayerActivity.kt @@ -200,7 +200,9 @@ class PlayerActivity : BasePlayerActivity() { is PlayerEvents.NavigateBack -> finish() is PlayerEvents.IsPlayingChanged -> { if (appPreferences.playerPipGesture) { - setPictureInPictureParams(pipParams(event.isPlaying)) + try { + setPictureInPictureParams(pipParams(event.isPlaying)) + } catch (_: IllegalArgumentException) { } } } } diff --git a/app/phone/src/main/java/dev/jdtech/jellyfin/adapters/EpisodeListAdapter.kt b/app/phone/src/main/java/dev/jdtech/jellyfin/adapters/EpisodeListAdapter.kt index 4df73fbb..bddb8781 100644 --- a/app/phone/src/main/java/dev/jdtech/jellyfin/adapters/EpisodeListAdapter.kt +++ b/app/phone/src/main/java/dev/jdtech/jellyfin/adapters/EpisodeListAdapter.kt @@ -1,5 +1,6 @@ package dev.jdtech.jellyfin.adapters +import android.text.Html.fromHtml import android.util.TypedValue import android.view.LayoutInflater import android.view.View @@ -45,7 +46,7 @@ class EpisodeListAdapter( binding.root.context.getString(CoreR.string.episode_name_with_end, episode.indexNumber, episode.indexNumberEnd, episode.name) } - binding.episodeOverview.text = episode.overview + binding.episodeOverview.text = fromHtml(episode.overview, 0) if (episode.playbackPositionTicks > 0) { binding.progressBar.layoutParams.width = TypedValue.applyDimension( diff --git a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/CollectionFragment.kt b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/CollectionFragment.kt index 69b57fed..c8bc3bda 100644 --- a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/CollectionFragment.kt +++ b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/CollectionFragment.kt @@ -24,6 +24,7 @@ import dev.jdtech.jellyfin.utils.checkIfLoginRequired import dev.jdtech.jellyfin.viewmodels.CollectionViewModel import kotlinx.coroutines.launch import timber.log.Timber +import dev.jdtech.jellyfin.core.R as CoreR @AndroidEntryPoint class CollectionFragment : Fragment() { @@ -40,6 +41,8 @@ class CollectionFragment : Fragment() { ): View { binding = FragmentFavoriteBinding.inflate(inflater, container, false) + binding.noFavoritesText.text = getString(CoreR.string.collection_no_media) + binding.favoritesRecyclerView.adapter = FavoritesListAdapter { item -> navigateToMediaItem(item) } diff --git a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/EpisodeBottomSheetFragment.kt b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/EpisodeBottomSheetFragment.kt index c9c1066a..17c61caf 100644 --- a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/EpisodeBottomSheetFragment.kt +++ b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/EpisodeBottomSheetFragment.kt @@ -2,6 +2,7 @@ package dev.jdtech.jellyfin.fragments import android.app.DownloadManager import android.os.Bundle +import android.text.Html.fromHtml import android.text.format.Formatter import android.util.TypedValue import android.view.LayoutInflater @@ -285,11 +286,13 @@ class EpisodeBottomSheetFragment : BottomSheetDialogFragment() { } binding.seriesName.text = episode.seriesName - binding.overview.text = episode.overview + binding.overview.text = fromHtml(episode.overview, 0) binding.year.text = formatDateTime(episode.premiereDate) binding.playtime.text = getString(CoreR.string.runtime_minutes, episode.runtimeTicks.div(600000000)) - binding.communityRating.isVisible = episode.communityRating != null - binding.communityRating.text = episode.communityRating.toString() + episode.communityRating?.also { + binding.communityRating.text = episode.communityRating.toString() + binding.communityRating.isVisible = true + } binding.missingIcon.isVisible = false if (appPreferences.displayExtraInfo) { diff --git a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MovieFragment.kt b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MovieFragment.kt index be6d3d40..b383842f 100644 --- a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MovieFragment.kt +++ b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MovieFragment.kt @@ -4,6 +4,7 @@ import android.app.DownloadManager import android.content.Intent import android.net.Uri import android.os.Bundle +import android.text.Html.fromHtml import android.text.format.Formatter import android.view.LayoutInflater import android.view.View @@ -276,7 +277,6 @@ class MovieFragment : Fragment() { if (item.trailer != null) { binding.itemActions.trailerButton.isVisible = true } - binding.communityRating.isVisible = item.communityRating != null binding.actors.isVisible = actors.isNotEmpty() binding.itemActions.playButton.isEnabled = item.canPlay && item.sources.isNotEmpty() @@ -309,7 +309,10 @@ class MovieFragment : Fragment() { binding.playtime.text = runTime } binding.officialRating.text = item.officialRating - binding.communityRating.text = item.communityRating.toString() + item.communityRating?.also { + binding.communityRating.text = it.toString() + binding.communityRating.isVisible = true + } videoMetadata.let { with(binding) { @@ -379,7 +382,7 @@ class MovieFragment : Fragment() { binding.info.sizeGroup.isVisible = size != null } - binding.info.description.text = item.overview + binding.info.description.text = fromHtml(item.overview, 0) binding.info.genres.text = genresString binding.info.genresGroup.isVisible = item.genres.isNotEmpty() binding.info.director.text = director?.name diff --git a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/ShowFragment.kt b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/ShowFragment.kt index 21be0c63..242f4c60 100644 --- a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/ShowFragment.kt +++ b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/ShowFragment.kt @@ -3,6 +3,7 @@ package dev.jdtech.jellyfin.fragments import android.content.Intent import android.net.Uri import android.os.Bundle +import android.text.Html.fromHtml import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -170,7 +171,6 @@ class ShowFragment : Fragment() { if (item.trailer != null) { binding.itemActions.trailerButton.isVisible = true } - binding.communityRating.isVisible = item.communityRating != null binding.actors.isVisible = actors.isNotEmpty() // TODO currently the sources of a show is always empty, we need a way to check if sources are available @@ -212,9 +212,12 @@ class ShowFragment : Fragment() { binding.playtime.text = runTime } binding.officialRating.text = item.officialRating - binding.communityRating.text = item.communityRating.toString() + item.communityRating?.also { + binding.communityRating.text = item.communityRating.toString() + binding.communityRating.isVisible = true + } - binding.info.description.text = item.overview + binding.info.description.text = fromHtml(item.overview, 0) binding.info.genres.text = genresString binding.info.genresGroup.isVisible = item.genres.isNotEmpty() binding.info.director.text = director?.name diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 75c1a531..4a96003b 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -1,8 +1,8 @@ import org.gradle.api.JavaVersion object Versions { - const val appCode = 23 - const val appName = "2024.02" + const val appCode = 25 + const val appName = "0.14.2" const val compileSdk = 34 const val buildTools = "34.0.0" @@ -11,6 +11,6 @@ object Versions { val java = JavaVersion.VERSION_17 - const val composeCompiler = "1.5.10" + const val composeCompiler = "1.5.11" const val ktlint = "0.50.0" } \ No newline at end of file diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 04903fa4..33930d84 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -29,7 +29,6 @@ android { flavorDimensions += "variant" productFlavors { register("libre") - register("huawei") } compileOptions { diff --git a/core/src/huawei/res/drawable/ic_banner.xml b/core/src/huawei/res/drawable/ic_banner.xml deleted file mode 100644 index 68ab6899..00000000 --- a/core/src/huawei/res/drawable/ic_banner.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/core/src/huawei/res/drawable/ic_banner_foreground.xml b/core/src/huawei/res/drawable/ic_banner_foreground.xml deleted file mode 100644 index 29c06075..00000000 --- a/core/src/huawei/res/drawable/ic_banner_foreground.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/core/src/huawei/res/drawable/ic_launcher_foreground.xml b/core/src/huawei/res/drawable/ic_launcher_foreground.xml deleted file mode 100644 index 1cd1c375..00000000 --- a/core/src/huawei/res/drawable/ic_launcher_foreground.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - diff --git a/core/src/main/java/dev/jdtech/jellyfin/dialogs/AddServerAddressDialog.kt b/core/src/main/java/dev/jdtech/jellyfin/dialogs/AddServerAddressDialog.kt index fc10227b..d6f6183c 100644 --- a/core/src/main/java/dev/jdtech/jellyfin/dialogs/AddServerAddressDialog.kt +++ b/core/src/main/java/dev/jdtech/jellyfin/dialogs/AddServerAddressDialog.kt @@ -2,6 +2,7 @@ package dev.jdtech.jellyfin.dialogs import android.app.Dialog import android.os.Bundle +import android.text.InputType import android.widget.EditText import androidx.fragment.app.DialogFragment import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -15,13 +16,14 @@ class AddServerAddressDialog( override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val editText = EditText(this.context) editText.hint = "http://:8096" + editText.inputType = InputType.TYPE_TEXT_VARIATION_URI return activity?.let { activity -> val builder = MaterialAlertDialogBuilder(activity) builder .setTitle(getString(R.string.add_server_address)) .setView(editText) .setPositiveButton(getString(R.string.add)) { _, _ -> - viewModel.addAddress(editText.text.toString()) + viewModel.addAddress(requireContext(), editText.text.toString()) } .setNegativeButton(getString(R.string.cancel)) { _, _ -> } diff --git a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/CollectionViewModel.kt b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/CollectionViewModel.kt index 9b6ed399..a858ba70 100644 --- a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/CollectionViewModel.kt +++ b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/CollectionViewModel.kt @@ -9,6 +9,7 @@ import dev.jdtech.jellyfin.models.FavoriteSection import dev.jdtech.jellyfin.models.FindroidEpisode import dev.jdtech.jellyfin.models.FindroidMovie import dev.jdtech.jellyfin.models.FindroidShow +import dev.jdtech.jellyfin.models.SortBy import dev.jdtech.jellyfin.models.UiText import dev.jdtech.jellyfin.repository.JellyfinRepository import kotlinx.coroutines.Dispatchers @@ -39,7 +40,10 @@ constructor( _uiState.emit(UiState.Loading) try { - val items = jellyfinRepository.getItems(parentId = parentId) + val items = jellyfinRepository.getItems( + parentId = parentId, + sortBy = SortBy.RELEASE_DATE, + ) if (items.isEmpty()) { _uiState.emit(UiState.Normal(emptyList())) diff --git a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerAddressesViewModel.kt b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerAddressesViewModel.kt index 4d2bc18c..b61682dc 100644 --- a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerAddressesViewModel.kt +++ b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerAddressesViewModel.kt @@ -1,5 +1,6 @@ package dev.jdtech.jellyfin.viewmodels +import android.content.Context import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel @@ -79,11 +80,19 @@ constructor( } } - fun addAddress(address: String) { + fun addAddress(context: Context, address: String) { viewModelScope.launch(Dispatchers.IO) { - val serverAddress = ServerAddress(UUID.randomUUID(), currentServerId, address) - database.insertServerAddress(serverAddress) - loadAddresses(currentServerId) + try { + val jellyfinApi = JellyfinApi(context) + jellyfinApi.api.baseUrl = address + val systemInfo by jellyfinApi.systemApi.getPublicSystemInfo() + if (systemInfo.id != currentServerId) { + return@launch + } + val serverAddress = ServerAddress(UUID.randomUUID(), currentServerId, address) + database.insertServerAddress(serverAddress) + loadAddresses(currentServerId) + } catch (_: Exception) { } } } } diff --git a/core/src/main/res/values-de/strings.xml b/core/src/main/res/values-de/strings.xml index ae19a4aa..7c2e24ca 100644 --- a/core/src/main/res/values-de/strings.xml +++ b/core/src/main/res/values-de/strings.xml @@ -170,4 +170,21 @@ Download stoppen Download Indikator %1$d-%2$d. %3$s + Trailer anschauen + Aus Favoriten entfernen + Keine Server gefunden + Keine Benutzer gefunden + Bild-in-Bild + Bist du sicher, dass du die Server Adresse \"%1$s\" entfernen möchtest? + Server Adresse entfernen + Diese Sammlung enthält keine Medien + Maximiert starten + Video standardmäßig maximiert öffnen + Kapitelmarker + Zeige Kapitelmarker in der Zeitleiste an + Benutzer auswählen + Als angesehen markieren + Zu Favoriten hinzufügen + Kapitel Geste + Drücke lange auf der linken/rechten Seite um Kapitel zu überspringen (überschreibt die 2x-Geschwindigkeitsgesten) \ No newline at end of file diff --git a/core/src/main/res/values-es-rMX/strings.xml b/core/src/main/res/values-es-rMX/strings.xml index 5949df00..3f6eb4d6 100644 --- a/core/src/main/res/values-es-rMX/strings.xml +++ b/core/src/main/res/values-es-rMX/strings.xml @@ -172,4 +172,6 @@ Ocurrió un error al descargar ¿Está seguro de remover el servidor con dirección %1$s Remover dirección del servidor + Ésta colección no contiene elementos + Gesto para cambiar capítulos \ No newline at end of file diff --git a/core/src/main/res/values-fr/strings.xml b/core/src/main/res/values-fr/strings.xml index 012532b7..2a5b78a9 100644 --- a/core/src/main/res/values-fr/strings.xml +++ b/core/src/main/res/values-fr/strings.xml @@ -142,7 +142,7 @@ Ajouter une adresse Ajouter l\'adresse d\'un serveur Ajouter - Le plugin Jellyscrub de nicknsy doit être installé sur le serveur + Nécessite que le plugin Jellyscrub de Nicknsy soit installé sur le serveur temporaire CC Déplacement du curseur de lecture @@ -175,4 +175,21 @@ Fenêtre flottante Geste de retour à l\'accueil depuis la fenêtre flottante Lors de la lecture, utilisez le bouton d\'accueil ou la navigation gestuelle pour lancer la fenêtre flottante + Non marqué comme joué + Aucun serveur trouvé + Aucun utilisateur trouvé + Sélectionner un utilisateur + Direct TV + Ajouter aux favoris + Cette collection ne contient aucun média + Ouvrir la vidéo en plein écran par défaut + Démarrer en plein écran + Appuyer longtemps sur les côtés de l\'écran pour passer le chapitre (cela remplace le geste de vitesse 2x) + Marqueurs de chapitre + Afficher les marqueurs de chapitre sur la barre temporelle + Lecture + Geste du chapitre + Regarder la bande annonce + Marquer comme joué + Retirer des favoris \ No newline at end of file diff --git a/core/src/main/res/values-hu/strings.xml b/core/src/main/res/values-hu/strings.xml index 3fff6575..590a5dd1 100644 --- a/core/src/main/res/values-hu/strings.xml +++ b/core/src/main/res/values-hu/strings.xml @@ -30,7 +30,7 @@ Rendező Írók Szereplők & Stáb - Szezonok + Évadok Előzetes megtekintése Megjelölés megtekintettnek, vagy nem-megtekintettnek Kedvenc @@ -187,4 +187,9 @@ Előzetes megtekintése Videó megnyitása alapértelmezés szerint maximalizált módban Indítás maximalizálva + Ez a gyűjtemény nem tartalmaz médiát + Fejezet gesztus + Hosszan nyomd meg a bal / jobb oldalt a fejezetek átugrására (felülírja a 2x sebesség gesztust) + Fejezet jelölések + Fejezetjelzők megjelenítése az idősávon \ No newline at end of file diff --git a/core/src/main/res/values-pt/strings.xml b/core/src/main/res/values-pt/strings.xml index 0adc48c4..c1e824ec 100644 --- a/core/src/main/res/values-pt/strings.xml +++ b/core/src/main/res/values-pt/strings.xml @@ -2,14 +2,14 @@ Jellyfin banner Adicionar Servidor - Versão do servidor desactualizada: %1$s. Por favor, actualize o seu servidor - Não é um servidor Jellyfin: %1$s - Versão de servidor não suportada: %1$s. Por favor, actualize o seu servidor + Versão do servidor desatualizada: %1$s. Por favor, atualize o seu servidor + Não é um servidor de Jellyfin: %1$s + Versão de servidor não suportada: %1$s. Por favor, atualize o seu servidor O servidor é demasiado lento para responder: %1$s Endereço de servidor vazio Servidor não encontrado - O servidor não tem identificação, algo parece estar errado com o servidor - Início de Sessão + O servidor não tem id, algo parece estar errado com o servidor + Iníciar Sessão Selecionar servidor Endereço de servidor Ligar @@ -18,18 +18,18 @@ Início Cancelar Remover - Remover Servidor + Remover servidor Têm a certeza que pretende remover o servidor %1$s Favoritos Definições Transferências Ver todos Aplicação Jellyfin nativa de terceiros - Entrar + Iníciar Sessão Nome de utilizador ou palavra-passe errados Erro ao carregar dados Tentar novamente - Conteúdo + O meu Conteúdo Escritores Temporadas Favorito @@ -41,16 +41,16 @@ Cartaz de Séries Não tem favoritos Procurar - Preferir idioma legenda - Reprodutor + Preferir idioma de subtítulo + Reprodutor de video Imagens em cache - Aspecto + Aspeto Dispositivo - Nome do Dispositivo + Nome de dispositivo Cache Tamanho da cache (MB) Info da Aplicação - Erro Desconhecido + Erro desconhecido Procurar filmes, séries, episódios… Sobre reprodutor mpv @@ -63,15 +63,15 @@ Filmes Séries Espisódios - Esconder + Ocultar Partilhar Fechar Transferir - Utilize o leitor experimental de MPV para reproduzir vídeos. MPV tem suporte de vários codecs de vídeo, áudio e subtítulos. + Utilize o leitor experimental de MPV para reproduzir vídeos. MPV tem suporte para mais codecs de vídeo, áudio e subtítulos. Gestor de Zoom %1$s cartaz %1$s cenário - Gestor + Gestos Gestor de volume e luminosidade Ordenar por Ordenar por ordem @@ -104,7 +104,7 @@ Tempo limite do soquete (ms) Género Diretor - Elenco e Equipa + Elenco & Equipa Ver o trailer Servidores Transferências @@ -115,13 +115,13 @@ Erro na preparação de itens do reprodutor. Não tem nada transferido Sem resultados da pesquisa - A App irá utilizar esta quantidade de MB do seu espaço em disco para armazenar imagens do servidor Jellyfin. Valores maiores podem ser benéficos em redes mais lentas. - Preferir idioma audio + A aplicação irá utilizar esta quantidade de MB do seu espaço em disco para armazenar imagens do servidor Jellyfin. Valores maiores podem ser benéficos em redes mais lentas. + Preferir idioma de audio Cache de imagens em memória para acelerar o tempo de carregamento. Terá efeito após o reinício da aplicação. Remover endereço do servidor Externo - Remover usuário - Tem certeza de que deseja remover o usuário %1$s + Remover utilizador + Tem certeza de que deseja remover o utilizador %1$s Saida de video Saída de áudio Adicionar endereço @@ -145,7 +145,7 @@ Usuários Idioma do aplicativo Adicionar - Indicador baixado + Indicador de transferido Decodificação de hardware Endereços Conexão rápida @@ -158,21 +158,38 @@ temperatura Imagem em imagem Use o botão home ou gesto para entrar na imagem enquanto o vídeo está sendo reproduzido - Ao usar o Findroid, você concorda com a Política de Privacidade, que afirma que não coletamos quaisquer dados + Ao usar o Findroid, esta a concordar com a Política de Privacidade, que afirma que não coletamos quaisquer dados Video Ícone do modo off-line Sem conexão com o servidor Jellyfin, para assistir off-line, ative o modo off-line Interno Selecione o local de armazenamento O local de armazenamento não está disponível - %1$s (%2$d MB grátis) - Preparando para baixar + %1$s (%2$d MB livre) + Preparando transferência Exibir informações extras Este item requer %1$s de armazenamento gratuito, mas apenas %2$s está disponível Fique online Erro ao baixar - Pare de baixar + Parar transferência Gesto inicial imagem em imagem Exibe informações detalhadas sobre áudio, vídeo e legendas Tem certeza de que deseja cancelar a transferência\? + Esta coleção não contém nenhum conteúdo + Inicie maximizado + Abra o vídeo no modo maximizado por padrão + Nenhum servidor encontrado + Nenhum utilizador encontrado + Seleccione um utilizador + TV ao vivo + Reproduzir + Gesto de capítulo + Marcadores de capítulo + Exibir marcadores de capítulo na barra de tempo + Ver trailer + Remover dos favoritos + Manter pressionado no Esquerdo / Direito para saltar capítulos (anula o gesto de velocidade x2) + Marcar como visto + Desmarcar como visto + Adicionar aos favoritos \ No newline at end of file diff --git a/core/src/main/res/values-sw600dp/dimens.xml b/core/src/main/res/values-w600dp/dimens.xml similarity index 83% rename from core/src/main/res/values-sw600dp/dimens.xml rename to core/src/main/res/values-w600dp/dimens.xml index 00d2ec8f..a7206fc3 100644 --- a/core/src/main/res/values-sw600dp/dimens.xml +++ b/core/src/main/res/values-w600dp/dimens.xml @@ -3,6 +3,6 @@ 400dp 6 3 - 4 + 3 124dp \ No newline at end of file diff --git a/core/src/main/res/values-sw720dp/dimens.xml b/core/src/main/res/values-w720dp/dimens.xml similarity index 76% rename from core/src/main/res/values-sw720dp/dimens.xml rename to core/src/main/res/values-w720dp/dimens.xml index cf46930b..4a453509 100644 --- a/core/src/main/res/values-sw720dp/dimens.xml +++ b/core/src/main/res/values-w720dp/dimens.xml @@ -1,6 +1,6 @@ 8 - 6 + 4 200dp \ No newline at end of file diff --git a/core/src/main/res/values-w840dp/dimens.xml b/core/src/main/res/values-w840dp/dimens.xml new file mode 100644 index 00000000..6f317297 --- /dev/null +++ b/core/src/main/res/values-w840dp/dimens.xml @@ -0,0 +1,4 @@ + + + 6 + \ No newline at end of file diff --git a/core/src/main/res/values-zh-rCN/strings.xml b/core/src/main/res/values-zh-rCN/strings.xml index 34e71001..81cd8ca5 100644 --- a/core/src/main/res/values-zh-rCN/strings.xml +++ b/core/src/main/res/values-zh-rCN/strings.xml @@ -187,4 +187,9 @@ 默认以最大化模式打开视频 播放 观看预告 + 该集合不包含任何媒体 + 章节手势 + 长按左/右侧可跳过章节(覆盖 2 倍速度手势) + 章节标记 + 在进度栏上显示章节标记 \ No newline at end of file diff --git a/core/src/main/res/values-zh-rTW/strings.xml b/core/src/main/res/values-zh-rTW/strings.xml index 84b2a22e..c6487364 100644 --- a/core/src/main/res/values-zh-rTW/strings.xml +++ b/core/src/main/res/values-zh-rTW/strings.xml @@ -175,4 +175,21 @@ 您確定要刪除伺服器位址嗎%1$s 跳轉預覽 臨時文件 + 未找到伺服器 + 未找到相應的用戶 + 選擇用戶 + 電視直播 + 播放 + 觀看預告 + 標記為已播放 + 取消標記為已播放 + 加入收藏夾 + 從收藏夾中刪除 + 開始最大化 + 預設以最大化模式開啟視頻 + 章節手勢 + 長按左/右側可跳過章節(覆蓋 2 倍速度手勢) + 章節標記 + 在時間欄上顯示章節標記 + 該集合不包含任何媒體 \ No newline at end of file diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 3e1dc584..056aa8e6 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -54,6 +54,7 @@ Latest %1$s Libraries Series poster + This collection does not contain any media You have no favorites You have nothing downloaded Search diff --git a/data/src/main/java/dev/jdtech/jellyfin/models/FindroidEpisode.kt b/data/src/main/java/dev/jdtech/jellyfin/models/FindroidEpisode.kt index c1fbee4e..6517de5b 100644 --- a/data/src/main/java/dev/jdtech/jellyfin/models/FindroidEpisode.kt +++ b/data/src/main/java/dev/jdtech/jellyfin/models/FindroidEpisode.kt @@ -63,7 +63,7 @@ suspend fun BaseItemDto.toFindroidEpisode( seriesName = seriesName.orEmpty(), seriesId = seriesId!!, seasonId = seasonId!!, - communityRating = communityRating, + communityRating = communityRating?.let { Math.round(it * 10).div(10F) }, missing = locationType == LocationType.VIRTUAL, images = toFindroidImages(jellyfinRepository), chapters = toFindroidChapters(), diff --git a/data/src/main/java/dev/jdtech/jellyfin/models/FindroidMovie.kt b/data/src/main/java/dev/jdtech/jellyfin/models/FindroidMovie.kt index abeec979..2c841835 100644 --- a/data/src/main/java/dev/jdtech/jellyfin/models/FindroidMovie.kt +++ b/data/src/main/java/dev/jdtech/jellyfin/models/FindroidMovie.kt @@ -56,7 +56,7 @@ suspend fun BaseItemDto.toFindroidMovie( runtimeTicks = runTimeTicks ?: 0, playbackPositionTicks = userData?.playbackPositionTicks ?: 0, premiereDate = premiereDate, - communityRating = communityRating, + communityRating = communityRating?.let { Math.round(it * 10).div(10F) }, genres = genres ?: emptyList(), people = people ?: emptyList(), officialRating = officialRating, diff --git a/data/src/main/java/dev/jdtech/jellyfin/models/FindroidShow.kt b/data/src/main/java/dev/jdtech/jellyfin/models/FindroidShow.kt index 7cb6da34..79fbdcdc 100644 --- a/data/src/main/java/dev/jdtech/jellyfin/models/FindroidShow.kt +++ b/data/src/main/java/dev/jdtech/jellyfin/models/FindroidShow.kt @@ -52,7 +52,7 @@ fun BaseItemDto.toFindroidShow( genres = genres ?: emptyList(), people = people ?: emptyList(), runtimeTicks = runTimeTicks ?: 0, - communityRating = communityRating, + communityRating = communityRating?.let { Math.round(it * 10).div(10F) }, officialRating = officialRating, status = status ?: "Ended", productionYear = productionYear, diff --git a/fastlane/Appfile b/fastlane/Appfile new file mode 100644 index 00000000..bfff7ed2 --- /dev/null +++ b/fastlane/Appfile @@ -0,0 +1 @@ +package_name("dev.jdtech.jellyfin") diff --git a/fastlane/Fastfile b/fastlane/Fastfile new file mode 100644 index 00000000..2df93427 --- /dev/null +++ b/fastlane/Fastfile @@ -0,0 +1,40 @@ +default_platform(:android) + +platform :android do + desc "Build and publish" + lane :publish do + gradle(task: "clean") + gradle( + task: "app:phone:assemble", + flavor: "libre", + build_type: "release", + print_command: false, + properties: { + "android.injected.signing.store.file" => ENV["FINDROID_KEYSTORE"], + "android.injected.signing.store.password" => ENV["FINDROID_KEYSTORE_PASSWORD"], + "android.injected.signing.key.alias" => ENV["FINDROID_KEY_ALIAS"], + "android.injected.signing.key.password" => ENV["FINDROID_KEY_PASSWORD"], + } + ) + + gradle( + task: "app:phone:bundle", + flavor: "libre", + build_type: "release", + print_command: false, + properties: { + "android.injected.signing.store.file" => ENV["FINDROID_KEYSTORE"], + "android.injected.signing.store.password" => ENV["FINDROID_KEYSTORE_PASSWORD"], + "android.injected.signing.key.alias" => ENV["FINDROID_KEY_ALIAS"], + "android.injected.signing.key.password" => ENV["FINDROID_KEY_PASSWORD"], + } + ) + + upload_to_play_store( + track: "production", + json_key: ENV["FINDROID_PLAY_API_CREDENTIALS"], + skip_upload_apk: true, + sync_image_upload: true + ) + end +end diff --git a/fastlane/README.md b/fastlane/README.md new file mode 100644 index 00000000..3f8de830 --- /dev/null +++ b/fastlane/README.md @@ -0,0 +1,56 @@ +fastlane documentation +---- + +# Installation + +Make sure you have the latest version of the Xcode command line tools installed: + +```sh +xcode-select --install +``` + +For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane) + +# Available Actions + +## Android + +### android test + +```sh +[bundle exec] fastlane android test +``` + +Runs all the tests + +### android beta + +```sh +[bundle exec] fastlane android beta +``` + +Submit a new Beta Build to Crashlytics Beta + +### android deploy + +```sh +[bundle exec] fastlane android deploy +``` + +Deploy a new version to the Google Play + +### android build + +```sh +[bundle exec] fastlane android build +``` + +build + +---- + +This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run. + +More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools). + +The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools). diff --git a/fastlane/metadata/android/en-US/changelogs/1.txt b/fastlane/metadata/android/en-US/changelogs/1.txt new file mode 100644 index 00000000..c9f05cb0 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/1.txt @@ -0,0 +1,9 @@ +Features: +- Completely native interface +- Supported media items: movies, series, seasons, episodes +- Video codes: H.263, H.264, H.265, VP8, VP9, AV1 +- Audio codes: Vorbis, Opus, FLAC, ALAC, PCM µ-law, PCM A-law, MP1, MP2, MP3, AMR-NB, AMR-WB, AAC, AC-3, E-AC-3, DTS, DTS-HD, TrueHD +- Subtitle codecs: SRT, VTT, SSA/ASS, PGSSUB +- Support for multiple servers +- Set preferred audio and subtitle language +- Light & dark theme \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/10.txt b/fastlane/metadata/android/en-US/changelogs/10.txt new file mode 100644 index 00000000..249270f1 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/10.txt @@ -0,0 +1,13 @@ +New features: +- Split gesture option into volume & brightness and zoom +- Add support for external subtitles (only ExoPlayer) +- Customize the seeking increments +- Add option to disable subtitles in mpv + +Improvements: +- Lot's of translations (Bulgarian, Chinese, French, German, Hungarian, Italian, Polish, Portuguese, Spanish) +- Provide better error messages with stacktrace +- Display downloaded episodes by series +- Add paging support to the library + +Also fixed a few crashes \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/11.txt b/fastlane/metadata/android/en-US/changelogs/11.txt new file mode 100644 index 00000000..416923b7 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/11.txt @@ -0,0 +1,14 @@ +New features: +- Allow seeking video by swiping or tapping +- Material You Dynamic colors +- Display public users on login screen +- Display discovered servers on add server screen + +Improvements: +- Layout improvements for larger screens +- Bring back Android TV (fix crashes and improvements) + +Translations: Chinese (Simplified), French, Italian, Korean, Russian + +Fixes: +- Fix crash when navigating to login screen (and other screens) \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/12.txt b/fastlane/metadata/android/en-US/changelogs/12.txt new file mode 100644 index 00000000..4c9f3987 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/12.txt @@ -0,0 +1,13 @@ +Improvements: +- Add "pinch to zoom" support to mpv + +Fixes: +- Fix play icon color in settings +- Fix mpv subfont.ttf not loading + - This fixes mpv not displaying SubRip Text (SRT) subtitles +- Fix external subtiles not working in mpv +- Fix crash when using swiping gesture if video is not loaded yet +- Fix player crashing when no PlayerItems are passed +- Fix only showing 1 discovered server + +Translations: Korean, Polish, Spanish \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/13.txt b/fastlane/metadata/android/en-US/changelogs/13.txt new file mode 100644 index 00000000..f4ac3970 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/13.txt @@ -0,0 +1,18 @@ +This update forces a servers database reset! Servers will need to be added again! + +New features: +- Servers database v2 +- Network settings + - Request timeout + - Connect timeout + - Socket timeout +- Mutli-user support + +Improvements: +- Add series name to episode sheet with navigation +- Enable predictive back gesture +- Improve downloads management +- Upgrade libmpv +- Handle audio focus +- Lot's of library upgrades +- Bugfixes \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/14.txt b/fastlane/metadata/android/en-US/changelogs/14.txt new file mode 100644 index 00000000..aeb2b78d --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/14.txt @@ -0,0 +1,16 @@ +Highlights: +- Add support for media sessions +- Basic support for multiple server addresses +- More mpv options + +Improvements: +- Add search button to home screen + +Translations: +- Chinese +- French +- Korean + +Fixes: +- Fix tv player showing subtitle tracks instead of audio tracks +- Remove server already added error \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/15.txt b/fastlane/metadata/android/en-US/changelogs/15.txt new file mode 100644 index 00000000..8538c769 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/15.txt @@ -0,0 +1,14 @@ +New features: +- Allow logging in with Quick Connect +- Support for ConfusedPolarBears intro-skipper + +Improvements: +- Updated mpv release (now includes all codecs in FFmpeg) + - Including an experimental AV1 hardware decoder. +- Respect "Allow media playback" + +Translations: Chinese, Dutch, French, Italian, Korean, Polish, Portuguese, Spanish + +Fixes: +- Fix playback position reporting not closing properly. +- Optimized the loading of app preferences (backend, not the settings screen) \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/16.txt b/fastlane/metadata/android/en-US/changelogs/16.txt new file mode 100644 index 00000000..010012c3 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/16.txt @@ -0,0 +1,13 @@ +New features: +- Support for collections + +Improvements: +- Follow "Play next episode automatically" from user playback settings +- ExoPlayer can now play HLS content + +Translations: Chinese, Italian, Korean, Portuguese + +Fixes: +- Fix Quick Connect code not readable in light mode +- Fix multiple download related issues +- Fix app crashing when exiting the player after finishing an item using mpv \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/17.txt b/fastlane/metadata/android/en-US/changelogs/17.txt new file mode 100644 index 00000000..97d6d36f --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/17.txt @@ -0,0 +1,6 @@ +Fixes: +- Fix resuming playback +- Fix downloads playback when there is no connection to the server +- Fix next up episode image crop + +Translations: Chinese, Dutch, Vietnamese, German, Hungarian, Italian, Portuguese, Polish, Russian, Yue \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/18.txt b/fastlane/metadata/android/en-US/changelogs/18.txt new file mode 100644 index 00000000..299825aa --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/18.txt @@ -0,0 +1,18 @@ +New features: +- Item metadata chips +- Seek gesture toggle +- AMOLED dark theme +- Scrubbing preview (trick play) +- Downloads rework + +Improvements: +- Material 3 styling in preferences +- Gesture exclusion zones + +Fixes: +- 500 error when trying to play an item +- mpv memory leak, anr and stuck loading icon +- And more + +Translations: +- Chinese (Simplified), Dutch, French, German, Hebrew, Italian, Polish, Portuguese, Russian, Slovak, Slovenian, Spanish, Swedish, Vietnamese \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/19.txt b/fastlane/metadata/android/en-US/changelogs/19.txt new file mode 100644 index 00000000..fdba510f --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/19.txt @@ -0,0 +1,13 @@ +Improvements: +- Search in offline mode +- App language setting for devices running Android 13+ +- Show movie size in extra info and improve size formatting + +Fixes: +- Navigation to collection +- Text overflowing into "View all" +- Text overlapping in movie and show screens +- AMOLED theme not taking Material 3 colors +- NullPointerException on episodes which do not contain a seriesId or seasonId + +Translations: Hungarian, Polish, Portuguese (Brazil), Russian, Slovak, Spanish \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/2.txt b/fastlane/metadata/android/en-US/changelogs/2.txt new file mode 100644 index 00000000..3b10a9b1 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/2.txt @@ -0,0 +1,9 @@ +Improvements: +- Replaced oss-licenses-plugin with AboutLibraries. +- Improved server url discovery, no more http://, https:// or ports required! +- New error panel to display detailed error messages. +- Make library images smaller to fit more on one screen. + +Fixes: +- Removed books from home & media screens. +- Move episode metadata to under the image to adjust for larger font sizes and smaller screens. \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/20.txt b/fastlane/metadata/android/en-US/changelogs/20.txt new file mode 100644 index 00000000..bcf97475 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/20.txt @@ -0,0 +1,16 @@ +New features: +- Picture-in-picture support +- Double tap center to play/pause + +Improvements: +- Ripple effect when double tapping in player +- Improvements to hiding system bars +- Show episode size when extra info is enabled + +Fixes: +- Fix playback position reset on process death or device lock +- Fix playback sync of download being too far ahead +- ... + +Translations: +- Chinese, Dutch, French, Hebrew, Hungarian, Italian, Korean, Polish, Portuguese, Romanian, Russion, Slovak, Spanish, Ukranian \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/21.txt b/fastlane/metadata/android/en-US/changelogs/21.txt new file mode 100644 index 00000000..bcf97475 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/21.txt @@ -0,0 +1,16 @@ +New features: +- Picture-in-picture support +- Double tap center to play/pause + +Improvements: +- Ripple effect when double tapping in player +- Improvements to hiding system bars +- Show episode size when extra info is enabled + +Fixes: +- Fix playback position reset on process death or device lock +- Fix playback sync of download being too far ahead +- ... + +Translations: +- Chinese, Dutch, French, Hebrew, Hungarian, Italian, Korean, Polish, Portuguese, Romanian, Russion, Slovak, Spanish, Ukranian \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/22.txt b/fastlane/metadata/android/en-US/changelogs/22.txt new file mode 100644 index 00000000..fc284f9a --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/22.txt @@ -0,0 +1,10 @@ +Fixes: +- Multiple crashes +- Offline mode snackbar not visible in landscape mode +- Incorrect popup background in player when using dark mode +- Playback resets +- Deleted server stays visible +- Stuck on login screen when server has no user + +Translations: +- Chinese, Czech, Hebrew, Hungarian, Italian, Korean, Portuguese, Slovak, Slovenian \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/23.txt b/fastlane/metadata/android/en-US/changelogs/23.txt new file mode 100644 index 00000000..ae7edf96 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/23.txt @@ -0,0 +1,16 @@ +New features: +- Disable audio track +- Long press for 2x speed +- Chapters + - Markers are displayed on the timebar + - Gestures +- Support for mixed libraries + +Improvements: +- Custom track selection dialog +- Make PiP remember zoom and brightness levels +- Improve PiP transition when using home gesture +- Increase the limit of items displayed on the home screen + +Translations: +- Bulgarian, Chinese, Danish, French, Hungarian, Italian, Korean, Portuguese, Slovak, Spanish, Turkish, Vietnamese \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/24.txt b/fastlane/metadata/android/en-US/changelogs/24.txt new file mode 100644 index 00000000..31fe5a03 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/24.txt @@ -0,0 +1,15 @@ +Improvements: +- Request audio focus in mpv +- Sort items in collections by release date +- Improve landscape library layout on mobile +- Reduce community rating to one decimal place + +Fixes: +- Set correct surface colors when using dynamic colors or AMOLED theme +- Fix crash when setting picture-in-picture params +- Check address when adding extra addresses to server +- Display correct empty collection string + +Translations: +- Dutch +- Portuguese (Brazil) \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/25.txt b/fastlane/metadata/android/en-US/changelogs/25.txt new file mode 100644 index 00000000..d2ee60b4 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/25.txt @@ -0,0 +1,14 @@ +Improvements: +- Support HTML in media descriptions + +Fixes: +- Library media items too small on tablet when in portrait mode + +Translations: +- Chinese +- French +- German +- Hungarian +- Portuguese +- Spanish (Mexico) +- Turkish \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/3.txt b/fastlane/metadata/android/en-US/changelogs/3.txt new file mode 100644 index 00000000..728eec17 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/3.txt @@ -0,0 +1,15 @@ +Improvements: +- Improved home screen loading +- Added missing episode icon +- Reworked player items preparation: + - Supports intros + - Improved loading speed +- Show complete detailed error messages +- Ask for login if server responds with 401 + +Fixes: +- Fixed playing episodes if missing episodes occur in the season +- Fixed missing images in some places +- Fixed library broken when media items are grouped in folders +- Removed Live TV section from home screen +- Fixed underlined "View detail" text \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/4.txt b/fastlane/metadata/android/en-US/changelogs/4.txt new file mode 100644 index 00000000..9911052c --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/4.txt @@ -0,0 +1,12 @@ +New Features: +- Experimental mpv player + - Can be enabled in the settings + - With extra option to force software decoding +- New player UI to support mpv + +Improvements: +- Spanish translations +- Video now extends into display cutout + +Fixes: +- Fix crash when trailer button is pressed but no trailers are available \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/5.txt b/fastlane/metadata/android/en-US/changelogs/5.txt new file mode 100644 index 00000000..76aaea90 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/5.txt @@ -0,0 +1,2 @@ +Fixes: +- Fix mpv player crashing \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/6.txt b/fastlane/metadata/android/en-US/changelogs/6.txt new file mode 100644 index 00000000..d6866595 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/6.txt @@ -0,0 +1,16 @@ +New Features: +- Playback speed controls +- Sorting options in library +- Person detail screen +- Downloads and offline playback +- Gestures in player to adjust volume and brightness +- STRM support +- Image caching with options in settings +- Customizable device name +- Basic Android TV layout + +Improvements: +- Theme improvements +- Pull to refresh on home screen +- Server setup improvements +- Czech and Spanish localization \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/7.txt b/fastlane/metadata/android/en-US/changelogs/7.txt new file mode 100644 index 00000000..e5616fa4 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/7.txt @@ -0,0 +1,10 @@ +Improvements: +- Change downloads to use internal database for metadata instead of files +- Only show download button if user is allowed to download +- Improve player gestures and add pinch to zoom +- Reduce the size of the mpv library by disabling lot's of decoders and other components + - If you notice certain content doesn't play anymore please report + +Fixes: +- Fix person placeholder drawable +- Add error handling to played and favorite buttons \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/8.txt b/fastlane/metadata/android/en-US/changelogs/8.txt new file mode 100644 index 00000000..8fb51516 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/8.txt @@ -0,0 +1,6 @@ +Improvements: +- Enable avi container format in mpv +- Many dependencies updated + +Fixes: +- Add missing check for if user is allowed to download in episode sheet \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/9.txt b/fastlane/metadata/android/en-US/changelogs/9.txt new file mode 100644 index 00000000..4dce78ae --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/9.txt @@ -0,0 +1,14 @@ +New features: +- Add option to display extended episode title in player +- Add option to download over mobile network +- Add option to disable player gestures and remember screen brightness + +Improvements: +- Expand episode bottom sheet by default +- Upgrade to Material 3 theme and components +- Redesign settings using two pane layout +- Add option to turn off subtitles in player (only ExoPlayer) +- Enable image caching by default +- Add support for Vorbis audio codec in mpv player + +Plus bugfixes! \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/full_description.txt b/fastlane/metadata/android/en-US/full_description.txt new file mode 100644 index 00000000..aa925f9e --- /dev/null +++ b/fastlane/metadata/android/en-US/full_description.txt @@ -0,0 +1,8 @@ +Findroid is a third-party Android application for Jellyfin that provides a native user interface to browse and play movies and series. + +To use this app you must have a Jellyfin server. + +You can also download movies and TV shows for offline playback while on the road. +And with the built-in mpv player you are sure that all media formats will play correctly including styled SSA/ASS subtitles. + +Thanks for using Findroid! \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/images/featureGraphic.png b/fastlane/metadata/android/en-US/images/featureGraphic.png new file mode 100644 index 00000000..d5330f28 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/featureGraphic.png differ diff --git a/fastlane/metadata/android/en-US/images/icon.png b/fastlane/metadata/android/en-US/images/icon.png new file mode 100644 index 00000000..edd0aa1f Binary files /dev/null and b/fastlane/metadata/android/en-US/images/icon.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/1_en-US.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/1_en-US.png new file mode 100644 index 00000000..3258a2be Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/1_en-US.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/2_en-US.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/2_en-US.png new file mode 100644 index 00000000..9392f5d3 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/2_en-US.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/3_en-US.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/3_en-US.png new file mode 100644 index 00000000..64006476 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/3_en-US.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/4_en-US.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/4_en-US.png new file mode 100644 index 00000000..327b6685 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/4_en-US.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/5_en-US.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/5_en-US.png new file mode 100644 index 00000000..e1d6fcd0 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/5_en-US.png differ diff --git a/fastlane/metadata/android/en-US/images/sevenInchScreenshots/1_en-US.png b/fastlane/metadata/android/en-US/images/sevenInchScreenshots/1_en-US.png new file mode 100644 index 00000000..3ff8179e Binary files /dev/null and b/fastlane/metadata/android/en-US/images/sevenInchScreenshots/1_en-US.png differ diff --git a/fastlane/metadata/android/en-US/images/sevenInchScreenshots/2_en-US.png b/fastlane/metadata/android/en-US/images/sevenInchScreenshots/2_en-US.png new file mode 100644 index 00000000..e780ea9e Binary files /dev/null and b/fastlane/metadata/android/en-US/images/sevenInchScreenshots/2_en-US.png differ diff --git a/fastlane/metadata/android/en-US/images/sevenInchScreenshots/3_en-US.png b/fastlane/metadata/android/en-US/images/sevenInchScreenshots/3_en-US.png new file mode 100644 index 00000000..a029f989 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/sevenInchScreenshots/3_en-US.png differ diff --git a/fastlane/metadata/android/en-US/images/sevenInchScreenshots/4_en-US.png b/fastlane/metadata/android/en-US/images/sevenInchScreenshots/4_en-US.png new file mode 100644 index 00000000..aca684a1 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/sevenInchScreenshots/4_en-US.png differ diff --git a/fastlane/metadata/android/en-US/images/sevenInchScreenshots/5_en-US.png b/fastlane/metadata/android/en-US/images/sevenInchScreenshots/5_en-US.png new file mode 100644 index 00000000..8bbc5345 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/sevenInchScreenshots/5_en-US.png differ diff --git a/fastlane/metadata/android/en-US/images/tenInchScreenshots/1_en-US.png b/fastlane/metadata/android/en-US/images/tenInchScreenshots/1_en-US.png new file mode 100644 index 00000000..b0ef8232 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/tenInchScreenshots/1_en-US.png differ diff --git a/fastlane/metadata/android/en-US/images/tenInchScreenshots/2_en-US.png b/fastlane/metadata/android/en-US/images/tenInchScreenshots/2_en-US.png new file mode 100644 index 00000000..879f9949 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/tenInchScreenshots/2_en-US.png differ diff --git a/fastlane/metadata/android/en-US/images/tenInchScreenshots/3_en-US.png b/fastlane/metadata/android/en-US/images/tenInchScreenshots/3_en-US.png new file mode 100644 index 00000000..4f0b5d26 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/tenInchScreenshots/3_en-US.png differ diff --git a/fastlane/metadata/android/en-US/images/tenInchScreenshots/4_en-US.png b/fastlane/metadata/android/en-US/images/tenInchScreenshots/4_en-US.png new file mode 100644 index 00000000..54a3668f Binary files /dev/null and b/fastlane/metadata/android/en-US/images/tenInchScreenshots/4_en-US.png differ diff --git a/fastlane/metadata/android/en-US/images/tenInchScreenshots/5_en-US.png b/fastlane/metadata/android/en-US/images/tenInchScreenshots/5_en-US.png new file mode 100644 index 00000000..e4c30328 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/tenInchScreenshots/5_en-US.png differ diff --git a/fastlane/metadata/android/en-US/short_description.txt b/fastlane/metadata/android/en-US/short_description.txt new file mode 100644 index 00000000..ec5f6c25 --- /dev/null +++ b/fastlane/metadata/android/en-US/short_description.txt @@ -0,0 +1 @@ +Third-party native Jellyfin app \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/title.txt b/fastlane/metadata/android/en-US/title.txt new file mode 100644 index 00000000..8115e156 --- /dev/null +++ b/fastlane/metadata/android/en-US/title.txt @@ -0,0 +1 @@ +Findroid \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/video.txt b/fastlane/metadata/android/en-US/video.txt new file mode 100644 index 00000000..e69de29b diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 723fb8f0..1bbaaab4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,38 +1,47 @@ [versions] -aboutlibraries = "11.1.0" -android-plugin = "8.3.0" +aboutlibraries = "11.1.3" +android-desugar-jdk-libs = "2.0.4" +android-plugin = "8.3.2" androidx-activity = "1.8.2" androidx-appcompat = "1.6.1" -androidx-compose-bom = "2024.02.01" -androidx-compose-material3 = "1.2.0" +androidx-compose-bom = "2024.04.00" +androidx-compose-material3 = "1.2.1" androidx-constraintlayout = "2.1.4" androidx-core = "1.12.0" androidx-hilt = "1.2.0" androidx-lifecycle = "2.7.0" -androidx-media3 = "1.2.1" +androidx-media3 = "1.3.1" androidx-navigation = "2.7.7" androidx-paging = "3.2.1" androidx-preference = "1.2.1" androidx-recyclerview = "1.3.2" androidx-room = "2.6.1" androidx-swiperefreshlayout = "1.1.0" +androidx-test-core = "1.5.0" +androidx-test-expresso = "3.5.1" +androidx-test-junit = "1.1.5" +androidx-test-rules = "1.5.0" +androidx-test-runner = "1.5.2" androidx-tv = "1.0.0-alpha10" androidx-work = "2.9.0" coil = "2.6.0" -hilt = "2.51" -compose-destinations = "1.10.1" -jellyfin = "1.4.6" -kotlin = "1.9.22" +hilt = "2.51.1" +compose-destinations = "1.10.2" +jellyfin = "1.4.7" +junit = "4.13.2" +kotlin = "1.9.23" kotlinx-serialization = "1.6.3" -ksp = "1.9.22-1.0.17" +ksp = "1.9.23-1.0.20" ktlint = "12.1.0" libmpv = "0.2.0" material = "1.11.0" +media3-ffmpeg-decoder = "1.2.1+1" timber = "5.0.1" [libraries] aboutlibraries-core = { group = "com.mikepenz", name = "aboutlibraries-core", version.ref = "aboutlibraries" } aboutlibraries = { group = "com.mikepenz", name = "aboutlibraries", version.ref = "aboutlibraries" } +android-desugar-jdk = { group = "com.android.tools", name = "desugar_jdk_libs", version.ref = "android-desugar-jdk-libs" } androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "androidx-activity" } androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "androidx-activity" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" } @@ -63,19 +72,30 @@ androidx-recyclerview = { group = "androidx.recyclerview", name = "recyclerview" androidx-room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "androidx-room" } androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "androidx-room" } androidx-swiperefreshlayout = { group = "androidx.swiperefreshlayout", name = "swiperefreshlayout", version.ref = "androidx-swiperefreshlayout" } -androidx-work = { group = "androidx.work", name = "work-runtime", version.ref = "androidx-work" } +androidx-test-core = { group = "androidx.test", name = "core", version.ref = "androidx-test-core" } +androidx-test-core-ktx = { group = "androidx.test", name = "core-ktx", version.ref = "androidx-test-core" } +androidx-test-expresso = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "androidx-test-expresso"} +androidx-test-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-junit" } +androidx-test-rules = { group = "androidx.test" , name = "rules", version.ref = "androidx-test-rules" } +androidx-test-runner = { group = "androidx.test", name = "runner", version.ref = "androidx-test-runner" } androidx-tv-foundation = { group = "androidx.tv", name = "tv-foundation", version.ref = "androidx-tv" } androidx-tv-material = { group = "androidx.tv", name = "tv-material", version.ref = "androidx-tv" } +androidx-work = { group = "androidx.work", name = "work-runtime", version.ref = "androidx-work" } +androidx-work-testing = { group = "androidx.work", name = "work-testing", version.ref = "androidx-work" } coil = { group = "io.coil-kt", name = "coil", version.ref = "coil" } coil-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil" } coil-svg = { group = "io.coil-kt", name = "coil-svg", version.ref = "coil" } compose-destinations-core = { group = "io.github.raamcosta.compose-destinations", name = "core", version.ref = "compose-destinations" } compose-destinations-ksp = { group = "io.github.raamcosta.compose-destinations", name = "ksp", version.ref = "compose-destinations" } hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" } +hilt-android-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" } +hilt-android-testing = { group = "com.google.dagger", name = "hilt-android-testing", version.ref = "hilt" } hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" } jellyfin-core = { group = "org.jellyfin.sdk", name = "jellyfin-core", version.ref = "jellyfin" } +junit = { group = "junit", name = "junit", version.ref = "junit" } libmpv = { group = "dev.jdtech.mpv", name = "libmpv", version.ref = "libmpv" } material = { group = "com.google.android.material", name = "material", version.ref = "material" } +media3-ffmpeg-decoder = { group = "org.jellyfin.media3", name = "media3-ffmpeg-decoder", version.ref = "media3-ffmpeg-decoder" } timber = { group = "com.jakewharton.timber", name = "timber", version.ref = "timber" } kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinx-serialization" } @@ -90,3 +110,6 @@ kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint" } + +[bundles] +androidx-test = ["androidx-test-core", "androidx-test-core-ktx", "androidx-test-expresso", "androidx-test-junit", "androidx-test-rules", "androidx-test-runner", "androidx-work-testing"] \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d64cd491..e6441136 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a80b22ce..b82aa23a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/libs/lib-decoder-ffmpeg-release.aar b/libs/lib-decoder-ffmpeg-release.aar deleted file mode 100644 index 519a00e9..00000000 Binary files a/libs/lib-decoder-ffmpeg-release.aar and /dev/null differ diff --git a/player/video/src/main/java/dev/jdtech/jellyfin/mpv/MPVPlayer.kt b/player/video/src/main/java/dev/jdtech/jellyfin/mpv/MPVPlayer.kt index 5d556183..d7004fe6 100644 --- a/player/video/src/main/java/dev/jdtech/jellyfin/mpv/MPVPlayer.kt +++ b/player/video/src/main/java/dev/jdtech/jellyfin/mpv/MPVPlayer.kt @@ -755,7 +755,17 @@ class MPVPlayer( playWhenReadyChangeReason = Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST, ) if (isPlayerReady) { - MPVLib.setPropertyBoolean("pause", !playWhenReady) + // Request audio focus when starting playback + if (requestAudioFocus && playWhenReady) { + val res = audioManager.requestAudioFocus(audioFocusRequest) + if (res != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { + MPVLib.setPropertyBoolean("pause", true) + } else { + MPVLib.setPropertyBoolean("pause", false) + } + } else { + MPVLib.setPropertyBoolean("pause", !playWhenReady) + } } } } diff --git a/player/video/src/main/java/dev/jdtech/jellyfin/viewmodels/PlayerActivityViewModel.kt b/player/video/src/main/java/dev/jdtech/jellyfin/viewmodels/PlayerActivityViewModel.kt index 2cc1218d..d6f78d9e 100644 --- a/player/video/src/main/java/dev/jdtech/jellyfin/viewmodels/PlayerActivityViewModel.kt +++ b/player/video/src/main/java/dev/jdtech/jellyfin/viewmodels/PlayerActivityViewModel.kt @@ -101,7 +101,7 @@ constructor( .build() player = MPVPlayer( context = application, - requestAudioFocus = false, + requestAudioFocus = true, trackSelectionParameters = trackSelectionParameters, seekBackIncrement = appPreferences.playerSeekBackIncrement, seekForwardIncrement = appPreferences.playerSeekForwardIncrement, diff --git a/player/video/src/main/res/values-de/strings.xml b/player/video/src/main/res/values-de/strings.xml index b0e68dc9..e75e2210 100644 --- a/player/video/src/main/res/values-de/strings.xml +++ b/player/video/src/main/res/values-de/strings.xml @@ -8,4 +8,11 @@ Player verlassen Wiederholen Vorspulen - + Player sperren + Zurückspulen + Starten/Anhalten + Vor springen + Fortschrittsanzeige + Keine + Bild-in-Bild öffnen + \ No newline at end of file diff --git a/player/video/src/main/res/values-fr/strings.xml b/player/video/src/main/res/values-fr/strings.xml index 94ad3382..13692833 100644 --- a/player/video/src/main/res/values-fr/strings.xml +++ b/player/video/src/main/res/values-fr/strings.xml @@ -15,4 +15,5 @@ Avancer Barre de progression Détacher la fenêtre flottante + Aucun \ No newline at end of file diff --git a/player/video/src/main/res/values-pt/strings.xml b/player/video/src/main/res/values-pt/strings.xml index b07f00b0..6ddf583e 100644 --- a/player/video/src/main/res/values-pt/strings.xml +++ b/player/video/src/main/res/values-pt/strings.xml @@ -15,4 +15,5 @@ Avançar Pular para trás Insira imagem em imagem + Nenhum \ No newline at end of file diff --git a/player/video/src/main/res/values-tr/strings.xml b/player/video/src/main/res/values-tr/strings.xml index a6b3daec..e5d31a66 100644 --- a/player/video/src/main/res/values-tr/strings.xml +++ b/player/video/src/main/res/values-tr/strings.xml @@ -1,2 +1,8 @@ - \ No newline at end of file + + Ses parçasını seç + Altyazı parçasını seç + Oynatma hızını seç + Bir sürüm seç + Hiçbiri + \ No newline at end of file diff --git a/player/video/src/main/res/values-zh-rTW/strings.xml b/player/video/src/main/res/values-zh-rTW/strings.xml index c4bf81c9..416d59ff 100644 --- a/player/video/src/main/res/values-zh-rTW/strings.xml +++ b/player/video/src/main/res/values-zh-rTW/strings.xml @@ -15,4 +15,5 @@ 輸入畫中畫 特技播放 進度條 + 一個也沒有 \ No newline at end of file