From c9a5a93c349d7e005af633932d0cd26955e3e040 Mon Sep 17 00:00:00 2001 From: SkyD666 Date: Sat, 14 Sep 2024 22:43:14 +0800 Subject: [PATCH] [optimize|fix|build] Optimize use of Flow in MVI mode; fix an issue that player progress value is Nan; update dependencies --- app/build.gradle.kts | 4 +- .../anivu/base/mvi/AbstractMviViewModel.kt | 38 ++++++------------- .../java/com/skyd/anivu/base/mvi/MviIntent.kt | 3 +- .../ui/mpv/controller/ProgressIndicator.kt | 4 +- .../skyd/anivu/ui/mpv/mvi/PlayerViewModel.kt | 17 ++------- .../ui/screen/about/license/LicenseScreen.kt | 5 +++ .../ui/screen/about/update/UpdateViewModel.kt | 19 +++------- .../ui/screen/article/ArticleViewModel.kt | 16 ++------ .../ui/screen/download/DownloadViewModel.kt | 20 ++-------- .../anivu/ui/screen/feed/FeedViewModel.kt | 17 ++------- .../feed/reorder/ReorderGroupViewModel.kt | 17 ++------- .../requestheaders/RequestHeadersViewModel.kt | 17 ++------- .../screen/filepicker/FilePickerViewModel.kt | 14 ++----- .../anivu/ui/screen/media/MediaViewModel.kt | 17 ++------- .../screen/media/list/MediaListViewModel.kt | 17 ++------- .../anivu/ui/screen/read/ReadViewModel.kt | 17 ++------- .../anivu/ui/screen/search/SearchViewModel.kt | 18 +++------ .../ui/screen/settings/data/DataViewModel.kt | 17 ++------- .../exportopml/ExportOpmlViewModel.kt | 17 ++------- .../importopml/ImportOpmlViewModel.kt | 17 ++------- gradle/libs.versions.toml | 5 ++- 21 files changed, 87 insertions(+), 229 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 94fdc744..c59fbeb5 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -22,7 +22,7 @@ android { minSdk = 24 targetSdk = 35 versionCode = 24 - versionName = "2.1-beta03" + versionName = "2.1-beta04" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" @@ -211,7 +211,7 @@ dependencies { implementation(libs.rome) implementation(libs.rome.modules) - implementation("be.ceau:opml-parser:3.1.0") { + implementation(libs.ceau.opmlparser) { exclude(group = "net.sf.kxml", module = "kxml2") } diff --git a/app/src/main/java/com/skyd/anivu/base/mvi/AbstractMviViewModel.kt b/app/src/main/java/com/skyd/anivu/base/mvi/AbstractMviViewModel.kt index faf6d84c..eb38dca8 100644 --- a/app/src/main/java/com/skyd/anivu/base/mvi/AbstractMviViewModel.kt +++ b/app/src/main/java/com/skyd/anivu/base/mvi/AbstractMviViewModel.kt @@ -10,6 +10,7 @@ import androidx.lifecycle.viewModelScope import com.skyd.anivu.BuildConfig import com.skyd.anivu.util.debug import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.MainCoroutineDispatcher import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.onFailure import kotlinx.coroutines.channels.onSuccess @@ -19,10 +20,9 @@ import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.receiveAsFlow -import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.flow.stateIn import java.util.concurrent.atomic.AtomicInteger import kotlin.LazyThreadSafetyMode.PUBLICATION @@ -66,7 +66,7 @@ abstract class AbstractMviViewModel(Channel.UNLIMITED) - private val intentMutableFlow = MutableSharedFlow(extraBufferCapacity = 2) + private val intentMutableFlow = MutableSharedFlow(extraBufferCapacity = Int.MAX_VALUE) final override val singleEvent: Flow = eventChannel.receiveAsFlow() @@ -88,7 +88,7 @@ abstract class AbstractMviViewModel get() = intentMutableFlow + protected val intentFlow: Flow get() = intentMutableFlow.asSharedFlow() // Extensions on Flow using viewModelScope. + protected fun Flow.toState(initialValue: S) = stateIn( + viewModelScope, + SharingStarted.Eagerly, + initialValue + ) + protected fun Flow.debugLog(subject: String): Flow = if (BuildConfig.DEBUG) { onEach { Log.i(logTag, ">>> $subject: $it") } @@ -137,24 +141,6 @@ abstract class AbstractMviViewModel Flow.shareWhileSubscribed(): SharedFlow = - shareIn(viewModelScope, SharingStarted.WhileSubscribed()) - - protected fun Flow.stateWithInitialNullWhileSubscribed(): StateFlow = - stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null) - - @Deprecated( - message = "This Flow is already shared in viewModelScope, so you don't need to share it again.", - replaceWith = ReplaceWith("this"), - level = DeprecationLevel.ERROR - ) - protected fun SharedFlow.shareWhileSubscribed(): SharedFlow = this - private companion object { private const val MAX_TAG_LENGTH = 23 } diff --git a/app/src/main/java/com/skyd/anivu/base/mvi/MviIntent.kt b/app/src/main/java/com/skyd/anivu/base/mvi/MviIntent.kt index cb841117..0c17fde1 100644 --- a/app/src/main/java/com/skyd/anivu/base/mvi/MviIntent.kt +++ b/app/src/main/java/com/skyd/anivu/base/mvi/MviIntent.kt @@ -37,8 +37,7 @@ fun intentChannel .consumeAsFlow() .run { if (startWith == null) this else startWith(startWith) } - .onEach(this@getDispatcher::processIntent) - .collect() + .collect(this@getDispatcher::processIntent) } } return remember(*keys, intentChannel) { diff --git a/app/src/main/java/com/skyd/anivu/ui/mpv/controller/ProgressIndicator.kt b/app/src/main/java/com/skyd/anivu/ui/mpv/controller/ProgressIndicator.kt index 88c66e07..c1192604 100644 --- a/app/src/main/java/com/skyd/anivu/ui/mpv/controller/ProgressIndicator.kt +++ b/app/src/main/java/com/skyd/anivu/ui/mpv/controller/ProgressIndicator.kt @@ -13,7 +13,9 @@ import com.skyd.anivu.ui.mpv.controller.state.PlayState @Composable fun ProgressIndicator(modifier: Modifier = Modifier, playState: () -> PlayState) { val animatedProgress by animateFloatAsState( - targetValue = playState().run { currentPosition.toFloat() / duration }, + targetValue = playState().run { + if (duration == 0) 0f else currentPosition.toFloat() / duration + }, animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec, label = "playerProgressIndicatorAnimate" ) diff --git a/app/src/main/java/com/skyd/anivu/ui/mpv/mvi/PlayerViewModel.kt b/app/src/main/java/com/skyd/anivu/ui/mpv/mvi/PlayerViewModel.kt index 066174c4..bc3ff788 100644 --- a/app/src/main/java/com/skyd/anivu/ui/mpv/mvi/PlayerViewModel.kt +++ b/app/src/main/java/com/skyd/anivu/ui/mpv/mvi/PlayerViewModel.kt @@ -1,6 +1,5 @@ package com.skyd.anivu.ui.mpv.mvi -import androidx.lifecycle.viewModelScope import com.skyd.anivu.base.mvi.AbstractMviViewModel import com.skyd.anivu.ext.catchMap import com.skyd.anivu.model.bean.MediaPlayHistoryBean @@ -9,8 +8,6 @@ import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.filterIsInstance @@ -20,7 +17,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.scan -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.take import kotlinx.coroutines.launch import javax.inject.Inject @@ -46,20 +42,15 @@ class PlayerViewModel @Inject constructor( val initialVS = PlayerState.initial() viewState = merge( - intentSharedFlow.filterIsInstance().take(1), - intentSharedFlow.filterNot { it is PlayerIntent.TrySeekToLast } + intentFlow.filterIsInstance().take(1), + intentFlow.filterNot { it is PlayerIntent.TrySeekToLast } ) - .shareWhileSubscribed() .toPlayerPartialStateChangeFlow() .debugLog("PlayerPartialStateChange") .sendSingleEvent() .scan(initialVS) { vs, change -> change.reduce(vs) } .debugLog("ViewState") - .stateIn( - viewModelScope, - SharingStarted.Eagerly, - initialVS - ) + .toState(initialVS) } private fun Flow.sendSingleEvent(): Flow { @@ -79,7 +70,7 @@ class PlayerViewModel @Inject constructor( } } - private fun SharedFlow.toPlayerPartialStateChangeFlow(): Flow { + private fun Flow.toPlayerPartialStateChangeFlow(): Flow { return merge( filterIsInstance().flatMapConcat { intent -> playerRepo.requestLastPlayPosition(intent.path).map { diff --git a/app/src/main/java/com/skyd/anivu/ui/screen/about/license/LicenseScreen.kt b/app/src/main/java/com/skyd/anivu/ui/screen/about/license/LicenseScreen.kt index 2705e482..7dc0fa00 100644 --- a/app/src/main/java/com/skyd/anivu/ui/screen/about/license/LicenseScreen.kt +++ b/app/src/main/java/com/skyd/anivu/ui/screen/about/license/LicenseScreen.kt @@ -182,5 +182,10 @@ private fun getLicenseList(): List { license = "Apache-2.0", link = "https://github.com/Calvin-LL/Reorderable", ), + LicenseBean( + name = "OPML Parser", + license = "Apache-2.0", + link = "https://github.com/mdewilde/opml-parser", + ), ).sortedBy { it.name } } \ No newline at end of file diff --git a/app/src/main/java/com/skyd/anivu/ui/screen/about/update/UpdateViewModel.kt b/app/src/main/java/com/skyd/anivu/ui/screen/about/update/UpdateViewModel.kt index 88e30c38..0e8607d0 100644 --- a/app/src/main/java/com/skyd/anivu/ui/screen/about/update/UpdateViewModel.kt +++ b/app/src/main/java/com/skyd/anivu/ui/screen/about/update/UpdateViewModel.kt @@ -1,6 +1,5 @@ package com.skyd.anivu.ui.screen.about.update -import androidx.lifecycle.viewModelScope import com.skyd.anivu.appContext import com.skyd.anivu.base.mvi.AbstractMviViewModel import com.skyd.anivu.config.Const @@ -12,8 +11,6 @@ import com.skyd.anivu.ext.toDateTimeString import com.skyd.anivu.model.repository.UpdateRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterIsInstance @@ -23,7 +20,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.scan -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.take import okhttp3.internal.toLongOrDefault import java.text.SimpleDateFormat @@ -41,21 +37,16 @@ class UpdateViewModel @Inject constructor(private var updateRepo: UpdateReposito val initialVS = UpdateState.initial() viewState = merge( - intentSharedFlow.filter { it is UpdateIntent.CheckUpdate && !it.isRetry }.take(1), - intentSharedFlow.filter { it is UpdateIntent.CheckUpdate && it.isRetry }, - intentSharedFlow.filterNot { it is UpdateIntent.CheckUpdate } + intentFlow.filter { it is UpdateIntent.CheckUpdate && !it.isRetry }.take(1), + intentFlow.filter { it is UpdateIntent.CheckUpdate && it.isRetry }, + intentFlow.filterNot { it is UpdateIntent.CheckUpdate } ) - .shareWhileSubscribed() .toUpdatePartialStateChangeFlow() .debugLog("UpdatePartialStateChange") .sendSingleEvent() .scan(initialVS) { vs, change -> change.reduce(vs) } .debugLog("ViewState") - .stateIn( - viewModelScope, - SharingStarted.Eagerly, - initialVS - ) + .toState(initialVS) } private fun Flow.sendSingleEvent(): Flow { @@ -71,7 +62,7 @@ class UpdateViewModel @Inject constructor(private var updateRepo: UpdateReposito } } - private fun SharedFlow.toUpdatePartialStateChangeFlow(): Flow { + private fun Flow.toUpdatePartialStateChangeFlow(): Flow { return merge( filterIsInstance().flatMapConcat { updateRepo.checkUpdate().map { data -> diff --git a/app/src/main/java/com/skyd/anivu/ui/screen/article/ArticleViewModel.kt b/app/src/main/java/com/skyd/anivu/ui/screen/article/ArticleViewModel.kt index 130adea4..d4076a7a 100644 --- a/app/src/main/java/com/skyd/anivu/ui/screen/article/ArticleViewModel.kt +++ b/app/src/main/java/com/skyd/anivu/ui/screen/article/ArticleViewModel.kt @@ -8,8 +8,6 @@ import com.skyd.anivu.ext.startWith import com.skyd.anivu.model.repository.ArticleRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filterIsInstance @@ -20,7 +18,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.scan -import kotlinx.coroutines.flow.stateIn import javax.inject.Inject @HiltViewModel @@ -34,20 +31,15 @@ class ArticleViewModel @Inject constructor( val initialVS = ArticleState.initial() viewState = merge( - intentSharedFlow.filterIsInstance().distinctUntilChanged(), - intentSharedFlow.filterNot { it is ArticleIntent.Init } + intentFlow.filterIsInstance().distinctUntilChanged(), + intentFlow.filterNot { it is ArticleIntent.Init } ) - .shareWhileSubscribed() .toArticlePartialStateChangeFlow() .debugLog("ArticlePartialStateChange") .sendSingleEvent() .scan(initialVS) { vs, change -> change.reduce(vs) } .debugLog("ViewState") - .stateIn( - viewModelScope, - SharingStarted.Eagerly, - initialVS - ) + .toState(initialVS) } private fun Flow.sendSingleEvent(): Flow { @@ -75,7 +67,7 @@ class ArticleViewModel @Inject constructor( } } - private fun SharedFlow.toArticlePartialStateChangeFlow(): Flow { + private fun Flow.toArticlePartialStateChangeFlow(): Flow { return merge( filterIsInstance().flatMapConcat { intent -> flowOf(articleRepo.requestArticleList(intent.urls).cachedIn(viewModelScope)).map { diff --git a/app/src/main/java/com/skyd/anivu/ui/screen/download/DownloadViewModel.kt b/app/src/main/java/com/skyd/anivu/ui/screen/download/DownloadViewModel.kt index cb165a90..efd55fb3 100644 --- a/app/src/main/java/com/skyd/anivu/ui/screen/download/DownloadViewModel.kt +++ b/app/src/main/java/com/skyd/anivu/ui/screen/download/DownloadViewModel.kt @@ -1,26 +1,19 @@ package com.skyd.anivu.ui.screen.download -import androidx.lifecycle.viewModelScope -import com.skyd.anivu.appContext import com.skyd.anivu.base.mvi.AbstractMviViewModel import com.skyd.anivu.base.mvi.MviSingleEvent import com.skyd.anivu.ext.catchMap import com.skyd.anivu.ext.startWith import com.skyd.anivu.model.repository.download.DownloadRepository -import com.skyd.anivu.model.worker.download.DownloadTorrentWorker import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.filterNot import kotlinx.coroutines.flow.flatMapConcat -import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.scan -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.take import javax.inject.Inject @@ -35,22 +28,17 @@ class DownloadViewModel @Inject constructor( val initialVS = DownloadState.initial() viewState = merge( - intentSharedFlow.filterIsInstance().take(1), - intentSharedFlow.filterNot { it is DownloadIntent.Init } + intentFlow.filterIsInstance().take(1), + intentFlow.filterNot { it is DownloadIntent.Init } ) - .shareWhileSubscribed() .toReadPartialStateChangeFlow() .debugLog("DownloadPartialStateChange") .scan(initialVS) { vs, change -> change.reduce(vs) } .debugLog("ViewState") - .stateIn( - viewModelScope, - SharingStarted.Eagerly, - initialVS - ) + .toState(initialVS) } - private fun SharedFlow.toReadPartialStateChangeFlow(): Flow { + private fun Flow.toReadPartialStateChangeFlow(): Flow { return merge( filterIsInstance().flatMapConcat { downloadRepo.requestDownloadingVideos().map { diff --git a/app/src/main/java/com/skyd/anivu/ui/screen/feed/FeedViewModel.kt b/app/src/main/java/com/skyd/anivu/ui/screen/feed/FeedViewModel.kt index 71b92cc6..b68e478d 100644 --- a/app/src/main/java/com/skyd/anivu/ui/screen/feed/FeedViewModel.kt +++ b/app/src/main/java/com/skyd/anivu/ui/screen/feed/FeedViewModel.kt @@ -1,6 +1,5 @@ package com.skyd.anivu.ui.screen.feed -import androidx.lifecycle.viewModelScope import com.skyd.anivu.base.mvi.AbstractMviViewModel import com.skyd.anivu.ext.catchMap import com.skyd.anivu.ext.startWith @@ -8,8 +7,6 @@ import com.skyd.anivu.model.repository.ArticleRepository import com.skyd.anivu.model.repository.feed.FeedRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.filterNot @@ -18,7 +15,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.scan -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.take import javax.inject.Inject @@ -34,20 +30,15 @@ class FeedViewModel @Inject constructor( val initialVS = FeedState.initial() viewState = merge( - intentSharedFlow.filterIsInstance().take(1), - intentSharedFlow.filterNot { it is FeedIntent.Init } + intentFlow.filterIsInstance().take(1), + intentFlow.filterNot { it is FeedIntent.Init } ) - .shareWhileSubscribed() .toFeedPartialStateChangeFlow() .debugLog("FeedPartialStateChange") .sendSingleEvent() .scan(initialVS) { vs, change -> change.reduce(vs) } .debugLog("ViewState") - .stateIn( - viewModelScope, - SharingStarted.Eagerly, - initialVS - ) + .toState(initialVS) } private fun Flow.sendSingleEvent(): Flow { @@ -128,7 +119,7 @@ class FeedViewModel @Inject constructor( } } - private fun SharedFlow.toFeedPartialStateChangeFlow(): Flow { + private fun Flow.toFeedPartialStateChangeFlow(): Flow { return merge( filterIsInstance().flatMapConcat { feedRepo.requestGroupAnyList().map { diff --git a/app/src/main/java/com/skyd/anivu/ui/screen/feed/reorder/ReorderGroupViewModel.kt b/app/src/main/java/com/skyd/anivu/ui/screen/feed/reorder/ReorderGroupViewModel.kt index a28582a6..29842ec4 100644 --- a/app/src/main/java/com/skyd/anivu/ui/screen/feed/reorder/ReorderGroupViewModel.kt +++ b/app/src/main/java/com/skyd/anivu/ui/screen/feed/reorder/ReorderGroupViewModel.kt @@ -1,14 +1,11 @@ package com.skyd.anivu.ui.screen.feed.reorder -import androidx.lifecycle.viewModelScope import com.skyd.anivu.base.mvi.AbstractMviViewModel import com.skyd.anivu.ext.catchMap import com.skyd.anivu.ext.startWith import com.skyd.anivu.model.repository.feed.ReorderGroupRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.filterNot @@ -18,7 +15,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.scan -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.take import javax.inject.Inject @@ -33,20 +29,15 @@ class ReorderGroupViewModel @Inject constructor( val initialVS = ReorderGroupState.initial() viewState = merge( - intentSharedFlow.filterIsInstance().take(1), - intentSharedFlow.filterNot { it is ReorderGroupIntent.Init } + intentFlow.filterIsInstance().take(1), + intentFlow.filterNot { it is ReorderGroupIntent.Init } ) - .shareWhileSubscribed() .toReorderGroupPartialStateChangeFlow() .debugLog("ReorderGroupPartialStateChange") .sendSingleEvent() .scan(initialVS) { vs, change -> change.reduce(vs) } .debugLog("ViewState") - .stateIn( - viewModelScope, - SharingStarted.Eagerly, - initialVS - ) + .toState(initialVS) } private fun Flow.sendSingleEvent(): Flow { @@ -64,7 +55,7 @@ class ReorderGroupViewModel @Inject constructor( } } - private fun SharedFlow.toReorderGroupPartialStateChangeFlow(): Flow { + private fun Flow.toReorderGroupPartialStateChangeFlow(): Flow { return merge( filterIsInstance().flatMapConcat { reorderGroupRepo.requestGroupList().map { diff --git a/app/src/main/java/com/skyd/anivu/ui/screen/feed/requestheaders/RequestHeadersViewModel.kt b/app/src/main/java/com/skyd/anivu/ui/screen/feed/requestheaders/RequestHeadersViewModel.kt index d21c92c4..ce6b3acb 100644 --- a/app/src/main/java/com/skyd/anivu/ui/screen/feed/requestheaders/RequestHeadersViewModel.kt +++ b/app/src/main/java/com/skyd/anivu/ui/screen/feed/requestheaders/RequestHeadersViewModel.kt @@ -1,14 +1,11 @@ package com.skyd.anivu.ui.screen.feed.requestheaders -import androidx.lifecycle.viewModelScope import com.skyd.anivu.base.mvi.AbstractMviViewModel import com.skyd.anivu.ext.catchMap import com.skyd.anivu.ext.startWith import com.skyd.anivu.model.repository.feed.RequestHeadersRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.filterNot @@ -17,7 +14,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.scan -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.take import javax.inject.Inject @@ -32,20 +28,15 @@ class RequestHeadersViewModel @Inject constructor( val initialVS = RequestHeadersState.initial() viewState = merge( - intentSharedFlow.filterIsInstance().take(1), - intentSharedFlow.filterNot { it is RequestHeadersIntent.Init } + intentFlow.filterIsInstance().take(1), + intentFlow.filterNot { it is RequestHeadersIntent.Init } ) - .shareWhileSubscribed() .toRequestHeadersPartialStateChangeFlow() .debugLog("RequestHeadersPartialStateChange") .sendSingleEvent() .scan(initialVS) { vs, change -> change.reduce(vs) } .debugLog("ViewState") - .stateIn( - viewModelScope, - SharingStarted.Eagerly, - initialVS - ) + .toState(initialVS) } private fun Flow.sendSingleEvent(): Flow { @@ -63,7 +54,7 @@ class RequestHeadersViewModel @Inject constructor( } } - private fun SharedFlow.toRequestHeadersPartialStateChangeFlow(): Flow { + private fun Flow.toRequestHeadersPartialStateChangeFlow(): Flow { return merge( filterIsInstance().flatMapConcat { intent -> requestHeadersRepo.getFeedHeaders(intent.feedUrl).map { diff --git a/app/src/main/java/com/skyd/anivu/ui/screen/filepicker/FilePickerViewModel.kt b/app/src/main/java/com/skyd/anivu/ui/screen/filepicker/FilePickerViewModel.kt index d2cb11d8..bae44114 100644 --- a/app/src/main/java/com/skyd/anivu/ui/screen/filepicker/FilePickerViewModel.kt +++ b/app/src/main/java/com/skyd/anivu/ui/screen/filepicker/FilePickerViewModel.kt @@ -1,14 +1,11 @@ package com.skyd.anivu.ui.screen.filepicker -import androidx.lifecycle.viewModelScope import com.skyd.anivu.base.mvi.AbstractMviViewModel import com.skyd.anivu.ext.catchMap import com.skyd.anivu.ext.startWith import com.skyd.anivu.model.repository.FilePickerRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.flatMapConcat @@ -16,7 +13,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.scan -import kotlinx.coroutines.flow.stateIn import javax.inject.Inject @HiltViewModel @@ -29,17 +25,13 @@ class FilePickerViewModel @Inject constructor( init { val initialVS = FilePickerState.initial() - viewState = intentSharedFlow + viewState = intentFlow .toFilePickerPartialStateChangeFlow() .debugLog("FilePickerPartialStateChange") .sendSingleEvent() .scan(initialVS) { vs, change -> change.reduce(vs) } .debugLog("ViewState") - .stateIn( - viewModelScope, - SharingStarted.Eagerly, - initialVS - ) + .toState(initialVS) } private fun Flow.sendSingleEvent(): Flow { @@ -54,7 +46,7 @@ class FilePickerViewModel @Inject constructor( } } - private fun SharedFlow.toFilePickerPartialStateChangeFlow(): Flow { + private fun Flow.toFilePickerPartialStateChangeFlow(): Flow { return merge( merge( filterIsInstance() diff --git a/app/src/main/java/com/skyd/anivu/ui/screen/media/MediaViewModel.kt b/app/src/main/java/com/skyd/anivu/ui/screen/media/MediaViewModel.kt index 50c38ee5..6b157157 100644 --- a/app/src/main/java/com/skyd/anivu/ui/screen/media/MediaViewModel.kt +++ b/app/src/main/java/com/skyd/anivu/ui/screen/media/MediaViewModel.kt @@ -1,14 +1,11 @@ package com.skyd.anivu.ui.screen.media -import androidx.lifecycle.viewModelScope import com.skyd.anivu.base.mvi.AbstractMviViewModel import com.skyd.anivu.ext.catchMap import com.skyd.anivu.ext.startWith import com.skyd.anivu.model.repository.MediaRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filterIsInstance @@ -18,7 +15,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.scan -import kotlinx.coroutines.flow.stateIn import javax.inject.Inject @HiltViewModel @@ -32,20 +28,15 @@ class MediaViewModel @Inject constructor( val initialVS = MediaState.initial() viewState = merge( - intentSharedFlow.filterIsInstance().distinctUntilChanged(), - intentSharedFlow.filterNot { it is MediaIntent.Init } + intentFlow.filterIsInstance().distinctUntilChanged(), + intentFlow.filterNot { it is MediaIntent.Init } ) - .shareWhileSubscribed() .toMediaPartialStateChangeFlow() .debugLog("MediaPartialStateChange") .sendSingleEvent() .scan(initialVS) { vs, change -> change.reduce(vs) } .debugLog("ViewState") - .stateIn( - viewModelScope, - SharingStarted.Eagerly, - initialVS - ) + .toState(initialVS) } private fun Flow.sendSingleEvent(): Flow { @@ -87,7 +78,7 @@ class MediaViewModel @Inject constructor( } } - private fun SharedFlow.toMediaPartialStateChangeFlow(): Flow { + private fun Flow.toMediaPartialStateChangeFlow(): Flow { return merge( merge( filterIsInstance().filterNot { it.path.isNullOrBlank() }, diff --git a/app/src/main/java/com/skyd/anivu/ui/screen/media/list/MediaListViewModel.kt b/app/src/main/java/com/skyd/anivu/ui/screen/media/list/MediaListViewModel.kt index 8c1215fe..b646d467 100644 --- a/app/src/main/java/com/skyd/anivu/ui/screen/media/list/MediaListViewModel.kt +++ b/app/src/main/java/com/skyd/anivu/ui/screen/media/list/MediaListViewModel.kt @@ -1,14 +1,11 @@ package com.skyd.anivu.ui.screen.media.list -import androidx.lifecycle.viewModelScope import com.skyd.anivu.base.mvi.AbstractMviViewModel import com.skyd.anivu.ext.catchMap import com.skyd.anivu.ext.startWith import com.skyd.anivu.model.repository.MediaRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged @@ -19,7 +16,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.scan -import kotlinx.coroutines.flow.stateIn import javax.inject.Inject @HiltViewModel @@ -33,20 +29,15 @@ class MediaListViewModel @Inject constructor( val initialVS = MediaListState.initial() viewState = merge( - intentSharedFlow.filterIsInstance().distinctUntilChanged(), - intentSharedFlow.filterNot { it is MediaListIntent.Init } + intentFlow.filterIsInstance().distinctUntilChanged(), + intentFlow.filterNot { it is MediaListIntent.Init } ) - .shareWhileSubscribed() .toMediaListPartialStateChangeFlow() .debugLog("MediaListPartialStateChange") .sendSingleEvent() .scan(initialVS) { vs, change -> change.reduce(vs) } .debugLog("ViewState") - .stateIn( - viewModelScope, - SharingStarted.Eagerly, - initialVS - ) + .toState(initialVS) } private fun Flow.sendSingleEvent(): Flow { @@ -64,7 +55,7 @@ class MediaListViewModel @Inject constructor( } } - private fun SharedFlow.toMediaListPartialStateChangeFlow(): Flow { + private fun Flow.toMediaListPartialStateChangeFlow(): Flow { return merge( merge( filterIsInstance().filterNot { it.path.isNullOrBlank() }, diff --git a/app/src/main/java/com/skyd/anivu/ui/screen/read/ReadViewModel.kt b/app/src/main/java/com/skyd/anivu/ui/screen/read/ReadViewModel.kt index 59655be4..ce2067ea 100644 --- a/app/src/main/java/com/skyd/anivu/ui/screen/read/ReadViewModel.kt +++ b/app/src/main/java/com/skyd/anivu/ui/screen/read/ReadViewModel.kt @@ -1,6 +1,5 @@ package com.skyd.anivu.ui.screen.read -import androidx.lifecycle.viewModelScope import com.skyd.anivu.R import com.skyd.anivu.appContext import com.skyd.anivu.base.mvi.AbstractMviViewModel @@ -10,8 +9,6 @@ import com.skyd.anivu.model.repository.ArticleRepository import com.skyd.anivu.model.repository.ReadRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.filterNot @@ -20,7 +17,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.scan -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.take import javax.inject.Inject @@ -36,20 +32,15 @@ class ReadViewModel @Inject constructor( val initialVS = ReadState.initial() viewState = merge( - intentSharedFlow.filterIsInstance().take(1), - intentSharedFlow.filterNot { it is ReadIntent.Init } + intentFlow.filterIsInstance().take(1), + intentFlow.filterNot { it is ReadIntent.Init } ) - .shareWhileSubscribed() .toReadPartialStateChangeFlow() .debugLog("ReadPartialStateChange") .sendSingleEvent() .scan(initialVS) { vs, change -> change.reduce(vs) } .debugLog("ViewState") - .stateIn( - viewModelScope, - SharingStarted.Eagerly, - initialVS - ) + .toState(initialVS) } private fun Flow.sendSingleEvent(): Flow { @@ -82,7 +73,7 @@ class ReadViewModel @Inject constructor( } } - private fun SharedFlow.toReadPartialStateChangeFlow(): Flow { + private fun Flow.toReadPartialStateChangeFlow(): Flow { return merge( filterIsInstance().flatMapConcat { intent -> articleRepo.readArticle(intent.articleId, read = true).flatMapConcat { diff --git a/app/src/main/java/com/skyd/anivu/ui/screen/search/SearchViewModel.kt b/app/src/main/java/com/skyd/anivu/ui/screen/search/SearchViewModel.kt index b99c1687..7127505d 100644 --- a/app/src/main/java/com/skyd/anivu/ui/screen/search/SearchViewModel.kt +++ b/app/src/main/java/com/skyd/anivu/ui/screen/search/SearchViewModel.kt @@ -10,8 +10,6 @@ import com.skyd.anivu.model.repository.ArticleRepository import com.skyd.anivu.model.repository.SearchRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.filterNot @@ -21,7 +19,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.scan -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.take import javax.inject.Inject @@ -37,23 +34,18 @@ class SearchViewModel @Inject constructor( val initialVS = SearchState.initial() viewState = merge( - intentSharedFlow.filterIsInstance().take(1), - intentSharedFlow.filterIsInstance().take(1), - intentSharedFlow.filterNot { + intentFlow.filterIsInstance().take(1), + intentFlow.filterIsInstance().take(1), + intentFlow.filterNot { it is SearchIntent.ListenSearchFeed || it is SearchIntent.ListenSearchArticle } ) - .shareWhileSubscribed() .toSearchPartialStateChangeFlow() .debugLog("SearchPartialStateChange") .sendSingleEvent() .scan(initialVS) { vs, change -> change.reduce(vs) } .debugLog("ViewState") - .stateIn( - viewModelScope, - SharingStarted.Eagerly, - initialVS - ) + .toState(initialVS) } private fun Flow.sendSingleEvent(): Flow { @@ -73,7 +65,7 @@ class SearchViewModel @Inject constructor( } } - private fun SharedFlow.toSearchPartialStateChangeFlow(): Flow { + private fun Flow.toSearchPartialStateChangeFlow(): Flow { return merge( filterIsInstance().flatMapConcat { flowOf(searchRepo.listenSearchFeed().cachedIn(viewModelScope)).map { diff --git a/app/src/main/java/com/skyd/anivu/ui/screen/settings/data/DataViewModel.kt b/app/src/main/java/com/skyd/anivu/ui/screen/settings/data/DataViewModel.kt index f56d20c8..6dc1fd86 100644 --- a/app/src/main/java/com/skyd/anivu/ui/screen/settings/data/DataViewModel.kt +++ b/app/src/main/java/com/skyd/anivu/ui/screen/settings/data/DataViewModel.kt @@ -1,6 +1,5 @@ package com.skyd.anivu.ui.screen.settings.data -import androidx.lifecycle.viewModelScope import com.skyd.anivu.R import com.skyd.anivu.appContext import com.skyd.anivu.base.mvi.AbstractMviViewModel @@ -10,8 +9,6 @@ import com.skyd.anivu.ext.startWith import com.skyd.anivu.model.repository.DataRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.filterNot @@ -20,7 +17,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.scan -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.take import javax.inject.Inject @@ -35,20 +31,15 @@ class DataViewModel @Inject constructor( val initialVS = DataState.initial() viewState = merge( - intentSharedFlow.filterIsInstance().take(1), - intentSharedFlow.filterNot { it is DataIntent.Init } + intentFlow.filterIsInstance().take(1), + intentFlow.filterNot { it is DataIntent.Init } ) - .shareWhileSubscribed() .toDataPartialStateChangeFlow() .debugLog("DataPartialStateChange") .sendSingleEvent() .scan(initialVS) { vs, change -> change.reduce(vs) } .debugLog("ViewState") - .stateIn( - viewModelScope, - SharingStarted.Eagerly, - initialVS - ) + .toState(initialVS) } private fun Flow.sendSingleEvent(): Flow { @@ -95,7 +86,7 @@ class DataViewModel @Inject constructor( } } - private fun SharedFlow.toDataPartialStateChangeFlow(): Flow { + private fun Flow.toDataPartialStateChangeFlow(): Flow { return merge( filterIsInstance().map { DataPartialStateChange.Init }, diff --git a/app/src/main/java/com/skyd/anivu/ui/screen/settings/data/importexport/exportopml/ExportOpmlViewModel.kt b/app/src/main/java/com/skyd/anivu/ui/screen/settings/data/importexport/exportopml/ExportOpmlViewModel.kt index aa649e3f..07b518ce 100644 --- a/app/src/main/java/com/skyd/anivu/ui/screen/settings/data/importexport/exportopml/ExportOpmlViewModel.kt +++ b/app/src/main/java/com/skyd/anivu/ui/screen/settings/data/importexport/exportopml/ExportOpmlViewModel.kt @@ -1,14 +1,11 @@ package com.skyd.anivu.ui.screen.settings.data.importexport.exportopml -import androidx.lifecycle.viewModelScope import com.skyd.anivu.base.mvi.AbstractMviViewModel import com.skyd.anivu.ext.catchMap import com.skyd.anivu.ext.startWith import com.skyd.anivu.model.repository.importexport.ImportExportRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.filterNot @@ -17,7 +14,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.scan -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.take import javax.inject.Inject @@ -32,20 +28,15 @@ class ExportOpmlViewModel @Inject constructor( val initialVS = ExportOpmlState.initial() viewState = merge( - intentSharedFlow.filterIsInstance().take(1), - intentSharedFlow.filterNot { it is ExportOpmlIntent.Init } + intentFlow.filterIsInstance().take(1), + intentFlow.filterNot { it is ExportOpmlIntent.Init } ) - .shareWhileSubscribed() .toFeedPartialStateChangeFlow() .debugLog("ExportOpmlPartialStateChange") .sendSingleEvent() .scan(initialVS) { vs, change -> change.reduce(vs) } .debugLog("ViewState") - .stateIn( - viewModelScope, - SharingStarted.Eagerly, - initialVS - ) + .toState(initialVS) } private fun Flow.sendSingleEvent(): Flow { @@ -65,7 +56,7 @@ class ExportOpmlViewModel @Inject constructor( } } - private fun SharedFlow.toFeedPartialStateChangeFlow(): Flow { + private fun Flow.toFeedPartialStateChangeFlow(): Flow { return merge( filterIsInstance().map { ExportOpmlPartialStateChange.Init }, diff --git a/app/src/main/java/com/skyd/anivu/ui/screen/settings/data/importexport/importopml/ImportOpmlViewModel.kt b/app/src/main/java/com/skyd/anivu/ui/screen/settings/data/importexport/importopml/ImportOpmlViewModel.kt index 88aa265a..3709a8a6 100644 --- a/app/src/main/java/com/skyd/anivu/ui/screen/settings/data/importexport/importopml/ImportOpmlViewModel.kt +++ b/app/src/main/java/com/skyd/anivu/ui/screen/settings/data/importexport/importopml/ImportOpmlViewModel.kt @@ -1,14 +1,11 @@ package com.skyd.anivu.ui.screen.settings.data.importexport.importopml -import androidx.lifecycle.viewModelScope import com.skyd.anivu.base.mvi.AbstractMviViewModel import com.skyd.anivu.ext.catchMap import com.skyd.anivu.ext.startWith import com.skyd.anivu.model.repository.importexport.ImportExportRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.filterNot @@ -17,7 +14,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.scan -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.take import javax.inject.Inject @@ -32,20 +28,15 @@ class ImportOpmlViewModel @Inject constructor( val initialVS = ImportOpmlState.initial() viewState = merge( - intentSharedFlow.filterIsInstance().take(1), - intentSharedFlow.filterNot { it is ImportOpmlIntent.Init } + intentFlow.filterIsInstance().take(1), + intentFlow.filterNot { it is ImportOpmlIntent.Init } ) - .shareWhileSubscribed() .toFeedPartialStateChangeFlow() .debugLog("ImportOpmlPartialStateChange") .sendSingleEvent() .scan(initialVS) { vs, change -> change.reduce(vs) } .debugLog("ViewState") - .stateIn( - viewModelScope, - SharingStarted.Eagerly, - initialVS - ) + .toState(initialVS) } private fun Flow.sendSingleEvent(): Flow { @@ -65,7 +56,7 @@ class ImportOpmlViewModel @Inject constructor( } } - private fun SharedFlow.toFeedPartialStateChangeFlow(): Flow { + private fun Flow.toFeedPartialStateChangeFlow(): Flow { return merge( filterIsInstance().map { ImportOpmlPartialStateChange.Init }, diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cce90644..806dbc96 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -50,7 +50,7 @@ okhttp3-logging = { module = "com.squareup.okhttp3:logging-interceptor", version retrofit2 = { module = "com.squareup.retrofit2:retrofit", version = "2.11.0" } retrofit2-kotlinx-serialization-converter = { module = "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter", version = "1.0.0" } kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version = "1.7.2" } -kotlinx-coroutines-guava = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-guava", version = "1.8.1" } +kotlinx-coroutines-guava = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-guava", version = "1.9.0" } aniyomi-mpv-lib = { module = "com.github.aniyomiorg:aniyomi-mpv-lib", version = "1.15.n" } ffmpeg-kit = { module = "com.github.jmir1:ffmpeg-kit", version = "1.15" } @@ -64,10 +64,11 @@ lottie-compose = { module = "com.airbnb.android:lottie-compose", version = "6.5. rome = { module = "com.rometools:rome", version.ref = "rome" } rome-modules = { module = "com.rometools:rome-modules", version.ref = "rome" } +ceau-opmlparser = { module = "be.ceau:opml-parser", version = "3.1.0" } readability4j = { module = "net.dankito.readability4j:readability4j", version = "1.0.8" } -reorderable = { module = "sh.calvin.reorderable:reorderable", version = "2.3.2" } +reorderable = { module = "sh.calvin.reorderable:reorderable", version = "2.3.3" } libtorrent4j-arm64 = { module = "org.libtorrent4j:libtorrent4j-android-arm64", version.ref = "libtorrent4j" } libtorrent4j-arm = { module = "org.libtorrent4j:libtorrent4j-android-arm", version.ref = "libtorrent4j" }