[optimize] Refactoring API client injection architecture
This commit is contained in:
@@ -8,17 +8,17 @@ class Comic(
|
||||
val token: String
|
||||
)
|
||||
{
|
||||
fun getPage(pageNumber: Int): String
|
||||
fun getPage(pageNumber: Int, api: ApiClient): String
|
||||
{
|
||||
return "${ApiClient.getBase()}api/image/$id/${comic.list[pageNumber]}?token=$token"
|
||||
return "${api.getBase()}api/image/$id/${comic.list[pageNumber]}?token=$token"
|
||||
}
|
||||
|
||||
fun getPage(pageName: String): String?
|
||||
fun getPage(pageName: String, api: ApiClient): String?
|
||||
{
|
||||
val v = comic.list.indexOf(pageName)
|
||||
if(v >= 0)
|
||||
{
|
||||
return getPage(v)
|
||||
return getPage(v, api)
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -33,7 +33,7 @@ class Comic(
|
||||
var v = comic.list.indexOf(pageName)
|
||||
if(v >= 0)
|
||||
{
|
||||
var r: Int = 1
|
||||
var r = 1
|
||||
v+=1
|
||||
while(v < comic.list.size && !comic.bookmarks.any{
|
||||
x -> x.page == comic.list[v]
|
||||
|
||||
@@ -14,28 +14,28 @@ class Video(
|
||||
val token: String,
|
||||
val video: VideoResponse
|
||||
) {
|
||||
fun getCover(): String {
|
||||
fun getCover(api: ApiClient): String {
|
||||
return if (isLocal)
|
||||
"$localBase/videos/$klass/$id/cover.jpg"
|
||||
else
|
||||
"${ApiClient.getBase()}api/video/$klass/$id/cover?token=$token"
|
||||
"${api.getBase()}api/video/$klass/$id/cover?token=$token"
|
||||
}
|
||||
|
||||
fun getVideo(): String {
|
||||
fun getVideo(api: ApiClient): String {
|
||||
return if (isLocal)
|
||||
"$localBase/videos/$klass/$id/video.mp4"
|
||||
else
|
||||
"${ApiClient.getBase()}api/video/$klass/$id/av?token=$token"
|
||||
"${api.getBase()}api/video/$klass/$id/av?token=$token"
|
||||
}
|
||||
|
||||
fun getSubtitle(): String {
|
||||
fun getSubtitle(api: ApiClient): String {
|
||||
return if (isLocal)
|
||||
"$localBase/videos/$klass/$id/subtitle.vtt"
|
||||
else
|
||||
"${ApiClient.getBase()}api/video/$klass/$id/subtitle?token=$token"
|
||||
"${api.getBase()}api/video/$klass/$id/subtitle?token=$token"
|
||||
}
|
||||
|
||||
fun getGallery(): List<KeyImage> {
|
||||
fun getGallery(api: ApiClient): List<KeyImage> {
|
||||
return if (isLocal)
|
||||
video.gallery.map {
|
||||
KeyImage(
|
||||
@@ -46,7 +46,7 @@ class Video(
|
||||
} else video.gallery.map {
|
||||
KeyImage(
|
||||
name = it,
|
||||
url = "${ApiClient.getBase()}api/video/$klass/$id/gallery/$it?token=$token",
|
||||
url = "${api.getBase()}api/video/$klass/$id/gallery/$it?token=$token",
|
||||
key = "$klass/$id/gallery/$it"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package com.acitelight.aether.service
|
||||
|
||||
import com.acitelight.aether.service.AuthManager.db64
|
||||
import com.acitelight.aether.service.AuthManager.signChallenge
|
||||
import com.acitelight.aether.service.AuthManager.signChallengeByte
|
||||
import kotlinx.coroutines.*
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
@@ -44,7 +41,7 @@ class AbyssStream private constructor(
|
||||
* Create and perform handshake on an already-connected socket.
|
||||
* If privateKeyRaw is provided, it must be 32 bytes.
|
||||
*/
|
||||
suspend fun create(socket: Socket, privateKeyRaw: ByteArray? = null): AbyssStream = withContext(Dispatchers.IO) {
|
||||
suspend fun create(authManager: AuthManager, socket: Socket, privateKeyRaw: ByteArray? = null): AbyssStream = withContext(Dispatchers.IO) {
|
||||
if (!socket.isConnected) throw IllegalArgumentException("socket is not connected")
|
||||
val inStream = socket.getInputStream()
|
||||
val outStream = socket.getOutputStream()
|
||||
@@ -69,7 +66,7 @@ class AbyssStream private constructor(
|
||||
|
||||
val ch = ByteArray(32)
|
||||
readExact(inStream, ch, 0, 32)
|
||||
val signed = signChallengeByte(localPriv, ch)
|
||||
val signed = authManager.signChallengeByte(localPriv, ch)
|
||||
writeExact(outStream, signed, 0, signed.size)
|
||||
readExact(inStream, ch, 0, 16)
|
||||
|
||||
@@ -222,7 +219,7 @@ class AbyssStream private constructor(
|
||||
val header = ByteArray(4)
|
||||
try {
|
||||
readExact(input, header, 0, 4)
|
||||
} catch (e: EOFException) {
|
||||
} catch (_: EOFException) {
|
||||
return null
|
||||
}
|
||||
val payloadLen = ByteBuffer.wrap(header).int and 0xffffffff.toInt()
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package com.acitelight.aether.service
|
||||
|
||||
|
||||
import android.util.Log
|
||||
import com.acitelight.aether.service.AuthManager.db64
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.selects.select
|
||||
@@ -17,7 +14,8 @@ import kotlin.coroutines.CoroutineContext
|
||||
|
||||
@Singleton
|
||||
class AbyssTunnelProxy @Inject constructor(
|
||||
private val settingsDataStoreManager: SettingsDataStoreManager
|
||||
private val settingsDataStoreManager: SettingsDataStoreManager,
|
||||
private val authManager: AuthManager
|
||||
) {
|
||||
private val coroutineContext: CoroutineContext = Dispatchers.IO
|
||||
private var serverHost: String = ""
|
||||
@@ -48,7 +46,7 @@ class AbyssTunnelProxy @Inject constructor(
|
||||
|
||||
launch {
|
||||
try { handleLocalConnection(client) }
|
||||
catch (ex: Exception) { /* ignore */ }
|
||||
catch (_: Exception) { /* ignore */ }
|
||||
}
|
||||
}
|
||||
} catch (ex: Exception) {
|
||||
@@ -72,14 +70,14 @@ class AbyssTunnelProxy @Inject constructor(
|
||||
var abyssStream: AbyssStream? = null
|
||||
try {
|
||||
abyssSocket = Socket(serverHost, serverPort)
|
||||
abyssStream = AbyssStream.create(abyssSocket, db64(settingsDataStoreManager.privateKeyFlow.first()))
|
||||
abyssStream = AbyssStream.create(authManager, abyssSocket, authManager.db64(settingsDataStoreManager.privateKeyFlow.first()))
|
||||
|
||||
// concurrently copy in both directions
|
||||
val job1 = launch { copyExactSuspend(localIn, abyssStream) } // local -> abyss
|
||||
val job2 = launch { copyFromAbyssToLocal(abyssStream, localOut) } // abyss -> local
|
||||
|
||||
// wait for either direction to finish
|
||||
select<Unit> {
|
||||
select {
|
||||
job1.onJoin { /* completed */ }
|
||||
job2.onJoin { /* completed */ }
|
||||
}
|
||||
|
||||
@@ -10,7 +10,10 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.ConnectionSpec
|
||||
import okhttp3.Cookie
|
||||
import okhttp3.CookieJar
|
||||
import okhttp3.EventListener
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.OkHttpClient
|
||||
@@ -24,23 +27,27 @@ import java.security.KeyStore
|
||||
import java.security.cert.CertificateException
|
||||
import java.security.cert.CertificateFactory
|
||||
import java.security.cert.X509Certificate
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import javax.net.ssl.SSLContext
|
||||
import javax.net.ssl.TrustManagerFactory
|
||||
import javax.net.ssl.X509TrustManager
|
||||
|
||||
@Singleton
|
||||
class ApiClient @Inject constructor(
|
||||
|
||||
object ApiClient {
|
||||
) {
|
||||
fun getBase(): String{
|
||||
return replaceAbyssProtocol(base)
|
||||
}
|
||||
private var base: String = ""
|
||||
var domain: String = ""
|
||||
var cert: String = ""
|
||||
private var domain: String = ""
|
||||
private var cert: String = ""
|
||||
private val json = Json {
|
||||
ignoreUnknownKeys = true
|
||||
}
|
||||
|
||||
fun replaceAbyssProtocol(uri: String): String {
|
||||
private fun replaceAbyssProtocol(uri: String): String {
|
||||
return uri.replaceFirst("^abyss://".toRegex(), "https://")
|
||||
}
|
||||
|
||||
@@ -52,7 +59,7 @@ object ApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
fun loadCertificateFromString(pemString: String): X509Certificate {
|
||||
private fun loadCertificateFromString(pemString: String): X509Certificate {
|
||||
val certificateFactory = CertificateFactory.getInstance("X.509")
|
||||
val decodedPem = pemString
|
||||
.replace("-----BEGIN CERTIFICATE-----", "")
|
||||
@@ -66,7 +73,7 @@ object ApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
fun createOkHttpClientWithDynamicCert(trustedCert: X509Certificate?): OkHttpClient {
|
||||
private fun createOkHttpClientWithDynamicCert(trustedCert: X509Certificate?): OkHttpClient {
|
||||
try {
|
||||
val defaultTmFactory = TrustManagerFactory.getInstance(
|
||||
TrustManagerFactory.getDefaultAlgorithm()
|
||||
@@ -86,7 +93,7 @@ object ApiClient {
|
||||
).apply {
|
||||
init(keyStore)
|
||||
}
|
||||
tmf.trustManagers.first { it is X509TrustManager } as X509TrustManager
|
||||
tmf.trustManagers.first { i -> i is X509TrustManager } as X509TrustManager
|
||||
}
|
||||
|
||||
val combinedTm = object : X509TrustManager {
|
||||
@@ -157,11 +164,22 @@ object ApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
fun createOkHttp(): OkHttpClient {
|
||||
private fun createOkHttp(): OkHttpClient {
|
||||
return if (cert == "")
|
||||
if (base.startsWith("abyss://"))
|
||||
OkHttpClient
|
||||
.Builder()
|
||||
.cookieJar(object : CookieJar {
|
||||
private val cookieStore = mutableMapOf<HttpUrl, List<Cookie>>()
|
||||
|
||||
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
|
||||
cookieStore[url] = cookies
|
||||
}
|
||||
|
||||
override fun loadForRequest(url: HttpUrl): List<Cookie> {
|
||||
return cookieStore[url] ?: emptyList()
|
||||
}
|
||||
})
|
||||
.proxy(
|
||||
Proxy(
|
||||
Proxy.Type.HTTP,
|
||||
@@ -174,6 +192,17 @@ object ApiClient {
|
||||
else
|
||||
OkHttpClient
|
||||
.Builder()
|
||||
.cookieJar(object : CookieJar {
|
||||
private val cookieStore = mutableMapOf<HttpUrl, List<Cookie>>()
|
||||
|
||||
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
|
||||
cookieStore[url] = cookies
|
||||
}
|
||||
|
||||
override fun loadForRequest(url: HttpUrl): List<Cookie> {
|
||||
return cookieStore[url] ?: emptyList()
|
||||
}
|
||||
})
|
||||
.connectionSpecs(listOf(ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS))
|
||||
.eventListener(dnsEventListener)
|
||||
.build()
|
||||
@@ -183,20 +212,22 @@ object ApiClient {
|
||||
}
|
||||
|
||||
private fun createRetrofit(): Retrofit {
|
||||
val okHttpClient = createOkHttp()
|
||||
client = createOkHttp()
|
||||
val b = replaceAbyssProtocol(base)
|
||||
|
||||
return Retrofit.Builder()
|
||||
.baseUrl(b)
|
||||
.client(okHttpClient)
|
||||
.client(client!!)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
|
||||
.build()
|
||||
}
|
||||
|
||||
|
||||
private var client: OkHttpClient? = null
|
||||
var api: ApiInterface? = null
|
||||
|
||||
fun getClient() = client!!
|
||||
|
||||
suspend fun apply(context: Context, urls: String, crt: String): String? {
|
||||
try {
|
||||
val urlList = urls.split(";").map { it.trim() }
|
||||
@@ -219,7 +250,7 @@ object ApiClient {
|
||||
base = selectedUrl
|
||||
withContext(Dispatchers.IO)
|
||||
{
|
||||
(context as AetherApp).abyssService?.proxy?.config(ApiClient.getBase().toUri().host!!, 4096)
|
||||
(context as AetherApp).abyssService?.proxy?.config(getBase().toUri().host!!, 4096)
|
||||
}
|
||||
api = createRetrofit().create(ApiInterface::class.java)
|
||||
|
||||
@@ -228,7 +259,7 @@ object ApiClient {
|
||||
Log.i("Delay Analyze", "Abyss Hello: ${h.string()}")
|
||||
|
||||
return base
|
||||
} catch (e: Exception) {
|
||||
} catch (_: Exception) {
|
||||
api = null
|
||||
base = ""
|
||||
domain = ""
|
||||
@@ -241,7 +272,7 @@ object ApiClient {
|
||||
return@withContext try {
|
||||
val address = InetAddress.getByName(host)
|
||||
address.isReachable(200)
|
||||
} catch (e: Exception) {
|
||||
} catch (_: Exception) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,10 +18,15 @@ import java.lang.reflect.Proxy
|
||||
import java.net.InetSocketAddress
|
||||
import java.security.PrivateKey
|
||||
import java.security.Signature
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
object AuthManager {
|
||||
@Singleton
|
||||
class AuthManager @Inject constructor(
|
||||
private val apiClient: ApiClient
|
||||
) {
|
||||
suspend fun fetchToken(username: String, privateKey: String): String? {
|
||||
val api = ApiClient.api
|
||||
val api = apiClient.api
|
||||
var challengeBase64 = ""
|
||||
|
||||
try{
|
||||
|
||||
@@ -1,48 +1,37 @@
|
||||
package com.acitelight.aether.service
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import com.acitelight.aether.Screen
|
||||
import com.acitelight.aether.model.Video
|
||||
import com.acitelight.aether.service.ApiClient.createOkHttp
|
||||
import com.tonyodev.fetch2.Download
|
||||
import com.tonyodev.fetch2.Fetch
|
||||
import com.tonyodev.fetch2.FetchConfiguration
|
||||
import com.tonyodev.fetch2.FetchListener
|
||||
import com.tonyodev.fetch2.Request
|
||||
import com.tonyodev.fetch2.Status
|
||||
import com.tonyodev.fetch2core.Extras
|
||||
import com.tonyodev.fetch2okhttp.OkHttpDownloader
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class FetchManager @Inject constructor(
|
||||
@ApplicationContext private val context: Context
|
||||
@ApplicationContext private val context: Context,
|
||||
private val apiClient: ApiClient
|
||||
) {
|
||||
private var fetch: Fetch? = null
|
||||
private var listener: FetchListener? = null
|
||||
private var client: OkHttpClient? = null
|
||||
val configured = MutableStateFlow(false)
|
||||
|
||||
fun init() {
|
||||
client = createOkHttp()
|
||||
val fetchConfiguration = FetchConfiguration.Builder(context)
|
||||
.setDownloadConcurrentLimit(8)
|
||||
.setHttpDownloader(OkHttpDownloader(client))
|
||||
.setHttpDownloader(OkHttpDownloader(apiClient.getClient()))
|
||||
.build()
|
||||
|
||||
fetch = Fetch.Impl.getInstance(fetchConfiguration)
|
||||
@@ -65,12 +54,6 @@ class FetchManager @Inject constructor(
|
||||
listener = null
|
||||
}
|
||||
|
||||
// query downloads
|
||||
suspend fun getAllDownloads(callback: (List<Download>) -> Unit) {
|
||||
configured.filter { it }.first()
|
||||
fetch?.getDownloads { list -> callback(list) } ?: callback(emptyList())
|
||||
}
|
||||
|
||||
suspend fun getAllDownloadsAsync(): List<Download> {
|
||||
configured.filter { it }.first()
|
||||
val completed = MutableStateFlow(false)
|
||||
@@ -140,7 +123,7 @@ class FetchManager @Inject constructor(
|
||||
)
|
||||
|
||||
val requests = mutableListOf(
|
||||
Request(video.getVideo(), videoPath.path).apply {
|
||||
Request(video.getVideo(apiClient), videoPath.path).apply {
|
||||
extras = Extras(
|
||||
mapOf(
|
||||
"name" to video.video.name,
|
||||
@@ -150,7 +133,7 @@ class FetchManager @Inject constructor(
|
||||
)
|
||||
)
|
||||
},
|
||||
Request(video.getCover(), coverPath.path).apply {
|
||||
Request(video.getCover(apiClient), coverPath.path).apply {
|
||||
extras = Extras(
|
||||
mapOf(
|
||||
"name" to video.video.name,
|
||||
@@ -160,7 +143,7 @@ class FetchManager @Inject constructor(
|
||||
)
|
||||
)
|
||||
},
|
||||
Request(video.getSubtitle(), subtitlePath.path).apply {
|
||||
Request(video.getSubtitle(apiClient), subtitlePath.path).apply {
|
||||
extras = Extras(
|
||||
mapOf(
|
||||
"name" to video.video.name,
|
||||
@@ -171,7 +154,7 @@ class FetchManager @Inject constructor(
|
||||
)
|
||||
},
|
||||
)
|
||||
for (p in video.getGallery()) {
|
||||
for (p in video.getGallery(apiClient)) {
|
||||
requests.add(
|
||||
Request(p.url, File(
|
||||
context.getExternalFilesDir(null),
|
||||
|
||||
@@ -16,7 +16,8 @@ import javax.inject.Singleton
|
||||
@Singleton
|
||||
class MediaManager @Inject constructor(
|
||||
val fetchManager: FetchManager,
|
||||
@ApplicationContext val context: Context
|
||||
@ApplicationContext val context: Context,
|
||||
private val apiClient: ApiClient
|
||||
)
|
||||
{
|
||||
var token: String = "null"
|
||||
@@ -25,7 +26,7 @@ class MediaManager @Inject constructor(
|
||||
{
|
||||
try
|
||||
{
|
||||
val j = ApiClient.api!!.getVideoClasses(token)
|
||||
val j = apiClient.api!!.getVideoClasses(token)
|
||||
return j.toList()
|
||||
}catch(_: Exception)
|
||||
{
|
||||
@@ -37,7 +38,7 @@ class MediaManager @Inject constructor(
|
||||
{
|
||||
try
|
||||
{
|
||||
val j = ApiClient.api!!.queryVideoClasses(klass, token)
|
||||
val j = apiClient.api!!.queryVideoClasses(klass, token)
|
||||
return j.toList()
|
||||
}catch(_: Exception)
|
||||
{
|
||||
@@ -57,7 +58,7 @@ class MediaManager @Inject constructor(
|
||||
}
|
||||
|
||||
try {
|
||||
val j = ApiClient.api!!.queryVideo(klass, id, token)
|
||||
val j = apiClient.api!!.queryVideo(klass, id, token)
|
||||
return Video(klass = klass, id = id, token=token, isLocal = false, localBase = "", video = j)
|
||||
}catch (_: Exception)
|
||||
{
|
||||
@@ -83,7 +84,7 @@ class MediaManager @Inject constructor(
|
||||
}
|
||||
|
||||
try {
|
||||
val j = ApiClient.api!!.queryVideo(klass, id, token)
|
||||
val j = apiClient.api!!.queryVideo(klass, id, token)
|
||||
return Video(klass = klass, id = id, token=token, isLocal = false, localBase = "", video = j)
|
||||
}catch (_: Exception)
|
||||
{
|
||||
@@ -133,7 +134,7 @@ class MediaManager @Inject constructor(
|
||||
}
|
||||
|
||||
val remoteVideos = if (remoteIds.isNotEmpty()) {
|
||||
val j = ApiClient.api!!.queryVideoBulk(klass, remoteIds, token)
|
||||
val j = apiClient.api!!.queryVideoBulk(klass, remoteIds, token)
|
||||
j.zip(remoteIds).map {
|
||||
Video(
|
||||
klass = klass,
|
||||
@@ -157,7 +158,7 @@ class MediaManager @Inject constructor(
|
||||
suspend fun listComics() : List<String>
|
||||
{
|
||||
try{
|
||||
val j = ApiClient.api!!.getComics(token)
|
||||
val j = apiClient.api!!.getComics(token)
|
||||
return j
|
||||
}catch (_: Exception)
|
||||
{
|
||||
@@ -168,7 +169,7 @@ class MediaManager @Inject constructor(
|
||||
suspend fun queryComicInfoSingle(id: String) : Comic?
|
||||
{
|
||||
try{
|
||||
val j = ApiClient.api!!.queryComicInfo(id, token)
|
||||
val j = apiClient.api!!.queryComicInfo(id, token)
|
||||
return Comic(id = id, comic = j, token = token)
|
||||
}catch (_: Exception)
|
||||
{
|
||||
@@ -179,7 +180,7 @@ class MediaManager @Inject constructor(
|
||||
suspend fun queryComicInfoBulk(id: List<String>) : List<Comic>?
|
||||
{
|
||||
try{
|
||||
val j = ApiClient.api!!.queryComicInfoBulk(id, token)
|
||||
val j = apiClient.api!!.queryComicInfoBulk(id, token)
|
||||
return j.zip(id).map { Comic(id = it.second, comic = it.first, token = token) }
|
||||
}catch (_: Exception)
|
||||
{
|
||||
@@ -190,7 +191,7 @@ class MediaManager @Inject constructor(
|
||||
suspend fun postBookmark(id: String, bookMark: BookMark): Boolean
|
||||
{
|
||||
try{
|
||||
ApiClient.api!!.postBookmark(id, token, bookMark)
|
||||
apiClient.api!!.postBookmark(id, token, bookMark)
|
||||
return true
|
||||
}catch (_: Exception)
|
||||
{
|
||||
|
||||
@@ -32,7 +32,6 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavHostController
|
||||
import coil3.compose.AsyncImage
|
||||
import coil3.request.ImageRequest
|
||||
@@ -157,7 +156,6 @@ fun ComicGridView(
|
||||
comicGridViewModel.updateProcess(comicId.hexToString())
|
||||
{
|
||||
if (record != null) {
|
||||
val k = comic!!.getPageChapterIndex(record!!.position)
|
||||
val route = "comic_page_route/${comic!!.id.toHex()}/${
|
||||
record!!.position
|
||||
}"
|
||||
@@ -248,7 +246,7 @@ fun ChapterCard(
|
||||
{
|
||||
AsyncImage(
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.data(comic.getPage(c.page))
|
||||
.data(comic.getPage(c.page, comicGridViewModel.apiClient))
|
||||
.memoryCacheKey("${comic.id}/${c.page}")
|
||||
.diskCacheKey("${comic.id}/${c.page}")
|
||||
.build(),
|
||||
@@ -300,13 +298,13 @@ fun ChapterCard(
|
||||
.padding(horizontal = 6.dp),
|
||||
onClick = {
|
||||
val route =
|
||||
"comic_page_route/${"${comic.id}".toHex()}/${comic.getPageIndex(r)}"
|
||||
"comic_page_route/${comic.id.toHex()}/${comic.getPageIndex(r)}"
|
||||
navController.navigate(route)
|
||||
}
|
||||
) {
|
||||
AsyncImage(
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.data(comic.getPage(r))
|
||||
.data(comic.getPage(r, comicGridViewModel.apiClient))
|
||||
.memoryCacheKey("${comic.id}/${r}")
|
||||
.diskCacheKey("${comic.id}/${r}")
|
||||
.build(),
|
||||
|
||||
@@ -89,7 +89,7 @@ fun ComicPageView(
|
||||
) { page ->
|
||||
AsyncImage(
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.data(it.getPage(page))
|
||||
.data(it.getPage(page, comicPageViewModel.apiClient))
|
||||
.memoryCacheKey("${it.id}/${page}")
|
||||
.diskCacheKey("${it.id}/${page}")
|
||||
.build(),
|
||||
@@ -252,7 +252,7 @@ fun ComicPageView(
|
||||
{
|
||||
AsyncImage(
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.data(it.getPage(r))
|
||||
.data(it.getPage(r, comicPageViewModel.apiClient))
|
||||
.memoryCacheKey("${it.id}/${r}")
|
||||
.diskCacheKey("${it.id}/${r}")
|
||||
.build(),
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package com.acitelight.aether.view
|
||||
|
||||
import android.nfc.Tag
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
@@ -16,10 +14,6 @@ import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
|
||||
import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid
|
||||
import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
|
||||
import androidx.compose.foundation.lazy.staggeredgrid.items
|
||||
@@ -28,42 +22,28 @@ import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Tab
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import coil3.compose.AsyncImage
|
||||
import com.acitelight.aether.model.Video
|
||||
import com.acitelight.aether.viewModel.VideoScreenViewModel
|
||||
import androidx.compose.material3.ScrollableTabRow
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.layout.Layout
|
||||
import androidx.compose.ui.layout.Placeable
|
||||
import androidx.compose.ui.modifier.modifierLocalOf
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import androidx.navigation.NavHostController
|
||||
import coil3.compose.AsyncImage
|
||||
import coil3.request.ImageRequest
|
||||
import com.acitelight.aether.Global
|
||||
import com.acitelight.aether.model.Comic
|
||||
import com.acitelight.aether.viewModel.ComicScreenViewModel
|
||||
import java.nio.charset.Charset
|
||||
|
||||
@Composable
|
||||
fun VariableGrid(
|
||||
@@ -223,7 +203,7 @@ fun ComicCard(
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight(),
|
||||
onClick = {
|
||||
val route = "comic_grid_route/${"${comic.id}".toHex()}"
|
||||
val route = "comic_grid_route/${comic.id.toHex()}"
|
||||
navController.navigate(route)
|
||||
}
|
||||
) {
|
||||
@@ -234,7 +214,7 @@ fun ComicCard(
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
AsyncImage(
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.data(comic.getPage(0))
|
||||
.data(comic.getPage(0, comicScreenViewModel.apiClient))
|
||||
.memoryCacheKey("${comic.id}/${0}")
|
||||
.diskCacheKey("${comic.id}/${0}")
|
||||
.build(),
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.acitelight.aether.view
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -37,35 +36,34 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavHostController
|
||||
import coil3.compose.AsyncImage
|
||||
import coil3.request.ImageRequest
|
||||
import com.acitelight.aether.Global.updateRelate
|
||||
import com.acitelight.aether.model.Comic
|
||||
import com.acitelight.aether.viewModel.ComicScreenViewModel
|
||||
import com.acitelight.aether.viewModel.HomeScreenViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun HomeScreen(
|
||||
homeScreenViewModel: HomeScreenViewModel = androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel<HomeScreenViewModel>(),
|
||||
navController: NavHostController)
|
||||
{
|
||||
navController: NavHostController
|
||||
) {
|
||||
val pagerState = rememberPagerState(initialPage = 0, pageCount = { 2 })
|
||||
|
||||
HorizontalPager(
|
||||
state = pagerState,
|
||||
modifier = Modifier.fillMaxSize().background(Color.Black)
|
||||
){
|
||||
p ->
|
||||
if(p == 0)
|
||||
{
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(Color.Black)
|
||||
) { p ->
|
||||
if (p == 0) {
|
||||
Column(Modifier.fillMaxHeight()) {
|
||||
Text(
|
||||
text = "Videos",
|
||||
style = MaterialTheme.typography.headlineMedium,
|
||||
modifier = Modifier.padding(8.dp).align(Alignment.Start)
|
||||
modifier = Modifier
|
||||
.padding(8.dp)
|
||||
.align(Alignment.Start)
|
||||
)
|
||||
|
||||
HorizontalDivider(Modifier.padding(8.dp), 2.dp, DividerDefaults.color)
|
||||
@@ -73,27 +71,38 @@ fun HomeScreen(
|
||||
LazyColumn(modifier = Modifier.fillMaxWidth())
|
||||
{
|
||||
items(homeScreenViewModel.recentManager.recentVideo)
|
||||
{
|
||||
i ->
|
||||
{ i ->
|
||||
MiniVideoCard(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 12.dp),
|
||||
i,
|
||||
{
|
||||
updateRelate(homeScreenViewModel.recentManager.recentVideo, i)
|
||||
apiClient = homeScreenViewModel.apiClient,
|
||||
imageLoader = homeScreenViewModel.imageLoader!!
|
||||
)
|
||||
{
|
||||
updateRelate(homeScreenViewModel.recentManager.recentVideo, i)
|
||||
|
||||
val playList = mutableListOf<String>()
|
||||
val fv = homeScreenViewModel.videoLibrary.classesMap.map { it.value }.flatten()
|
||||
val playList = mutableListOf<String>()
|
||||
val fv = homeScreenViewModel.videoLibrary.classesMap.map { it.value }
|
||||
.flatten()
|
||||
|
||||
val group = fv.filter { it.klass == i.klass && it.video.group == i.video.group }
|
||||
for (i in group) {
|
||||
playList.add("${i.klass}/${i.id}")
|
||||
}
|
||||
val group =
|
||||
fv.filter { it.klass == i.klass && it.video.group == i.video.group }
|
||||
for (i in group) {
|
||||
playList.add("${i.klass}/${i.id}")
|
||||
}
|
||||
|
||||
val route = "video_player_route/${(playList.joinToString(",") + "|${i.id}").toHex()}"
|
||||
navController.navigate(route)
|
||||
}, homeScreenViewModel.imageLoader!!)
|
||||
HorizontalDivider(Modifier.padding(vertical = 8.dp).alpha(0.4f), 1.dp, DividerDefaults.color)
|
||||
val route =
|
||||
"video_player_route/${(playList.joinToString(",") + "|${i.id}").toHex()}"
|
||||
navController.navigate(route)
|
||||
}
|
||||
HorizontalDivider(
|
||||
Modifier
|
||||
.padding(vertical = 8.dp)
|
||||
.alpha(0.4f),
|
||||
1.dp,
|
||||
DividerDefaults.color
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,7 +111,9 @@ fun HomeScreen(
|
||||
Text(
|
||||
text = "Comics",
|
||||
style = MaterialTheme.typography.headlineMedium,
|
||||
modifier = Modifier.padding(8.dp).align(Alignment.Start)
|
||||
modifier = Modifier
|
||||
.padding(8.dp)
|
||||
.align(Alignment.Start)
|
||||
)
|
||||
|
||||
HorizontalDivider(Modifier.padding(8.dp), 2.dp, DividerDefaults.color)
|
||||
@@ -115,8 +126,7 @@ fun HomeScreen(
|
||||
)
|
||||
{
|
||||
items(homeScreenViewModel.recentManager.recentComic)
|
||||
{
|
||||
comic ->
|
||||
{ comic ->
|
||||
ComicCardRecent(comic, navController, homeScreenViewModel)
|
||||
}
|
||||
}
|
||||
@@ -138,7 +148,7 @@ fun ComicCardRecent(
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight(),
|
||||
onClick = {
|
||||
val route = "comic_grid_route/${"${comic.id}".toHex()}"
|
||||
val route = "comic_grid_route/${comic.id.toHex()}"
|
||||
navController.navigate(route)
|
||||
}
|
||||
) {
|
||||
@@ -149,7 +159,7 @@ fun ComicCardRecent(
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
AsyncImage(
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.data(comic.getPage(0))
|
||||
.data(comic.getPage(0, homeScreenViewModel.apiClient))
|
||||
.memoryCacheKey("${comic.id}/${0}")
|
||||
.diskCacheKey("${comic.id}/${0}")
|
||||
.build(),
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.acitelight.aether.view
|
||||
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@@ -17,7 +15,6 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Key
|
||||
import androidx.compose.material.icons.filled.Link
|
||||
import androidx.compose.material.icons.filled.Person
|
||||
import androidx.compose.material.icons.filled.Security
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.Checkbox
|
||||
@@ -31,25 +28,16 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.acitelight.aether.service.ApiClient.api
|
||||
import com.acitelight.aether.viewModel.MeScreenViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@Composable
|
||||
fun MeScreen(meScreenViewModel: MeScreenViewModel = androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel<MeScreenViewModel>()) {
|
||||
val context = LocalContext.current
|
||||
var username by meScreenViewModel.username;
|
||||
var privateKey by meScreenViewModel.privateKey;
|
||||
var username by meScreenViewModel.username
|
||||
var privateKey by meScreenViewModel.privateKey
|
||||
var url by meScreenViewModel.url
|
||||
var cert by meScreenViewModel.cert
|
||||
|
||||
@@ -204,19 +192,6 @@ fun MeScreen(meScreenViewModel: MeScreenViewModel = androidx.hilt.lifecycle.view
|
||||
) {
|
||||
Text("Save")
|
||||
}
|
||||
|
||||
Button(
|
||||
onClick = {
|
||||
meScreenViewModel.viewModelScope.launch {
|
||||
Log.i("Delay Analyze", "Start Abyss Hello")
|
||||
val h = api!!.hello()
|
||||
Log.i("Delay Analyze", "Abyss Hello: ${h.string()}")
|
||||
}
|
||||
},
|
||||
modifier = Modifier.weight(0.5f).padding(8.dp)
|
||||
) {
|
||||
Text("Ping")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,12 +35,12 @@ import coil3.ImageLoader
|
||||
import coil3.compose.AsyncImage
|
||||
import coil3.request.ImageRequest
|
||||
import com.acitelight.aether.model.Video
|
||||
import com.acitelight.aether.service.ApiClient
|
||||
|
||||
|
||||
@Composable
|
||||
fun MiniPlaylistCard(modifier: Modifier, video: Video, imageLoader: ImageLoader, selected: Boolean, onClick: () -> Unit) {
|
||||
fun MiniPlaylistCard(modifier: Modifier, video: Video, imageLoader: ImageLoader, selected: Boolean, apiClient: ApiClient, onClick: () -> Unit) {
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
|
||||
Card(
|
||||
modifier = modifier
|
||||
.height(80.dp)
|
||||
@@ -58,7 +58,7 @@ fun MiniPlaylistCard(modifier: Modifier, video: Video, imageLoader: ImageLoader,
|
||||
{
|
||||
AsyncImage(
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.data(video.getCover())
|
||||
.data(video.getCover(apiClient))
|
||||
.memoryCacheKey("${video.klass}/${video.id}/cover")
|
||||
.diskCacheKey("${video.klass}/${video.id}/cover")
|
||||
.listener(
|
||||
|
||||
@@ -28,10 +28,11 @@ import coil3.ImageLoader
|
||||
import coil3.compose.AsyncImage
|
||||
import coil3.request.ImageRequest
|
||||
import com.acitelight.aether.model.Video
|
||||
import com.acitelight.aether.service.ApiClient
|
||||
|
||||
|
||||
@Composable
|
||||
fun MiniVideoCard(modifier: Modifier, video: Video, onClick: () -> Unit, imageLoader: ImageLoader) {
|
||||
fun MiniVideoCard(modifier: Modifier, video: Video, imageLoader: ImageLoader, apiClient: ApiClient, onClick: () -> Unit) {
|
||||
Card(
|
||||
modifier = modifier
|
||||
.height(80.dp)
|
||||
@@ -49,7 +50,7 @@ fun MiniVideoCard(modifier: Modifier, video: Video, onClick: () -> Unit, imageLo
|
||||
{
|
||||
AsyncImage(
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.data(video.getCover())
|
||||
.data(video.getCover(apiClient))
|
||||
.memoryCacheKey("${video.klass}/${video.id}/cover")
|
||||
.diskCacheKey("${video.klass}/${video.id}/cover")
|
||||
.listener(
|
||||
|
||||
@@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
@@ -40,7 +39,6 @@ import androidx.compose.ui.unit.sp
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.room.util.TableInfo
|
||||
import coil3.compose.AsyncImage
|
||||
import coil3.request.ImageRequest
|
||||
import com.acitelight.aether.Global.updateRelate
|
||||
@@ -120,7 +118,7 @@ fun TransmissionScreen(
|
||||
for (i in downloadToGroup(
|
||||
item,
|
||||
downloads
|
||||
)) transmissionScreenViewModel.delete(i.id, true)
|
||||
)) transmissionScreenViewModel.delete(i.id)
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -247,7 +245,7 @@ private fun VideoDownloadCard(
|
||||
else {
|
||||
AsyncImage(
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.data(video.getCover())
|
||||
.data(video.getCover(viewModel.apiClient))
|
||||
.memoryCacheKey("${model.klass}/${model.vid}/cover")
|
||||
.diskCacheKey("${model.klass}/${model.vid}/cover")
|
||||
.build(),
|
||||
|
||||
@@ -557,7 +557,7 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel) {
|
||||
LazyColumn(contentPadding = PaddingValues(vertical = 4.dp)) {
|
||||
items(videoPlayerViewModel.videos) { item ->
|
||||
MiniPlaylistCard(Modifier.padding(4.dp), video = item, imageLoader = videoPlayerViewModel.imageLoader!!,
|
||||
selected = id == item.id)
|
||||
selected = id == item.id, apiClient = videoPlayerViewModel.apiClient)
|
||||
{
|
||||
if (name == item.video.name)
|
||||
return@MiniPlaylistCard
|
||||
|
||||
@@ -245,22 +245,25 @@ fun VideoPlayerPortal(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 12.dp),
|
||||
i,
|
||||
{
|
||||
videoPlayerViewModel.isPlaying = false
|
||||
videoPlayerViewModel.player?.pause()
|
||||
apiClient = videoPlayerViewModel.apiClient,
|
||||
imageLoader = videoPlayerViewModel.imageLoader!!
|
||||
) {
|
||||
videoPlayerViewModel.isPlaying = false
|
||||
videoPlayerViewModel.player?.pause()
|
||||
|
||||
val playList = mutableListOf<String>()
|
||||
val fv = videoPlayerViewModel.videoLibrary.classesMap.map { it.value }.flatten()
|
||||
val playList = mutableListOf<String>()
|
||||
val fv =
|
||||
videoPlayerViewModel.videoLibrary.classesMap.map { it.value }.flatten()
|
||||
|
||||
val group = fv.filter { it.klass == i.klass && it.video.group == i.video.group }
|
||||
for (i in group) {
|
||||
playList.add("${i.klass}/${i.id}")
|
||||
}
|
||||
val group =
|
||||
fv.filter { it.klass == i.klass && it.video.group == i.video.group }
|
||||
for (i in group) {
|
||||
playList.add("${i.klass}/${i.id}")
|
||||
}
|
||||
|
||||
val route = "video_player_route/${playList.joinToString(",").toHex()}"
|
||||
navController.navigate(route)
|
||||
}, videoPlayerViewModel.imageLoader!!
|
||||
)
|
||||
val route = "video_player_route/${playList.joinToString(",").toHex()}"
|
||||
navController.navigate(route)
|
||||
}
|
||||
HorizontalDivider(
|
||||
Modifier
|
||||
.padding(vertical = 8.dp)
|
||||
|
||||
@@ -368,7 +368,7 @@ fun VideoCard(
|
||||
|
||||
AsyncImage(
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.data(video.getCover())
|
||||
.data(video.getCover(videoScreenViewModel.apiClient))
|
||||
.memoryCacheKey("${video.klass}/${video.id}/cover")
|
||||
.diskCacheKey("${video.klass}/${video.id}/cover")
|
||||
.build(),
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
package com.acitelight.aether.viewModel
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import coil3.ImageLoader
|
||||
@@ -14,7 +11,7 @@ import com.acitelight.aether.model.BookMark
|
||||
import com.acitelight.aether.model.Comic
|
||||
import com.acitelight.aether.model.ComicRecord
|
||||
import com.acitelight.aether.model.ComicRecordDatabase
|
||||
import com.acitelight.aether.service.ApiClient.createOkHttp
|
||||
import com.acitelight.aether.service.ApiClient
|
||||
import com.acitelight.aether.service.MediaManager
|
||||
import com.acitelight.aether.service.RecentManager
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
@@ -26,7 +23,8 @@ import javax.inject.Inject
|
||||
class ComicGridViewModel @Inject constructor(
|
||||
@ApplicationContext val context: Context,
|
||||
val mediaManager: MediaManager,
|
||||
val recentManager: RecentManager
|
||||
val recentManager: RecentManager,
|
||||
val apiClient: ApiClient
|
||||
) : ViewModel()
|
||||
{
|
||||
var imageLoader: ImageLoader? = null
|
||||
@@ -38,7 +36,7 @@ class ComicGridViewModel @Inject constructor(
|
||||
init {
|
||||
imageLoader = ImageLoader.Builder(context)
|
||||
.components {
|
||||
add(OkHttpNetworkFetcherFactory(createOkHttp()))
|
||||
add(OkHttpNetworkFetcherFactory(apiClient.getClient()))
|
||||
}
|
||||
.build()
|
||||
db = try{
|
||||
|
||||
@@ -17,7 +17,7 @@ import coil3.network.okhttp.OkHttpNetworkFetcherFactory
|
||||
import com.acitelight.aether.model.Comic
|
||||
import com.acitelight.aether.model.ComicRecord
|
||||
import com.acitelight.aether.model.ComicRecordDatabase
|
||||
import com.acitelight.aether.service.ApiClient.createOkHttp
|
||||
import com.acitelight.aether.service.ApiClient
|
||||
import com.acitelight.aether.service.MediaManager
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
@@ -28,7 +28,8 @@ import javax.inject.Inject
|
||||
@HiltViewModel
|
||||
class ComicPageViewModel @Inject constructor(
|
||||
val mediaManager: MediaManager,
|
||||
@ApplicationContext private val context: Context
|
||||
@ApplicationContext private val context: Context,
|
||||
val apiClient: ApiClient
|
||||
) : ViewModel()
|
||||
{
|
||||
var imageLoader: ImageLoader? = null
|
||||
@@ -43,7 +44,7 @@ class ComicPageViewModel @Inject constructor(
|
||||
init{
|
||||
imageLoader = ImageLoader.Builder(context)
|
||||
.components {
|
||||
add(OkHttpNetworkFetcherFactory(createOkHttp()))
|
||||
add(OkHttpNetworkFetcherFactory(apiClient.getClient()))
|
||||
}
|
||||
.build()
|
||||
listState = LazyListState(0, 0)
|
||||
|
||||
@@ -1,28 +1,24 @@
|
||||
package com.acitelight.aether.viewModel
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import coil3.ImageLoader
|
||||
import coil3.network.okhttp.OkHttpNetworkFetcherFactory
|
||||
import com.acitelight.aether.model.Comic
|
||||
import com.acitelight.aether.model.ComicResponse
|
||||
import com.acitelight.aether.service.ApiClient.createOkHttp
|
||||
import com.acitelight.aether.service.ApiClient
|
||||
import com.acitelight.aether.service.MediaManager
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class ComicScreenViewModel @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
val mediaManager: MediaManager
|
||||
val mediaManager: MediaManager,
|
||||
val apiClient: ApiClient
|
||||
) : ViewModel() {
|
||||
|
||||
var imageLoader: ImageLoader? = null;
|
||||
@@ -54,7 +50,7 @@ class ComicScreenViewModel @Inject constructor(
|
||||
init {
|
||||
imageLoader = ImageLoader.Builder(context)
|
||||
.components {
|
||||
add(OkHttpNetworkFetcherFactory(createOkHttp()))
|
||||
add(OkHttpNetworkFetcherFactory(apiClient.getClient()))
|
||||
}
|
||||
.build()
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import coil3.ImageLoader
|
||||
import coil3.network.okhttp.OkHttpNetworkFetcherFactory
|
||||
import com.acitelight.aether.service.ApiClient.createOkHttp
|
||||
import com.acitelight.aether.service.ApiClient
|
||||
import com.acitelight.aether.service.RecentManager
|
||||
import com.acitelight.aether.service.VideoLibrary
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -19,6 +19,7 @@ class HomeScreenViewModel @Inject constructor(
|
||||
val recentManager: RecentManager,
|
||||
@ApplicationContext val context: Context,
|
||||
val videoLibrary: VideoLibrary,
|
||||
val apiClient: ApiClient
|
||||
) : ViewModel()
|
||||
{
|
||||
var imageLoader: ImageLoader? = null
|
||||
@@ -26,7 +27,7 @@ class HomeScreenViewModel @Inject constructor(
|
||||
init{
|
||||
imageLoader = ImageLoader.Builder(context)
|
||||
.components {
|
||||
add(OkHttpNetworkFetcherFactory(createOkHttp()))
|
||||
add(OkHttpNetworkFetcherFactory(apiClient.getClient()))
|
||||
}
|
||||
.build()
|
||||
viewModelScope.launch {
|
||||
|
||||
@@ -1,45 +1,37 @@
|
||||
package com.acitelight.aether.viewModel
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.widget.Toast
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.core.net.toUri
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.acitelight.aether.AetherApp
|
||||
import com.acitelight.aether.Global
|
||||
import com.acitelight.aether.dataStore
|
||||
import com.acitelight.aether.model.Video
|
||||
import com.acitelight.aether.service.ApiClient
|
||||
import com.acitelight.aether.service.AuthManager
|
||||
import com.acitelight.aether.service.MediaManager
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import com.acitelight.aether.service.*
|
||||
import com.acitelight.aether.service.SettingsDataStoreManager
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class MeScreenViewModel @Inject constructor(
|
||||
private val settingsDataStoreManager: SettingsDataStoreManager,
|
||||
@ApplicationContext private val context: Context,
|
||||
val mediaManager: MediaManager
|
||||
val mediaManager: MediaManager,
|
||||
private val apiClient: ApiClient,
|
||||
private val authManager: AuthManager
|
||||
) : ViewModel() {
|
||||
|
||||
val username = mutableStateOf("");
|
||||
val username = mutableStateOf("")
|
||||
val privateKey = mutableStateOf("")
|
||||
val url = mutableStateOf("");
|
||||
val url = mutableStateOf("")
|
||||
val cert = mutableStateOf("")
|
||||
|
||||
val uss = settingsDataStoreManager.useSelfSignedFlow
|
||||
@@ -54,10 +46,10 @@ class MeScreenViewModel @Inject constructor(
|
||||
if(username.value=="" || privateKey.value=="" || url.value=="") return@launch
|
||||
|
||||
try{
|
||||
val usedUrl = ApiClient.apply(context, url.value, if(uss.first()) cert.value else "")
|
||||
apiClient.apply(context, url.value, if(uss.first()) cert.value else "")
|
||||
|
||||
if (mediaManager.token == "null")
|
||||
mediaManager.token = AuthManager.fetchToken(
|
||||
mediaManager.token = authManager.fetchToken(
|
||||
username.value,
|
||||
settingsDataStoreManager.privateKeyFlow.first()
|
||||
)!!
|
||||
@@ -65,7 +57,7 @@ class MeScreenViewModel @Inject constructor(
|
||||
Global.loggedIn = true
|
||||
withContext(Dispatchers.IO)
|
||||
{
|
||||
(context as AetherApp).abyssService?.proxy?.config(ApiClient.getBase().toUri().host!!, 4096)
|
||||
(context as AetherApp).abyssService?.proxy?.config(apiClient.getBase().toUri().host!!, 4096)
|
||||
context.abyssService?.downloader?.init()
|
||||
}
|
||||
}catch(e: Exception)
|
||||
@@ -100,10 +92,10 @@ class MeScreenViewModel @Inject constructor(
|
||||
if (u == "" || p == "" || us == "") return@launch
|
||||
|
||||
try {
|
||||
val usedUrl = ApiClient.apply(context, u, if(uss.first()) c else "")
|
||||
(context as AetherApp).abyssService?.proxy?.config(ApiClient.getBase().toUri().host!!, 4096)
|
||||
val usedUrl = apiClient.apply(context, u, if(uss.first()) c else "")
|
||||
(context as AetherApp).abyssService?.proxy?.config(apiClient.getBase().toUri().host!!, 4096)
|
||||
context.abyssService?.downloader?.init()
|
||||
mediaManager.token = AuthManager.fetchToken(
|
||||
mediaManager.token = authManager.fetchToken(
|
||||
us,
|
||||
p
|
||||
)!!
|
||||
@@ -133,7 +125,7 @@ class MeScreenViewModel @Inject constructor(
|
||||
if (u == "" || p == "" || ur == "") return@launch
|
||||
|
||||
try {
|
||||
mediaManager.token = AuthManager.fetchToken(
|
||||
mediaManager.token = authManager.fetchToken(
|
||||
u,
|
||||
p
|
||||
)!!
|
||||
@@ -141,7 +133,7 @@ class MeScreenViewModel @Inject constructor(
|
||||
Global.loggedIn = true
|
||||
withContext(Dispatchers.IO)
|
||||
{
|
||||
(context as AetherApp).abyssService?.proxy?.config(ApiClient.getBase().toUri().host!!, 4096)
|
||||
(context as AetherApp).abyssService?.proxy?.config(apiClient.getBase().toUri().host!!, 4096)
|
||||
context.abyssService?.downloader?.init()
|
||||
}
|
||||
Toast.makeText(context, "Account Updated", Toast.LENGTH_SHORT).show()
|
||||
|
||||
@@ -9,7 +9,7 @@ import coil3.ImageLoader
|
||||
import coil3.network.okhttp.OkHttpNetworkFetcherFactory
|
||||
import com.acitelight.aether.model.Video
|
||||
import com.acitelight.aether.model.VideoDownloadItemState
|
||||
import com.acitelight.aether.service.ApiClient.createOkHttp
|
||||
import com.acitelight.aether.service.ApiClient
|
||||
import com.acitelight.aether.service.FetchManager
|
||||
import com.acitelight.aether.service.MediaManager
|
||||
import com.acitelight.aether.service.VideoLibrary
|
||||
@@ -20,7 +20,6 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
@@ -29,6 +28,7 @@ class TransmissionScreenViewModel @Inject constructor(
|
||||
@ApplicationContext val context: Context,
|
||||
val videoLibrary: VideoLibrary,
|
||||
val mediaManager: MediaManager,
|
||||
val apiClient: ApiClient
|
||||
) : ViewModel() {
|
||||
var imageLoader: ImageLoader? = null
|
||||
val downloads: SnapshotStateList<VideoDownloadItemState> = mutableStateListOf()
|
||||
@@ -205,7 +205,7 @@ class TransmissionScreenViewModel @Inject constructor(
|
||||
fun pause(id: Int) = fetchManager.pause(id)
|
||||
fun resume(id: Int) = fetchManager.resume(id)
|
||||
fun cancel(id: Int) = fetchManager.cancel(id)
|
||||
fun delete(id: Int, deleteFile: Boolean = true) {
|
||||
fun delete(id: Int) {
|
||||
fetchManager.delete(id) {
|
||||
viewModelScope.launch(Dispatchers.Main) { removeOnMain(id) }
|
||||
}
|
||||
@@ -218,7 +218,7 @@ class TransmissionScreenViewModel @Inject constructor(
|
||||
|
||||
init {
|
||||
imageLoader = ImageLoader.Builder(context).components {
|
||||
add(OkHttpNetworkFetcherFactory(createOkHttp()))
|
||||
add(OkHttpNetworkFetcherFactory(apiClient.getClient()))
|
||||
}.build()
|
||||
|
||||
viewModelScope.launch {
|
||||
|
||||
@@ -8,29 +8,34 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableFloatStateOf
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableLongStateOf
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.core.net.toUri
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.PlaybackException
|
||||
import androidx.media3.common.Player
|
||||
import androidx.media3.common.Player.STATE_READY
|
||||
import androidx.media3.common.Tracks
|
||||
import androidx.media3.common.text.Cue
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.datasource.DefaultDataSource
|
||||
import androidx.media3.datasource.okhttp.OkHttpDataSource
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
|
||||
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
|
||||
import coil3.ImageLoader
|
||||
import coil3.network.okhttp.OkHttpNetworkFetcherFactory
|
||||
import com.acitelight.aether.model.KeyImage
|
||||
import com.acitelight.aether.model.Video
|
||||
import com.acitelight.aether.model.VideoQueryIndex
|
||||
import com.acitelight.aether.model.VideoRecord
|
||||
import com.acitelight.aether.model.VideoRecordDatabase
|
||||
import com.acitelight.aether.service.ApiClient.createOkHttp
|
||||
import com.acitelight.aether.service.ApiClient
|
||||
import com.acitelight.aether.service.MediaManager
|
||||
import com.acitelight.aether.service.RecentManager
|
||||
import com.acitelight.aether.service.VideoLibrary
|
||||
import com.acitelight.aether.view.formatTime
|
||||
import com.acitelight.aether.view.hexToString
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
@@ -38,20 +43,12 @@ import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.Request
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
import androidx.core.net.toUri
|
||||
import androidx.media3.common.Tracks
|
||||
import androidx.media3.datasource.DefaultDataSource
|
||||
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
|
||||
import com.acitelight.aether.Global
|
||||
import com.acitelight.aether.model.KeyImage
|
||||
import com.acitelight.aether.service.VideoLibrary
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.first
|
||||
|
||||
@HiltViewModel
|
||||
class VideoPlayerViewModel @Inject constructor(
|
||||
@@ -59,6 +56,7 @@ class VideoPlayerViewModel @Inject constructor(
|
||||
val mediaManager: MediaManager,
|
||||
val recentManager: RecentManager,
|
||||
val videoLibrary: VideoLibrary,
|
||||
val apiClient: ApiClient
|
||||
) : ViewModel() {
|
||||
var showPlaylist by mutableStateOf(false)
|
||||
var isLandscape by mutableStateOf(false)
|
||||
@@ -79,7 +77,7 @@ class VideoPlayerViewModel @Inject constructor(
|
||||
var renderedFirst = false
|
||||
var videos: List<Video> = listOf()
|
||||
|
||||
private val httpDataSourceFactory = OkHttpDataSource.Factory(createOkHttp())
|
||||
private val httpDataSourceFactory = OkHttpDataSource.Factory(apiClient.getClient())
|
||||
private val defaultDataSourceFactory by lazy {
|
||||
DefaultDataSource.Factory(
|
||||
context,
|
||||
@@ -117,7 +115,7 @@ class VideoPlayerViewModel @Inject constructor(
|
||||
|
||||
imageLoader = ImageLoader.Builder(context)
|
||||
.components {
|
||||
add(OkHttpNetworkFetcherFactory(createOkHttp()))
|
||||
add(OkHttpNetworkFetcherFactory(apiClient.getClient()))
|
||||
}
|
||||
.build()
|
||||
|
||||
@@ -156,7 +154,7 @@ class VideoPlayerViewModel @Inject constructor(
|
||||
)
|
||||
) {
|
||||
try {
|
||||
val client = createOkHttp()
|
||||
val client = apiClient.getClient()
|
||||
|
||||
val headReq = Request.Builder().url(trimmed).head().build()
|
||||
val headResp = try {
|
||||
@@ -240,7 +238,7 @@ class VideoPlayerViewModel @Inject constructor(
|
||||
currentKlass.value = video.klass
|
||||
currentName.value = video.video.name
|
||||
currentDuration.longValue = video.video.duration
|
||||
currentGallery.value = video.getGallery()
|
||||
currentGallery.value = video.getGallery(apiClient)
|
||||
|
||||
player?.apply {
|
||||
stop()
|
||||
@@ -249,7 +247,7 @@ class VideoPlayerViewModel @Inject constructor(
|
||||
|
||||
recentManager.pushVideo(context, VideoQueryIndex(video.klass, video.id))
|
||||
|
||||
val subtitleCandidate = video.getSubtitle().trim()
|
||||
val subtitleCandidate = video.getSubtitle(apiClient).trim()
|
||||
val subtitleUri = tryResolveSubtitleUri(subtitleCandidate)
|
||||
|
||||
if (player == null) {
|
||||
@@ -303,7 +301,7 @@ class VideoPlayerViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
val url = video.getVideo()
|
||||
val url = video.getVideo(apiClient)
|
||||
val videoUri = if (video.isLocal) Uri.fromFile(File(url)) else url.toUri()
|
||||
|
||||
val mediaItem: MediaItem = if (subtitleUri != null) {
|
||||
|
||||
@@ -1,25 +1,19 @@
|
||||
package com.acitelight.aether.viewModel
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateMapOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import coil3.ImageLoader
|
||||
import coil3.network.okhttp.OkHttpNetworkFetcherFactory
|
||||
import com.acitelight.aether.Global
|
||||
import com.acitelight.aether.model.Video
|
||||
import com.acitelight.aether.service.ApiClient.createOkHttp
|
||||
import com.acitelight.aether.service.ApiClient
|
||||
import com.acitelight.aether.service.FetchManager
|
||||
import com.acitelight.aether.service.MediaManager
|
||||
import com.acitelight.aether.service.RecentManager
|
||||
import com.acitelight.aether.service.VideoLibrary
|
||||
import com.tonyodev.fetch2.Status
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
@@ -31,7 +25,6 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
||||
@HiltViewModel
|
||||
@@ -39,12 +32,12 @@ class VideoScreenViewModel @Inject constructor(
|
||||
val fetchManager: FetchManager,
|
||||
@ApplicationContext val context: Context,
|
||||
val mediaManager: MediaManager,
|
||||
val recentManager: RecentManager,
|
||||
val videoLibrary: VideoLibrary
|
||||
val videoLibrary: VideoLibrary,
|
||||
val apiClient: ApiClient
|
||||
) : ViewModel() {
|
||||
private val _tabIndex = mutableIntStateOf(0)
|
||||
val tabIndex: State<Int> = _tabIndex
|
||||
var imageLoader: ImageLoader? = null;
|
||||
var imageLoader: ImageLoader? = null
|
||||
var menuVisibility = mutableStateOf(false)
|
||||
var searchFilter = mutableStateOf("")
|
||||
var doneInit = mutableStateOf(false)
|
||||
@@ -79,7 +72,7 @@ class VideoScreenViewModel @Inject constructor(
|
||||
else {
|
||||
videoLibrary.classes.add("Offline")
|
||||
videoLibrary.updatingMap[0] = true
|
||||
videoLibrary.classesMap["Offline"] = mutableStateListOf<Video>()
|
||||
videoLibrary.classesMap["Offline"] = mutableStateListOf()
|
||||
|
||||
val downloaded = fetchManager.getAllDownloadsAsync().filter {
|
||||
it.status == Status.COMPLETED &&
|
||||
@@ -101,7 +94,7 @@ class VideoScreenViewModel @Inject constructor(
|
||||
fun setTabIndex(index: Int) {
|
||||
viewModelScope.launch()
|
||||
{
|
||||
_tabIndex.intValue = index;
|
||||
_tabIndex.intValue = index
|
||||
if (videoLibrary.updatingMap[index] == true) return@launch
|
||||
|
||||
videoLibrary.updatingMap[index] = true
|
||||
@@ -126,7 +119,7 @@ class VideoScreenViewModel @Inject constructor(
|
||||
init {
|
||||
imageLoader = ImageLoader.Builder(context)
|
||||
.components {
|
||||
add(OkHttpNetworkFetcherFactory(createOkHttp()))
|
||||
add(OkHttpNetworkFetcherFactory(apiClient.getClient()))
|
||||
}
|
||||
.build()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user