Skip to content

Commit

Permalink
wip: 🚧 add info switch functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
TobyBridle committed Nov 21, 2023
1 parent 3d0b4ae commit 41d914f
Show file tree
Hide file tree
Showing 11 changed files with 310 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import android.util.Log
import android.webkit.JavascriptInterface
import android.webkit.WebView
import android.webkit.WebViewClient
import com.chouten.app.BuildConfig
import com.chouten.app.R
import com.chouten.app.domain.model.Payloads_V2.Action_V2
import com.chouten.app.domain.model.Payloads_V3.Action_V3
import com.chouten.app.domain.repository.WebviewHandler
import com.chouten.app.domain.repository.postWebMessage
import com.chouten.app.presentation.ui.screens.info.SwitchConfig
import com.lagradost.nicehttp.Requests
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
Expand All @@ -20,13 +22,13 @@ import kotlinx.serialization.json.Json
import okhttp3.RequestBody.Companion.toRequestBody
import javax.inject.Inject

class WebviewHandlerImpl<BaseResultPayload : WebviewHandler.Companion.ActionPayload<Action_V2>> @Inject constructor(
class WebviewHandlerImpl<BaseResultPayload : WebviewHandler.Companion.ActionPayload<Action_V3>> @Inject constructor(
private val httpClient: Requests,
/**
* Converts an object such as { "action": "search", "result": "..." } to the correct payload
*/
private val resultConverter: (Action_V2, String) -> BaseResultPayload
) : WebviewHandler<Action_V2, BaseResultPayload> {
private val resultConverter: (Action_V3, String) -> BaseResultPayload
) : WebviewHandler<Action_V3, BaseResultPayload> {

override val formatVersion: Int = 2

Expand All @@ -37,6 +39,8 @@ class WebviewHandlerImpl<BaseResultPayload : WebviewHandler.Companion.ActionPayl
private lateinit var webview: WebView
private lateinit var commonCode: String

private lateinit var switchConfig: SwitchConfig
private var isSwitchToggled = false

@OptIn(ExperimentalSerializationApi::class)
private val json = Json {
Expand All @@ -57,7 +61,7 @@ class WebviewHandlerImpl<BaseResultPayload : WebviewHandler.Companion.ActionPayl
webview.settings.javaScriptEnabled = true
webview.settings.domStorageEnabled = true
webview.addJavascriptInterface(this, "Native")
WebView.setWebContentsDebuggingEnabled(true)
WebView.setWebContentsDebuggingEnabled(BuildConfig.DEBUG)
}
if (!::commonCode.isInitialized) {
commonCode = getCommonCode(context)
Expand All @@ -75,7 +79,7 @@ class WebviewHandlerImpl<BaseResultPayload : WebviewHandler.Companion.ActionPayl
* @throws IllegalStateException if the common code is not initialized
*/
override suspend fun load(
code: String, payload: WebviewHandler.Companion.WebviewPayload<Action_V2>
code: String, payload: WebviewHandler.Companion.WebviewPayload<Action_V3>
) {
if (!::webview.isInitialized) {
throw IllegalStateException("Webview handler is not initialized")
Expand All @@ -88,7 +92,7 @@ class WebviewHandlerImpl<BaseResultPayload : WebviewHandler.Companion.ActionPayl
// We need to wait for the webview to finish loading before we can inject the payload
override fun onPageFinished(view: WebView?, url: String?) {
val response = WebviewHandler.Companion.BasePayload(
requestId = "-1", action = Action_V2.LOGIC, payload = payload
requestId = "-1", action = Action_V3.LOGIC, payload = payload
)

webview.postWebMessage(response)
Expand All @@ -108,7 +112,7 @@ class WebviewHandlerImpl<BaseResultPayload : WebviewHandler.Companion.ActionPayl
* @throws IllegalStateException if the webview handler is not initialized
* @throws IllegalStateException if the common code is not initialized
*/
override suspend fun submitPayload(payload: WebviewHandler.Companion.RequestPayload<Action_V2>) {
override suspend fun submitPayload(payload: WebviewHandler.Companion.RequestPayload<Action_V3>) {
if (!::webview.isInitialized) {
throw IllegalStateException("Webview handler is not initialized")
}
Expand All @@ -120,14 +124,14 @@ class WebviewHandlerImpl<BaseResultPayload : WebviewHandler.Companion.ActionPayl
}

when (payload.action) {
Action_V2.HTTP_REQUEST -> handleHttpRequest(payload)
Action_V2.RESULT -> callback(
Action_V3.HTTP_REQUEST -> handleHttpRequest(payload)
Action_V3.RESULT -> callback(
resultConverter(
payload.action, payload.result ?: "null"
)
)

Action_V2.ERROR -> destroy()
Action_V3.ERROR -> destroy()
else -> throw IllegalArgumentException("Invalid action")
}
}
Expand Down Expand Up @@ -169,7 +173,7 @@ class WebviewHandlerImpl<BaseResultPayload : WebviewHandler.Companion.ActionPayl
* @throws IllegalArgumentException if the method is invalid
*/
private suspend fun handleHttpRequest(
payload: WebviewHandler.Companion.RequestPayload<Action_V2>
payload: WebviewHandler.Companion.RequestPayload<Action_V3>
) {
val responseText = withContext(Dispatchers.IO) {
when (payload.method) {
Expand Down Expand Up @@ -216,14 +220,14 @@ class WebviewHandlerImpl<BaseResultPayload : WebviewHandler.Companion.ActionPayl
runBlocking {
try {
val payload =
json.decodeFromString<WebviewHandler.Companion.RequestPayload<Action_V2>>(
json.decodeFromString<WebviewHandler.Companion.RequestPayload<Action_V3>>(
data
)
submitPayload(payload)
} catch (e: Exception) {
e.printStackTrace()
val error = resultConverter(
Action_V2.ERROR, e.message ?: "Unknown Error"
Action_V3.ERROR, e.message ?: "Unknown Error"
)
callback(error)
}
Expand All @@ -239,19 +243,59 @@ class WebviewHandlerImpl<BaseResultPayload : WebviewHandler.Companion.ActionPayl
runBlocking {
try {
val parsed = resultConverter(
Action_V2.RESULT, data
Action_V3.RESULT, data
)
callback(parsed)
} catch (e: Exception) {
e.printStackTrace()
val error = resultConverter(
Action_V2.ERROR, e.message ?: "Unknown Error"
Action_V3.ERROR, e.message ?: "Unknown Error"
)
callback(error)
}
}
}

@JavascriptInterface
fun getSwitchValue(): Int {
if (!::switchConfig.isInitialized) {
return 0
}
// If the toggle is switched (1) but the default value is also 1,
// we want to return 0 instead
return if (isSwitchToggled xor (switchConfig.default == 0)) 1 else 0
}

override fun <T> getGenericValue(key: String): T? {
return when (key) {
"switchConfig" -> {
if (::switchConfig.isInitialized) {
switchConfig as? T
} else null
}

"switchValue" -> {
return (isSwitchToggled xor (switchConfig.default == 0)) as T?
}

else -> throw IllegalArgumentException("Invalid key $key")
}
}

override fun <T> setGenericValue(key: String, value: T) {
when (key) {
"switchConfig" -> {
switchConfig = value as SwitchConfig
}

"switchValue" -> {
isSwitchToggled = (value as Boolean) xor (switchConfig.default == 0)
}

else -> throw IllegalArgumentException("Invalid key $key")
}
}

/**
* Used by the JS code to log a message
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.chouten.app.di

import android.util.Log
import com.chouten.app.data.repository.WebviewHandlerImpl
import com.chouten.app.domain.model.Payloads_V2
import com.chouten.app.domain.model.Payloads_V3
import com.chouten.app.domain.repository.WebviewHandler
import com.chouten.app.presentation.ui.screens.info.InfoResult
import com.chouten.app.presentation.ui.screens.info.SwitchConfig
import com.chouten.app.presentation.ui.screens.search.SearchResult
import com.chouten.app.presentation.ui.screens.watch.WatchResult
import com.lagradost.nicehttp.Requests
Expand All @@ -18,65 +20,79 @@ import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object WebviewModuleV2 {
object WebviewModuleV3 {

@Singleton
@Provides
fun provideSearchWebviewHandler(client: Requests): WebviewHandler<Payloads_V2.Action_V2, Payloads_V2.GenericPayload<List<SearchResult>>> {
fun provideSearchWebviewHandler(client: Requests): WebviewHandler<Payloads_V3.Action_V3, Payloads_V3.GenericPayload<List<SearchResult>>> {
return WebviewHandlerImpl(client) { action, result: String ->
Payloads_V2.GenericPayload(action, Json.decodeFromString(result))
Payloads_V3.GenericPayload(action, Json.decodeFromString(result))
}
}

@OptIn(ExperimentalSerializationApi::class)
@Provides
fun provideInfoMetadataWebviewHandler(client: Requests): WebviewHandler<Payloads_V2.Action_V2, Payloads_V2.GenericPayload<InfoResult>> {
fun provideSwitchConfigWebviewHandler(client: Requests): WebviewHandler<Payloads_V3.Action_V3, Payloads_V3.GenericPayload<SwitchConfig>> {
val json = Json {
ignoreUnknownKeys = true
isLenient = true
explicitNulls = false
}
return WebviewHandlerImpl(client) { action, result: String ->
Payloads_V2.GenericPayload(action, json.decodeFromString(result))
Payloads_V3.GenericPayload(action, json.decodeFromString(result))
}
}

@OptIn(ExperimentalSerializationApi::class)
@Provides
fun provideInfoEpListWebviewHandler(client: Requests): WebviewHandler<Payloads_V2.Action_V2, Payloads_V2.GenericPayload<List<InfoResult.MediaListItem>>> {
fun provideInfoMetadataWebviewHandler(client: Requests): WebviewHandler<Payloads_V3.Action_V3, Payloads_V3.GenericPayload<InfoResult>> {
val json = Json {
ignoreUnknownKeys = true
isLenient = true
explicitNulls = false
}
return WebviewHandlerImpl(client) { action, result: String ->
Payloads_V2.GenericPayload(action, json.decodeFromString(result))
Payloads_V3.GenericPayload(action, json.decodeFromString(result))
}
}

@OptIn(ExperimentalSerializationApi::class)
@Provides
fun provideServerWebviewHandler(client: Requests): WebviewHandler<Payloads_V2.Action_V2, Payloads_V2.GenericPayload<List<WatchResult.ServerData>>> {
fun provideInfoEpListWebviewHandler(client: Requests): WebviewHandler<Payloads_V3.Action_V3, Payloads_V3.GenericPayload<List<InfoResult.MediaListItem>>> {
val json = Json {
ignoreUnknownKeys = true
isLenient = true
explicitNulls = false
}
return WebviewHandlerImpl(client) { action, result: String ->
Payloads_V2.GenericPayload(action, json.decodeFromString(result))
Log.d("WEBVIEW", "RESULT: $result")
Payloads_V3.GenericPayload(action, json.decodeFromString(result))
}
}

@OptIn(ExperimentalSerializationApi::class)
@Provides
fun provideSourceWebviewHandler(client: Requests): WebviewHandler<Payloads_V2.Action_V2, Payloads_V2.GenericPayload<WatchResult>> {
fun provideServerWebviewHandler(client: Requests): WebviewHandler<Payloads_V3.Action_V3, Payloads_V3.GenericPayload<List<WatchResult.ServerData>>> {
val json = Json {
ignoreUnknownKeys = true
isLenient = true
explicitNulls = false
}
return WebviewHandlerImpl(client) { action, result: String ->
Payloads_V2.GenericPayload(action, json.decodeFromString(result))
Payloads_V3.GenericPayload(action, json.decodeFromString(result))
}
}

@OptIn(ExperimentalSerializationApi::class)
@Provides
fun provideSourceWebviewHandler(client: Requests): WebviewHandler<Payloads_V3.Action_V3, Payloads_V3.GenericPayload<WatchResult>> {
val json = Json {
ignoreUnknownKeys = true
isLenient = true
explicitNulls = false
}
return WebviewHandlerImpl(client) { action, result: String ->
Payloads_V3.GenericPayload(action, json.decodeFromString(result))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ data class ModuleModel(
* with the current version of the app.
* The value is inclusive (e.g if 3, 3 is the maximum working version).
*/
const val MAX_FORMAT_VERSION = 2
const val MAX_FORMAT_VERSION = 3

/**
* Convert the ByteArray icon to a Bitmap.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import kotlinx.serialization.Serializable
* The payloads and actions for format version 2
* @see WebviewHandler
*/
object Payloads_V2 {
object Payloads_V3 {
@Serializable
enum class Action_V2 {
enum class Action_V3 {
@SerialName("HTTPRequest")
HTTP_REQUEST,

Expand All @@ -32,6 +32,9 @@ object Payloads_V2 {
@SerialName("info")
GET_INFO,

@SerialName("switchConfig")
GET_SWITCH_CONFIG,

@SerialName("metadata")
GET_METADATA,

Expand All @@ -43,6 +46,7 @@ object Payloads_V2 {

@SerialName("server")
GET_SERVER,

}

/**
Expand All @@ -55,12 +59,12 @@ object Payloads_V2 {
*/
@Serializable
data class GenericPayload<T>(
override val action: Action_V2,
override val action: Action_V3,
val result: Result<T>,
) : WebviewHandler.Companion.ActionPayload<Action_V2> {
) : WebviewHandler.Companion.ActionPayload<Action_V3> {
@Serializable
data class Result<T>(
val action: Action_V2,
val action: Action_V3,
val result: T,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import kotlinx.serialization.serializer
* @param ResultPayload the payload that the webview handler returns to the callback
* @property formatVersion The version that the webview handler is targeting
* @property callback The callback that the app uses to handle data from the webview handler
* @see com.chouten.app.domain.model.Payloads_V2.Action_V2
* @see com.chouten.app.domain.model.Payloads_V2.GenericPayload
* @see com.chouten.app.domain.model.Payloads_V3.Action_V3
* @see com.chouten.app.domain.model.Payloads_V3.GenericPayload
* @see com.chouten.app.data.repository.WebviewHandlerImpl
*/
interface WebviewHandler<Action : Enum<Action>, ResultPayload : WebviewHandler.Companion.ActionPayload<Action>> {
Expand Down Expand Up @@ -73,6 +73,9 @@ interface WebviewHandler<Action : Enum<Action>, ResultPayload : WebviewHandler.C
*/
suspend fun getCommonCode(context: Context): String

fun <T> getGenericValue(key: String): T?
fun <T> setGenericValue(key: String, value: T)

companion object {

/**
Expand Down Expand Up @@ -143,7 +146,7 @@ interface WebviewHandler<Action : Enum<Action>, ResultPayload : WebviewHandler.C
* The interface used by the app to build a specific ResultPayload
* @param Action the enum containing all the actions that the webview handler can handle
* @property action The action
* @see com.chouten.app.domain.model.Payloads_V2.GenericPayload
* @see com.chouten.app.domain.model.Payloads_V3.GenericPayload
*/
interface ActionPayload<Action : Enum<Action>> {
val action: Action
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ package com.chouten.app.presentation.ui.screens.home
//class HomeViewModel @Inject constructor(
// val application: Application,
// val moduleUseCases: ModuleUseCases,
// val webviewHandler: WebviewHandler<Action_V2, GenericPayload<List<SearchResult>>>,
// val webviewHandler: WebviewHandler<Action_V3, GenericPayload<List<SearchResult>>>,
// private val logUseCases: LogUseCases
//) : ViewModel() {
// init {
Expand All @@ -21,7 +21,7 @@ package com.chouten.app.presentation.ui.screens.home
// }
//
// webviewHandler.initialize(application) { res ->
// if (res.action != Action_V2.RESULT) return@initialize
// if (res.action != Action_V3.RESULT) return@initialize
// Log.d("WEBVIEW", "RESULT: ${res.result.result}")
// }
// moduleUseCases.getModuleUris().find {
Expand All @@ -30,7 +30,7 @@ package com.chouten.app.presentation.ui.screens.home
// val code: String = model.code?.search?.getOrNull(0)?.code ?: ""
// webviewHandler.load(
// code, WebviewHandler.Companion.WebviewPayload(
// query = "Operation Barbershop", action = Action_V2.SEARCH
// query = "Operation Barbershop", action = Action_V3.SEARCH
// )
// )
// }
Expand Down
Loading

0 comments on commit 41d914f

Please sign in to comment.