Compare commits

...

6 Commits

Author SHA1 Message Date
0fd7cc964f
update gradle wrapper, agp, kotlin and libraries
* kotline 1.9.22 -> 2.0.20
* ktor 2.3.6 -> 3.0.0
* agp 8.3.0 -> 8.7.1
2024-10-29 22:07:06 +01:00
b07a6fd407
update gradle wrapper, agp, kotlin and libraries 2024-03-03 21:21:12 +01:00
7d661712f7
update to kotlin 1.9.0 2023-11-15 15:50:13 +01:00
8fcf047e99
update agp and libraries
* agp 8.1.2 -> 8.1.3
* ktor 2.3.4 -> 2.3.6
* androidx.core 1.10.1 -> 1.12.0
* androidx.navigation 2.6.0 -> 2.7.5
* androidx.lifecycle 2.6.1 -> 2.6.1
* com.google.android.material 1.9.0 -> 1.10.0
* gradle wrapper 8.2.1 -> 8.4
2023-11-15 15:37:44 +01:00
17dbe945e5
mograte MyListFragment to use a simple ViewModel
fixes crashes in MyListFragment if the User closes the fragment with a loading job still running, part of #56
2023-10-15 18:44:22 +02:00
5f609d4c33
update agp and libraries
* agp 8.1.0 -> 8.1.2
* ktor 2.3.2 -> 2.3.4
* kotlinx-serialization-json 1.5.1 -> 1.6.0
2023-09-29 23:47:47 +02:00
11 changed files with 149 additions and 64 deletions

View File

@ -4,9 +4,16 @@ plugins {
id 'org.jetbrains.kotlin.plugin.serialization' version "$kotlin_version" id 'org.jetbrains.kotlin.plugin.serialization' version "$kotlin_version"
} }
kotlin {
jvmToolchain 17
sourceSets.configureEach {
languageSettings.optIn("kotlin.RequiresOptIn")
}
}
android { android {
compileSdk 33 compileSdk 34
buildToolsVersion '30.0.3' buildToolsVersion = '34.0.0'
defaultConfig { defaultConfig {
applicationId "org.mosad.teapod" applicationId "org.mosad.teapod"
@ -22,6 +29,7 @@ android {
buildFeatures { buildFeatures {
viewBinding true viewBinding true
buildConfig true
} }
buildTypes { buildTypes {
@ -32,37 +40,28 @@ android {
} }
} }
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
kotlin.sourceSets.configureEach {
languageSettings.optIn("kotlin.RequiresOptIn")
}
}
namespace 'org.mosad.teapod' namespace 'org.mosad.teapod'
} }
dependencies { dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"]) implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0'
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1' implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3'
implementation 'androidx.core:core-ktx:1.10.1' implementation 'androidx.core:core-ktx:1.13.1'
implementation 'androidx.core:core-splashscreen:1.0.1' implementation 'androidx.core:core-splashscreen:1.0.1'
implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.appcompat:appcompat:1.7.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.navigation:navigation-fragment-ktx:2.6.0' implementation 'androidx.navigation:navigation-fragment-ktx:2.8.3'
implementation 'androidx.navigation:navigation-ui-ktx:2.6.0' implementation 'androidx.navigation:navigation-ui-ktx:2.8.3'
implementation 'androidx.security:security-crypto:1.1.0-alpha06' implementation 'androidx.security:security-crypto:1.1.0-alpha06'
implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1' implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.8.6'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6'
implementation "androidx.paging:paging-runtime-ktx:3.3.2"
implementation 'com.google.android.material:material:1.9.0' implementation 'com.google.android.material:material:1.12.0'
implementation "com.google.android.exoplayer:exoplayer-core:$exo_version" implementation "com.google.android.exoplayer:exoplayer-core:$exo_version"
implementation "com.google.android.exoplayer:exoplayer-hls:$exo_version" implementation "com.google.android.exoplayer:exoplayer-hls:$exo_version"
implementation "com.google.android.exoplayer:exoplayer-dash:$exo_version" implementation "com.google.android.exoplayer:exoplayer-dash:$exo_version"
@ -71,7 +70,7 @@ dependencies {
implementation 'com.facebook.shimmer:shimmer:0.5.0' implementation 'com.facebook.shimmer:shimmer:0.5.0'
implementation 'com.github.bumptech.glide:glide:4.15.1' implementation 'com.github.bumptech.glide:glide:4.16.0'
implementation 'jp.wasabeef:glide-transformations:4.3.0' implementation 'jp.wasabeef:glide-transformations:4.3.0'
implementation "io.ktor:ktor-client-core:$ktor_version" implementation "io.ktor:ktor-client-core:$ktor_version"
@ -80,8 +79,8 @@ dependencies {
implementation "io.ktor:ktor-serialization-kotlinx-json:$ktor_version" implementation "io.ktor:ktor-serialization-kotlinx-json:$ktor_version"
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.ext:junit:1.2.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
} }

View File

@ -1,17 +1,21 @@
package org.mosad.teapod.ui.activity.main.fragments package org.mosad.teapod.ui.activity.main.fragments
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.adapter.FragmentStateAdapter
import com.google.android.material.tabs.TabLayoutMediator import com.google.android.material.tabs.TabLayoutMediator
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.mosad.teapod.R import org.mosad.teapod.R
import org.mosad.teapod.databinding.FragmentMyListsBinding import org.mosad.teapod.databinding.FragmentMyListsBinding
import org.mosad.teapod.parser.crunchyroll.Crunchyroll import org.mosad.teapod.ui.activity.main.viewmodel.MyListsFragmentViewModel
import org.mosad.teapod.util.toItemMediaList import org.mosad.teapod.util.toItemMediaList
class MyListsFragment : Fragment() { class MyListsFragment : Fragment() {
@ -19,6 +23,8 @@ class MyListsFragment : Fragment() {
private lateinit var binding: FragmentMyListsBinding private lateinit var binding: FragmentMyListsBinding
private lateinit var pagerAdapter: FragmentStateAdapter private lateinit var pagerAdapter: FragmentStateAdapter
private val model: MyListsFragmentViewModel by viewModels()
private val fragments = arrayListOf<Fragment>() private val fragments = arrayListOf<Fragment>()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
@ -33,7 +39,6 @@ class MyListsFragment : Fragment() {
pagerAdapter = ScreenSlidePagerAdapter(this) pagerAdapter = ScreenSlidePagerAdapter(this)
binding.pagerMyLists.adapter = pagerAdapter binding.pagerMyLists.adapter = pagerAdapter
// TODO is position 0 always episodes? (and 1 always similar titles)
TabLayoutMediator(binding.tabMyLists, binding.pagerMyLists) { tab, position -> TabLayoutMediator(binding.tabMyLists, binding.pagerMyLists) { tab, position ->
tab.text = when(position) { tab.text = when(position) {
0 -> getString(R.string.my_list) 0 -> getString(R.string.my_list)
@ -43,15 +48,33 @@ class MyListsFragment : Fragment() {
} }
}.attach() }.attach()
lifecycleScope.launch { viewLifecycleOwner.lifecycleScope.launch {
val items = Crunchyroll.watchlist(50) viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
model.onUiState(viewLifecycleOwner.lifecycleScope) { uiState ->
MediaFragmentSimilar(items.toItemMediaList()).also { when (uiState) {
fragments.add(it) is MyListsFragmentViewModel.UiState.Normal -> bindUiStateNormal(uiState)
pagerAdapter.notifyItemInserted(fragments.indexOf(it)) is MyListsFragmentViewModel.UiState.Loading -> bindUiStateLoading()
is MyListsFragmentViewModel.UiState.Error -> bindUiStateError(uiState)
}
}
} }
} }
}
private fun bindUiStateNormal(uiState: MyListsFragmentViewModel.UiState.Normal) {
MediaFragmentSimilar(uiState.watchlistItems.toItemMediaList()).also {
fragments.add(it)
pagerAdapter.notifyItemInserted(fragments.indexOf(it))
}
}
private fun bindUiStateLoading() {
// currently not used
}
private fun bindUiStateError(uiState: MyListsFragmentViewModel.UiState.Error) {
// currently not used
Log.e(javaClass.name, "A error occurred while loading a UiState: ${uiState.message}")
} }
/** /**

View File

@ -32,7 +32,7 @@ import kotlinx.coroutines.launch
import org.mosad.teapod.parser.crunchyroll.* import org.mosad.teapod.parser.crunchyroll.*
import kotlin.random.Random import kotlin.random.Random
class HomeViewModel : ViewModel() { class HomeViewModel : ViewModel() {
private val WATCHLIST_LENGTH = 50 private val WATCHLIST_LENGTH = 50

View File

@ -0,0 +1,50 @@
package org.mosad.teapod.ui.activity.main.viewmodel
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import org.mosad.teapod.parser.crunchyroll.Crunchyroll
import org.mosad.teapod.parser.crunchyroll.Item
class MyListsFragmentViewModel : ViewModel() {
private val WATCHLIST_LENGTH = 50
private val uiState = MutableStateFlow<UiState>(UiState.Loading)
sealed class UiState {
object Loading : UiState()
data class Normal(
val watchlistItems: List<Item>
) : UiState()
data class Error(val message: String?) : UiState()
}
init {
load()
}
fun onUiState(scope: LifecycleCoroutineScope, collector: (UiState) -> Unit) {
scope.launch { uiState.collect { collector(it) } }
}
fun load() {
viewModelScope.launch {
uiState.emit(UiState.Loading)
try {
// run the loading in parallel to speed up the process
val watchlistJob = viewModelScope.async { Crunchyroll.watchlist(WATCHLIST_LENGTH).data }
uiState.emit(
UiState.Normal(watchlistJob.await())
)
} catch (e: Exception) {
uiState.emit(UiState.Error(e.message))
}
}
}
}

View File

@ -14,6 +14,8 @@ import android.widget.TextView
import androidx.core.view.children import androidx.core.view.children
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import org.mosad.teapod.R import org.mosad.teapod.R
import org.mosad.teapod.databinding.PlayerLanguageSettingsBinding import org.mosad.teapod.databinding.PlayerLanguageSettingsBinding
import org.mosad.teapod.ui.activity.player.PlayerViewModel import org.mosad.teapod.ui.activity.player.PlayerViewModel
@ -81,8 +83,10 @@ class LanguageSettingsDialogFragment : DialogFragment() {
binding.buttonCloseLanguageSettings.setOnClickListener { dismiss() } binding.buttonCloseLanguageSettings.setOnClickListener { dismiss() }
binding.buttonCancel.setOnClickListener { dismiss() } binding.buttonCancel.setOnClickListener { dismiss() }
binding.buttonSelect.setOnClickListener { binding.buttonSelect.setOnClickListener {
model.setLanguage(selectedAudioLocale, selectedSubtitleLocale) lifecycleScope.launch {
dismiss() model.setLanguage(selectedAudioLocale, selectedSubtitleLocale)
dismiss()
}
} }
// initially hide the status and navigation bar // initially hide the status and navigation bar

View File

@ -1,14 +1,14 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = "1.8.22" ext.kotlin_version = "2.0.20"
ext.ktor_version = "2.3.2" ext.ktor_version = "3.0.0"
ext.exo_version = "2.18.7" ext.exo_version = "2.18.7"
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:8.1.0' classpath 'com.android.tools.build:gradle:8.7.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
@ -23,6 +23,6 @@ allprojects {
} }
} }
task clean(type: Delete) { tasks.register('clean', Delete) {
delete rootProject.buildDir delete rootProject.layout.buildDirectory
} }

View File

@ -16,9 +16,8 @@ org.gradle.jvmargs=-Xmx2048m
# https://developer.android.com/topic/libraries/support-library/androidx-rn # https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX # Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true android.enableJetifier=false
# Kotlin code style for this project: "official" or "obsolete": # Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official kotlin.code.style=official
android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=false android.nonTransitiveRClass=false
android.nonFinalResIds=false android.nonFinalResIds=false

Binary file not shown.

View File

@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

27
gradlew vendored
View File

@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
# SPDX-License-Identifier: Apache-2.0
#
############################################################################## ##############################################################################
# #
@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop. # Darwin, MinGW, and NonStop.
# #
# (3) This script is generated from the Groovy template # (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project. # within the Gradle project.
# #
# You can find Gradle at https://github.com/gradle/gradle/. # You can find Gradle at https://github.com/gradle/gradle/.
@ -83,7 +85,9 @@ done
# This is normally unused # This is normally unused
# shellcheck disable=SC2034 # shellcheck disable=SC2034
APP_BASE_NAME=${0##*/} APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD=maximum
@ -130,10 +134,13 @@ location of your Java installation."
fi fi
else else
JAVACMD=java JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
@ -141,7 +148,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #( case $MAX_FD in #(
max*) max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045 # shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) || MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit" warn "Could not query maximum file descriptor limit"
esac esac
@ -149,7 +156,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #( '' | soft) :;; #(
*) *)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045 # shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" || ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD" warn "Could not set maximum file descriptor limit to $MAX_FD"
esac esac
@ -198,11 +205,11 @@ fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command; # Collect all arguments for the java command:
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# shell script including quotes and variable substitutions, so put them in # and any embedded shellness will be escaped.
# double quotes to make sure that they get re-expanded; and # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# * put everything else in single quotes, so that it's not re-expanded. # treated as '${Hostname}' itself on the command line.
set -- \ set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \ "-Dorg.gradle.appname=$APP_BASE_NAME" \

22
gradlew.bat vendored
View File

@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and @rem See the License for the specific language governing permissions and
@rem limitations under the License. @rem limitations under the License.
@rem @rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off @if "%DEBUG%"=="" @echo off
@rem ########################################################################## @rem ##########################################################################
@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute if %ERRORLEVEL% equ 0 goto execute
echo. echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. echo location of your Java installation. 1>&2
goto fail goto fail
@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute if exist "%JAVA_EXE%" goto execute
echo. echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. echo location of your Java installation. 1>&2
goto fail goto fail