0
0
mirror of https://github.com/mediathekview/zapp.git synced 2024-09-19 20:02:17 +02:00

Merge branch 'develop' into feature/media3

# Conflicts:
#	app/build.gradle
This commit is contained in:
Christine Coenen 2023-07-22 10:57:30 +02:00
commit 732f6c5c2b
26 changed files with 171 additions and 46 deletions

View File

@ -16,7 +16,7 @@ jobs:
uses: actions/setup-java@v2
with:
distribution: 'temurin'
java-version: 11
java-version: 17
cache: 'gradle'
- name: Build and test with Gradle

View File

@ -6,26 +6,26 @@ apply plugin: 'koin'
apply plugin: 'androidx.navigation.safeargs.kotlin'
android {
compileSdkVersion 33
buildToolsVersion '33.0.2'
compileSdkVersion 34
buildToolsVersion '34.0.0'
defaultConfig {
applicationId "de.christinecoenen.code.zapp"
minSdkVersion 26
targetSdkVersion 33
versionCode 65
versionName "8.2.0"
targetSdkVersion 34
versionCode 67
versionName "8.3.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resConfigs 'de', 'en'
resourceConfigurations += ['de', 'en']
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
jvmTarget = JavaVersion.VERSION_17.toString()
freeCompilerArgs += [
'-opt-in=kotlin.RequiresOptIn',
]
@ -38,14 +38,13 @@ android {
}
buildFeatures {
viewBinding {
enabled = true
}
viewBinding = true
}
buildTypes {
debug {
shrinkResources false
applicationIdSuffix '.debug'
}
release {
shrinkResources true
@ -78,17 +77,17 @@ android {
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
def fragment_version = '1.5.5'
def fragment_version = '1.6.0'
// kotlin
implementation 'androidx.core:core-ktx:1.9.0'
implementation 'androidx.core:core-ktx:1.10.1'
// tests
def androix_test_version = '1.5.0'
// device tests
def espresso_version = '3.5.1'
debugImplementation "androidx.fragment:fragment-testing:1.6.0-alpha08"
debugImplementation "androidx.fragment:fragment-testing:$fragment_version"
androidTestImplementation "androidx.test:core-ktx:$androix_test_version"
androidTestImplementation 'androidx.test.ext:junit-ktx:1.1.5'
androidTestImplementation 'androidx.test:runner:1.5.2'
@ -103,15 +102,15 @@ dependencies {
// unit tests
testImplementation 'junit:junit:4.13.2'
testImplementation "androidx.test:core-ktx:$androix_test_version"
testImplementation 'org.robolectric:robolectric:4.6.1'
testImplementation 'org.mockito.kotlin:mockito-kotlin:3.2.0'
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4'
testImplementation 'org.robolectric:robolectric:4.10.3'
testImplementation 'org.mockito.kotlin:mockito-kotlin:5.0.0'
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.2'
// support
implementation "androidx.fragment:fragment-ktx:$fragment_version"
implementation 'androidx.activity:activity-ktx:1.7.0'
implementation 'androidx.activity:activity-ktx:1.7.2'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.8.0'
implementation 'com.google.android.material:material:1.9.0'
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.annotation:annotation:1.6.0'
@ -127,7 +126,7 @@ dependencies {
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
// room database
def room_version = "2.5.1"
def room_version = "2.5.2"
implementation "androidx.room:room-runtime:$room_version"
implementation "androidx.room:room-paging:$room_version"
kapt "androidx.room:room-compiler:$room_version"
@ -137,7 +136,7 @@ dependencies {
implementation 'com.google.code.gson:gson:2.10.1'
// sortable list
implementation 'com.github.woxthebox:draglistview:1.7.2'
implementation 'com.github.woxthebox:draglistview:1.7.3'
// markdown
implementation 'io.noties.markwon:core:4.6.2'
@ -147,7 +146,7 @@ dependencies {
implementation "androidx.work:work-runtime-ktx:$work_version"
// exo player
def media3_version = "1.0.0"
def media3_version = "1.1.0"
implementation "androidx.media3:media3-exoplayer:$media3_version"
implementation "androidx.media3:media3-exoplayer-hls:$media3_version"
implementation "androidx.media3:media3-ui:$media3_version"
@ -160,7 +159,7 @@ dependencies {
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
// ACRA crash reporting
def acra_version = "5.9.7"
def acra_version = "5.11.0"
implementation "ch.acra:acra-mail:$acra_version"
implementation "ch.acra:acra-dialog:$acra_version"
@ -171,7 +170,7 @@ dependencies {
implementation 'com.jakewharton:process-phoenix:2.1.2'
// joda time
implementation 'joda-time:joda-time:2.12.2'
implementation 'joda-time:joda-time:2.12.5'
// about libraries view
implementation "com.mikepenz:aboutlibraries:$about_libraries_version"

View File

@ -1 +1,21 @@
# Please add these rules to your existing keep rules in order to suppress warnings.
# This is generated automatically by the Android Gradle plugin.
-dontwarn org.bouncycastle.jsse.BCSSLParameters
-dontwarn org.bouncycastle.jsse.BCSSLSocket
-dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider
-dontwarn org.joda.convert.FromString
-dontwarn org.joda.convert.ToString
-dontwarn org.openjsse.javax.net.ssl.SSLParameters
-dontwarn org.openjsse.javax.net.ssl.SSLSocket
-dontwarn org.openjsse.net.ssl.OpenJSSE
# https://r8.googlesource.com/r8/+/refs/heads/main/compatibility-faq.md#troubleshooting-gson-gson
-keep class com.google.gson.reflect.TypeToken { *; }
-keep class * extends com.google.gson.reflect.TypeToken
# https://github.com/square/retrofit/issues/3751#issuecomment-1564410089
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
-keep,allowobfuscation,allowshrinking interface retrofit2.Call
-keep,allowobfuscation,allowshrinking class retrofit2.Response
-if interface * { @retrofit2.http.* public *** *(...); }
-keep,allowoptimization,allowshrinking,allowobfuscation class <3>

View File

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

View File

@ -0,0 +1,3 @@
<resources>
<string name="app_name">Zapp (Debug)</string>
</resources>

View File

@ -7,6 +7,8 @@
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-feature
android:name="android.hardware.touchscreen"
@ -132,6 +134,11 @@
android:value="true" />
</service>
<service
android:name="androidx.work.impl.foreground.SystemForegroundService"
android:foregroundServiceType="dataSync"
tools:node="merge" />
<receiver
android:name=".app.mediathek.controller.downloads.RetryDownloadBroadcastReceiver"
android:exported="false" />

View File

@ -14,6 +14,7 @@ import androidx.core.view.MenuProvider
import androidx.core.view.isVisible
import androidx.navigation.NavController
import androidx.navigation.NavDestination
import androidx.navigation.NavGraph
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.*
import androidx.preference.PreferenceManager
@ -43,7 +44,10 @@ class MainActivity : AppCompatActivity(), MenuProvider {
setContentView(binding.root)
val startFragmentId = settingsRepository.startFragment
navController = binding.navHostFragment.getFragment<NavHostFragment>().navController
navController.graph.setStartDestination(startFragmentId)
appBarConfiguration = AppBarConfiguration(
setOf(
@ -65,6 +69,8 @@ class MainActivity : AppCompatActivity(), MenuProvider {
PreferenceManager.setDefaultValues(application, R.xml.preferences, false)
navController.navigate(startFragmentId)
requestPermissions()
if (!settingsRepository.dynamicColors) {

View File

@ -3,6 +3,8 @@ package de.christinecoenen.code.zapp.app.mediathek.controller.downloads
import android.annotation.SuppressLint
import android.app.PendingIntent
import android.content.Context
import android.content.pm.ServiceInfo
import android.os.Build
import androidx.core.app.NotificationManagerCompat
import androidx.work.*
import de.christinecoenen.code.zapp.app.mediathek.controller.downloads.notifications.DownloadCompletedEventNotification
@ -237,10 +239,18 @@ class DownloadWorker(appContext: Context, workerParams: WorkerParameters) :
}
override suspend fun getForegroundInfo() =
ForegroundInfo(
id.hashCode(),
downloadProgressNotification.build(progress, downloadedBytes, totalBytes)
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ForegroundInfo(
id.hashCode(),
downloadProgressNotification.build(progress, downloadedBytes, totalBytes),
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
)
} else {
ForegroundInfo(
id.hashCode(),
downloadProgressNotification.build(progress, downloadedBytes, totalBytes)
)
}
private suspend fun reportProgress() {
val update = workDataOf(ProgressKey to progress)
@ -256,16 +266,21 @@ class DownloadWorker(appContext: Context, workerParams: WorkerParameters) :
HttpURLConnection.HTTP_NOT_FOUND,
HttpURLConnection.HTTP_GONE ->
ErrorType.FileNotFound
HttpURLConnection.HTTP_UNAUTHORIZED,
HttpURLConnection.HTTP_FORBIDDEN,
451 ->
ErrorType.FileForbidden
429 ->
ErrorType.TooManyRequests
in 400..499 ->
ErrorType.ClientError
in 500..600 ->
ErrorType.ServerError
else ->
ErrorType.Unknown
}

View File

@ -26,6 +26,7 @@ import de.christinecoenen.code.zapp.app.mediathek.ui.list.adapter.PagedMediathek
import de.christinecoenen.code.zapp.databinding.MediathekListFragmentBinding
import de.christinecoenen.code.zapp.databinding.ViewNoShowsBinding
import de.christinecoenen.code.zapp.models.shows.MediathekShow
import de.christinecoenen.code.zapp.utils.system.LifecycleOwnerHelper.launchOnCreated
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.drop
@ -120,13 +121,13 @@ class MediathekListFragment : Fragment(),
binding.list.adapter = adapter.withLoadStateFooter(FooterLoadStateAdapter(adapter::retry))
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.launchOnCreated {
viewmodel.pageFlow.collectLatest { pagingData ->
adapter.submitData(pagingData)
}
}
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.launchOnCreated {
viewmodel
.pageFlow
.drop(1)
@ -138,7 +139,7 @@ class MediathekListFragment : Fragment(),
}
}
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.launchOnCreated {
adapter.loadStateFlow
.map { it.refresh }
.distinctUntilChanged()

View File

@ -28,8 +28,8 @@ class MediathekItemViewHolder(
private val mediathekRepository: MediathekRepository by inject()
private val bgColorDefault = binding.root.context.themeColor(R.attr.backgroundColor)
private val bgColorHighlight by lazy { binding.root.context.themeColor(R.attr.colorSurface) }
private val bgColorDefault = binding.root.context.themeColor(com.google.android.material.R.attr.backgroundColor)
private val bgColorHighlight by lazy { binding.root.context.themeColor(com.google.android.material.R.attr.colorSurface) }
private var isRelevantForUserJob: Job? = null
private var isBookmarkedJob: Job? = null

View File

@ -82,6 +82,7 @@ class SleepTimerBottomSheet : BottomSheetDialogFragment(), SleepTimer.Listener {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
BackgroundPlayerService.bind(requireContext(), backgroundPlayerServiceConnection)
expand()
}
override fun onDestroyView() {

View File

@ -78,6 +78,13 @@ class SettingsRepository(context: Context) {
return prefValueToUiMode(uiMode)
}
val startFragment: Int
get() = when (preferences.getString(context.getString(R.string.pref_key_start_tab), "live")) {
"mediathek" -> R.id.mediathekListFragment
"personal" -> R.id.personalFragment
else -> R.id.channelListFragment
}
fun prefValueToUiMode(prefSetting: String?): Int {
val defaultMode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM else AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY

View File

@ -5,10 +5,16 @@ import android.app.Activity
import android.content.Context
import android.media.AudioManager
import android.util.AttributeSet
import android.view.*
import android.view.GestureDetector
import android.view.GestureDetector.SimpleOnGestureListener
import android.view.Gravity
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.view.ScaleGestureDetector.SimpleOnScaleGestureListener
import android.view.View
import android.view.View.OnTouchListener
import android.view.ViewGroup
import android.view.Window
import android.widget.Toast
import androidx.media3.ui.AspectRatioFrameLayout
import androidx.media3.ui.AspectRatioFrameLayout.AspectRatioListener
@ -81,6 +87,9 @@ class SwipeablePlayerView @JvmOverloads constructor(
} else {
setZoomStateBoxed()
}
subtitleView?.setUserDefaultStyle()
subtitleView?.setUserDefaultTextSize()
}
fun toggleControls() {
@ -183,12 +192,18 @@ class SwipeablePlayerView @JvmOverloads constructor(
return super.onDown(e)
}
// removing this leads to a compilation error with sdk 33
@Suppress("NOTHING_TO_OVERRIDE")
override fun onScroll(
e1: MotionEvent,
e1: MotionEvent?,
e2: MotionEvent,
distanceX: Float,
distanceY: Float
): Boolean {
if (e1 == null) {
return false
}
if (!canUseWipeControls || e1.y <= forbiddenAreaSizeTop) {
return super.onScroll(e1, e2, distanceX, distanceY)
}
@ -213,10 +228,12 @@ class SwipeablePlayerView @JvmOverloads constructor(
adjustBrightness(yPercent)
true
}
e2.x > width - INDICATOR_WIDTH -> {
adjustVolume(yPercent)
true
}
else -> {
endScroll()
super.onScroll(e1, e2, distanceX, distanceY)

View File

@ -1,7 +1,12 @@
# v-next
# 8.3.1
* Absturz bei geänderter Sender-Anordnung gefixt
# 8.3.0
* Einstellungen im Material-Design (danke an Bnyro)
* Schlummerfunktion (danke an Bnyro)
* Exo-Player-Update - sollte Playback-Probleme auf einigen Geräten beheben
* Möglichkeit, Start-Tab in den Einstellungen zu setzen (danke an Bnyro)
* Videos nutzen Untertitel-Stil aus den Android-Systemeinstellungen
# 8.2.0
* Unterstützung für dynamische Gerätefarben

View File

@ -151,6 +151,8 @@
<string name="pref_ui_mode_light">Always light</string>
<string name="pref_ui_mode_dark">Always dark</string>
<string name="pref_start_tab_title">Start page</string>
<string name="stream_quality_cellular_disabled">Don\'t play back</string>
<string name="stream_quality_cellular_lowest">Lowest quality</string>
<string name="stream_quality_cellular_medium">Medium quality</string>

View File

@ -29,6 +29,18 @@
<item>@string/stream_quality_cellular_highest</item>
</string-array>
<string-array name="available_tabs_names">
<item>@string/activity_main_tab_live</item>
<item>@string/activity_main_tab_mediathek</item>
<item>@string/activity_main_tab_personal</item>
</string-array>
<string-array name="available_tabs_values">
<item>live</item>
<item>mediathek</item>
<item>personal</item>
</string-array>
<array name="mediathek_filter_show_length_slider_initial_values">
<item>@fraction/mediathek_filter_min_duration</item>
<item>@fraction/mediathek_filter_max_duration</item>

View File

@ -13,5 +13,6 @@
<string name="pref_key_sleep_timer_delay">pref_key_sleep_timer_delay_millis</string>
<string name="pref_key_player_zoomed">pref_key_player_zoomed</string>
<string name="pref_key_download_to_sd_card">pref_key_download_to_sd_card</string>
<string name="pref_key_start_tab">pref_key_start_tab</string>
</resources>

View File

@ -151,6 +151,8 @@
<string name="pref_ui_mode_light">Immer hell</string>
<string name="pref_ui_mode_dark">Immer dunkel</string>
<string name="pref_start_tab_title">Startseite</string>
<string name="stream_quality_cellular_disabled">Videos nicht abspielen</string>
<string name="stream_quality_cellular_lowest">Niedrigste Qualität</string>
<string name="stream_quality_cellular_medium">Mittlere Qualität</string>

View File

@ -16,9 +16,17 @@
<SwitchPreferenceCompat
android:defaultValue="false"
android:title="@string/pref_dynamic_colors"
android:key="@string/pref_key_dynamic_colors"
android:summary="@string/pref_dynamic_colors_summary"
android:key="@string/pref_key_dynamic_colors"/>
android:title="@string/pref_dynamic_colors" />
<ListPreference
android:defaultValue="live"
android:entries="@array/available_tabs_names"
android:key="@string/pref_key_start_tab"
android:title="@string/pref_start_tab_title"
app:entryValues="@array/available_tabs_values"
app:useSimpleSummaryProvider="true" />
<ListPreference
android:defaultValue="de"

View File

@ -1,9 +1,9 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.koin_version = '3.3.3'
ext.about_libraries_version = '10.6.1'
ext.nav_version = '2.5.3'
ext.koin_version = '3.4.1'
ext.about_libraries_version = '10.8.3'
ext.nav_version = '2.6.0'
repositories {
google()
@ -14,7 +14,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:7.4.2'
classpath 'com.android.tools.build:gradle:8.0.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0"

View File

@ -0,0 +1,5 @@
* Einstellungen im Material-Design (danke an Bnyro)
* Schlummerfunktion (danke an Bnyro)
* Exo-Player-Update - sollte Playback-Probleme auf einigen Geräten beheben
* Möglichkeit, Start-Tab in den Einstellungen zu setzen (danke an Bnyro)
* Videos nutzen Untertitel-Stil aus den Android-Systemeinstellungen

View File

@ -0,0 +1 @@
* Absturz bei geänderter Sender-Anordnung gefixt

View File

@ -0,0 +1,5 @@
* Settings in material design (thanks to Bnyro)
* Sleep timer (thanks to Bnyro)
* Exo player update - should fix playback problems on some devices
* Possibility to set start tab in settings (thanks to Bnyro)
* Videos use subtitle style from Android system settings

View File

@ -0,0 +1 @@
* Fixed crash caused by changed channel order

View File

@ -10,7 +10,7 @@
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
org.gradle.jvmargs=-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
@ -18,3 +18,6 @@ org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryErro
# org.gradle.parallel=true
android.enableJetifier=false
android.useAndroidX=true
android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=true
android.nonFinalResIds=true

View File

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip