xref: /aosp_15_r20/external/accompanist/web/src/main/java/com/google/accompanist/web/WebView.kt (revision fa44fe6ae8e729aa3cfe5c03eedbbf98fb44e2c6)
1 /*
<lambda>null2  * Copyright 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 @file:Suppress("DEPRECATION")
18 
19 package com.google.accompanist.web
20 
21 import android.content.Context
22 import android.graphics.Bitmap
23 import android.os.Bundle
24 import android.view.ViewGroup.LayoutParams
25 import android.webkit.WebChromeClient
26 import android.webkit.WebResourceError
27 import android.webkit.WebResourceRequest
28 import android.webkit.WebView
29 import android.webkit.WebViewClient
30 import android.widget.FrameLayout
31 import androidx.activity.compose.BackHandler
32 import androidx.compose.foundation.layout.BoxWithConstraints
33 import androidx.compose.runtime.Composable
34 import androidx.compose.runtime.Immutable
35 import androidx.compose.runtime.LaunchedEffect
36 import androidx.compose.runtime.Stable
37 import androidx.compose.runtime.getValue
38 import androidx.compose.runtime.mutableStateListOf
39 import androidx.compose.runtime.mutableStateOf
40 import androidx.compose.runtime.remember
41 import androidx.compose.runtime.rememberCoroutineScope
42 import androidx.compose.runtime.saveable.Saver
43 import androidx.compose.runtime.saveable.mapSaver
44 import androidx.compose.runtime.saveable.rememberSaveable
45 import androidx.compose.runtime.setValue
46 import androidx.compose.runtime.snapshotFlow
47 import androidx.compose.runtime.snapshots.SnapshotStateList
48 import androidx.compose.ui.Modifier
49 import androidx.compose.ui.viewinterop.AndroidView
50 import com.google.accompanist.web.LoadingState.Finished
51 import com.google.accompanist.web.LoadingState.Loading
52 import kotlinx.coroutines.CoroutineScope
53 import kotlinx.coroutines.Dispatchers
54 import kotlinx.coroutines.flow.MutableSharedFlow
55 import kotlinx.coroutines.launch
56 import kotlinx.coroutines.withContext
57 
58 /**
59  * A wrapper around the Android View WebView to provide a basic WebView composable.
60  *
61  * If you require more customisation you are most likely better rolling your own and using this
62  * wrapper as an example.
63  *
64  * The WebView attempts to set the layoutParams based on the Compose modifier passed in. If it
65  * is incorrectly sizing, use the layoutParams composable function instead.
66  *
67  * @param state The webview state holder where the Uri to load is defined.
68  * @param modifier A compose modifier
69  * @param captureBackPresses Set to true to have this Composable capture back presses and navigate
70  * the WebView back.
71  * @param navigator An optional navigator object that can be used to control the WebView's
72  * navigation from outside the composable.
73  * @param onCreated Called when the WebView is first created, this can be used to set additional
74  * settings on the WebView. WebChromeClient and WebViewClient should not be set here as they will be
75  * subsequently overwritten after this lambda is called.
76  * @param onDispose Called when the WebView is destroyed. Provides a bundle which can be saved
77  * if you need to save and restore state in this WebView.
78  * @param client Provides access to WebViewClient via subclassing
79  * @param chromeClient Provides access to WebChromeClient via subclassing
80  * @param factory An optional WebView factory for using a custom subclass of WebView
81  * @sample com.google.accompanist.sample.webview.BasicWebViewSample
82  */
83 @Deprecated(
84     """
85 accompanist/web is deprecated and the API is no longer maintained.
86 We recommend forking the implementation and customising it to your needs.
87 For more information please visit https://google.github.io/accompanist/web
88 """
89 )
90 @Composable
91 public fun WebView(
92     state: WebViewState,
93     modifier: Modifier = Modifier,
94     captureBackPresses: Boolean = true,
95     navigator: WebViewNavigator = rememberWebViewNavigator(),
96     onCreated: (WebView) -> Unit = {},
<lambda>null97     onDispose: (WebView) -> Unit = {},
<lambda>null98     client: AccompanistWebViewClient = remember { AccompanistWebViewClient() },
<lambda>null99     chromeClient: AccompanistWebChromeClient = remember { AccompanistWebChromeClient() },
100     factory: ((Context) -> WebView)? = null,
101 ) {
<lambda>null102     BoxWithConstraints(modifier) {
103         // WebView changes it's layout strategy based on
104         // it's layoutParams. We convert from Compose Modifier to
105         // layout params here.
106         val width =
107             if (constraints.hasFixedWidth)
108                 LayoutParams.MATCH_PARENT
109             else
110                 LayoutParams.WRAP_CONTENT
111         val height =
112             if (constraints.hasFixedHeight)
113                 LayoutParams.MATCH_PARENT
114             else
115                 LayoutParams.WRAP_CONTENT
116 
117         val layoutParams = FrameLayout.LayoutParams(
118             width,
119             height
120         )
121 
122         WebView(
123             state,
124             layoutParams,
125             Modifier,
126             captureBackPresses,
127             navigator,
128             onCreated,
129             onDispose,
130             client,
131             chromeClient,
132             factory
133         )
134     }
135 }
136 
137 /**
138  * A wrapper around the Android View WebView to provide a basic WebView composable.
139  *
140  * If you require more customisation you are most likely better rolling your own and using this
141  * wrapper as an example.
142  *
143  * The WebView attempts to set the layoutParams based on the Compose modifier passed in. If it
144  * is incorrectly sizing, use the layoutParams composable function instead.
145  *
146  * @param state The webview state holder where the Uri to load is defined.
147  * @param layoutParams A FrameLayout.LayoutParams object to custom size the underlying WebView.
148  * @param modifier A compose modifier
149  * @param captureBackPresses Set to true to have this Composable capture back presses and navigate
150  * the WebView back.
151  * @param navigator An optional navigator object that can be used to control the WebView's
152  * navigation from outside the composable.
153  * @param onCreated Called when the WebView is first created, this can be used to set additional
154  * settings on the WebView. WebChromeClient and WebViewClient should not be set here as they will be
155  * subsequently overwritten after this lambda is called.
156  * @param onDispose Called when the WebView is destroyed. Provides a bundle which can be saved
157  * if you need to save and restore state in this WebView.
158  * @param client Provides access to WebViewClient via subclassing
159  * @param chromeClient Provides access to WebChromeClient via subclassing
160  * @param factory An optional WebView factory for using a custom subclass of WebView
161  */
162 @Deprecated(
163     """
164 accompanist/web is deprecated and the API is no longer maintained.
165 We recommend forking the implementation and customising it to your needs.
166 For more information please visit https://google.github.io/accompanist/web
167 """
168 )
169 @Composable
WebViewnull170 public fun WebView(
171     state: WebViewState,
172     layoutParams: FrameLayout.LayoutParams,
173     modifier: Modifier = Modifier,
174     captureBackPresses: Boolean = true,
175     navigator: WebViewNavigator = rememberWebViewNavigator(),
176     onCreated: (WebView) -> Unit = {},
<lambda>null177     onDispose: (WebView) -> Unit = {},
<lambda>null178     client: AccompanistWebViewClient = remember { AccompanistWebViewClient() },
<lambda>null179     chromeClient: AccompanistWebChromeClient = remember { AccompanistWebChromeClient() },
180     factory: ((Context) -> WebView)? = null,
181 ) {
182     val webView = state.webView
183 
<lambda>null184     BackHandler(captureBackPresses && navigator.canGoBack) {
185         webView?.goBack()
186     }
187 
wvnull188     webView?.let { wv ->
189         LaunchedEffect(wv, navigator) {
190             with(navigator) {
191                 wv.handleNavigationEvents()
192             }
193         }
194 
195         LaunchedEffect(wv, state) {
196             snapshotFlow { state.content }.collect { content ->
197                 when (content) {
198                     is WebContent.Url -> {
199                         wv.loadUrl(content.url, content.additionalHttpHeaders)
200                     }
201 
202                     is WebContent.Data -> {
203                         wv.loadDataWithBaseURL(
204                             content.baseUrl,
205                             content.data,
206                             content.mimeType,
207                             content.encoding,
208                             content.historyUrl
209                         )
210                     }
211 
212                     is WebContent.Post -> {
213                         wv.postUrl(
214                             content.url,
215                             content.postData
216                         )
217                     }
218 
219                     is WebContent.NavigatorOnly -> {
220                         // NO-OP
221                     }
222                 }
223             }
224         }
225     }
226 
227     // Set the state of the client and chrome client
228     // This is done internally to ensure they always are the same instance as the
229     // parent Web composable
230     client.state = state
231     client.navigator = navigator
232     chromeClient.state = state
233 
234     AndroidView(
contextnull235         factory = { context ->
236             (factory?.invoke(context) ?: WebView(context)).apply {
237                 onCreated(this)
238 
239                 this.layoutParams = layoutParams
240 
241                 state.viewState?.let {
242                     this.restoreState(it)
243                 }
244 
245                 webChromeClient = chromeClient
246                 webViewClient = client
247             }.also { state.webView = it }
248         },
249         modifier = modifier,
<lambda>null250         onRelease = {
251             onDispose(it)
252         }
253     )
254 }
255 
256 /**
257  * AccompanistWebViewClient
258  *
259  * A parent class implementation of WebViewClient that can be subclassed to add custom behaviour.
260  *
261  * As Accompanist Web needs to set its own web client to function, it provides this intermediary
262  * class that can be overriden if further custom behaviour is required.
263  */
264 @Deprecated(
265     """
266 accompanist/web is deprecated and the API is no longer maintained.
267 We recommend forking the implementation and customising it to your needs.
268 For more information please visit https://google.github.io/accompanist/web
269 """
270 )
271 public open class AccompanistWebViewClient : WebViewClient() {
272     public open lateinit var state: WebViewState
273         internal set
274     public open lateinit var navigator: WebViewNavigator
275         internal set
276 
onPageStartednull277     override fun onPageStarted(view: WebView, url: String?, favicon: Bitmap?) {
278         super.onPageStarted(view, url, favicon)
279         state.loadingState = Loading(0.0f)
280         state.errorsForCurrentRequest.clear()
281         state.pageTitle = null
282         state.pageIcon = null
283 
284         state.lastLoadedUrl = url
285     }
286 
onPageFinishednull287     override fun onPageFinished(view: WebView, url: String?) {
288         super.onPageFinished(view, url)
289         state.loadingState = Finished
290     }
291 
doUpdateVisitedHistorynull292     override fun doUpdateVisitedHistory(view: WebView, url: String?, isReload: Boolean) {
293         super.doUpdateVisitedHistory(view, url, isReload)
294 
295         navigator.canGoBack = view.canGoBack()
296         navigator.canGoForward = view.canGoForward()
297     }
298 
onReceivedErrornull299     override fun onReceivedError(
300         view: WebView,
301         request: WebResourceRequest?,
302         error: WebResourceError?
303     ) {
304         super.onReceivedError(view, request, error)
305 
306         if (error != null) {
307             state.errorsForCurrentRequest.add(WebViewError(request, error))
308         }
309     }
310 }
311 
312 /**
313  * AccompanistWebChromeClient
314  *
315  * A parent class implementation of WebChromeClient that can be subclassed to add custom behaviour.
316  *
317  * As Accompanist Web needs to set its own web client to function, it provides this intermediary
318  * class that can be overriden if further custom behaviour is required.
319  */
320 @Deprecated(
321     """
322 accompanist/web is deprecated and the API is no longer maintained.
323 We recommend forking the implementation and customising it to your needs.
324 For more information please visit https://google.github.io/accompanist/web
325 """
326 )
327 public open class AccompanistWebChromeClient : WebChromeClient() {
328     public open lateinit var state: WebViewState
329         internal set
330 
onReceivedTitlenull331     override fun onReceivedTitle(view: WebView, title: String?) {
332         super.onReceivedTitle(view, title)
333         state.pageTitle = title
334     }
335 
onReceivedIconnull336     override fun onReceivedIcon(view: WebView, icon: Bitmap?) {
337         super.onReceivedIcon(view, icon)
338         state.pageIcon = icon
339     }
340 
onProgressChangednull341     override fun onProgressChanged(view: WebView, newProgress: Int) {
342         super.onProgressChanged(view, newProgress)
343         if (state.loadingState is Finished) return
344         state.loadingState = Loading(newProgress / 100.0f)
345     }
346 }
347 
348 @Deprecated(
349     """
350 accompanist/web is deprecated and the API is no longer maintained.
351 We recommend forking the implementation and customising it to your needs.
352 For more information please visit https://google.github.io/accompanist/web
353 """
354 )
355 public sealed class WebContent {
356     public data class Url(
357         val url: String,
358         val additionalHttpHeaders: Map<String, String> = emptyMap(),
359     ) : WebContent()
360 
361     public data class Data(
362         val data: String,
363         val baseUrl: String? = null,
364         val encoding: String = "utf-8",
365         val mimeType: String? = null,
366         val historyUrl: String? = null
367     ) : WebContent()
368 
369     public data class Post(
370         val url: String,
371         val postData: ByteArray
372     ) : WebContent() {
equalsnull373         override fun equals(other: Any?): Boolean {
374             if (this === other) return true
375             if (javaClass != other?.javaClass) return false
376 
377             other as Post
378 
379             if (url != other.url) return false
380             if (!postData.contentEquals(other.postData)) return false
381 
382             return true
383         }
384 
hashCodenull385         override fun hashCode(): Int {
386             var result = url.hashCode()
387             result = 31 * result + postData.contentHashCode()
388             return result
389         }
390     }
391 
392     @Deprecated("Use state.lastLoadedUrl instead")
getCurrentUrlnull393     public fun getCurrentUrl(): String? {
394         return when (this) {
395             is Url -> url
396             is Data -> baseUrl
397             is Post -> url
398             is NavigatorOnly -> throw IllegalStateException("Unsupported")
399         }
400     }
401 
402     public object NavigatorOnly : WebContent()
403 }
404 
withUrlnull405 internal fun WebContent.withUrl(url: String) = when (this) {
406     is WebContent.Url -> copy(url = url)
407     else -> WebContent.Url(url)
408 }
409 
410 /**
411  * Sealed class for constraining possible loading states.
412  * See [Loading] and [Finished].
413  */
414 @Deprecated(
415     """
416 accompanist/web is deprecated and the API is no longer maintained.
417 We recommend forking the implementation and customising it to your needs.
418 For more information please visit https://google.github.io/accompanist/web
419 """
420 )
421 public sealed class LoadingState {
422     /**
423      * Describes a WebView that has not yet loaded for the first time.
424      */
425     public object Initializing : LoadingState()
426 
427     /**
428      * Describes a webview between `onPageStarted` and `onPageFinished` events, contains a
429      * [progress] property which is updated by the webview.
430      */
431     public data class Loading(val progress: Float) : LoadingState()
432 
433     /**
434      * Describes a webview that has finished loading content.
435      */
436     public object Finished : LoadingState()
437 }
438 
439 /**
440  * A state holder to hold the state for the WebView. In most cases this will be remembered
441  * using the rememberWebViewState(uri) function.
442  */
443 @Deprecated(
444     """
445 accompanist/web is deprecated and the API is no longer maintained.
446 We recommend forking the implementation and customising it to your needs.
447 For more information please visit https://google.github.io/accompanist/web
448 """
449 )
450 @Stable
451 public class WebViewState(webContent: WebContent) {
452     public var lastLoadedUrl: String? by mutableStateOf(null)
453         internal set
454 
455     /**
456      *  The content being loaded by the WebView
457      */
458     public var content: WebContent by mutableStateOf(webContent)
459 
460     /**
461      * Whether the WebView is currently [LoadingState.Loading] data in its main frame (along with
462      * progress) or the data loading has [LoadingState.Finished]. See [LoadingState]
463      */
464     public var loadingState: LoadingState by mutableStateOf(LoadingState.Initializing)
465         internal set
466 
467     /**
468      * Whether the webview is currently loading data in its main frame
469      */
470     public val isLoading: Boolean
471         get() = loadingState !is Finished
472 
473     /**
474      * The title received from the loaded content of the current page
475      */
476     public var pageTitle: String? by mutableStateOf(null)
477         internal set
478 
479     /**
480      * the favicon received from the loaded content of the current page
481      */
482     public var pageIcon: Bitmap? by mutableStateOf(null)
483         internal set
484 
485     /**
486      * A list for errors captured in the last load. Reset when a new page is loaded.
487      * Errors could be from any resource (iframe, image, etc.), not just for the main page.
488      * For more fine grained control use the OnError callback of the WebView.
489      */
490     public val errorsForCurrentRequest: SnapshotStateList<WebViewError> = mutableStateListOf()
491 
492     /**
493      * The saved view state from when the view was destroyed last. To restore state,
494      * use the navigator and only call loadUrl if the bundle is null.
495      * See WebViewSaveStateSample.
496      */
497     public var viewState: Bundle? = null
498         internal set
499 
500     // We need access to this in the state saver. An internal DisposableEffect or AndroidView
501     // onDestroy is called after the state saver and so can't be used.
502     internal var webView by mutableStateOf<WebView?>(null)
503 }
504 
505 /**
506  * Allows control over the navigation of a WebView from outside the composable. E.g. for performing
507  * a back navigation in response to the user clicking the "up" button in a TopAppBar.
508  *
509  * @see [rememberWebViewNavigator]
510  */
511 @Stable
512 @Deprecated(
513     """
514 accompanist/web is deprecated and the API is no longer maintained.
515 We recommend forking the implementation and customising it to your needs.
516 For more information please visit https://google.github.io/accompanist/web
517 """
518 )
519 public class WebViewNavigator(private val coroutineScope: CoroutineScope) {
520     private sealed interface NavigationEvent {
521         object Back : NavigationEvent
522         object Forward : NavigationEvent
523         object Reload : NavigationEvent
524         object StopLoading : NavigationEvent
525 
526         data class LoadUrl(
527             val url: String,
528             val additionalHttpHeaders: Map<String, String> = emptyMap()
529         ) : NavigationEvent
530 
531         data class LoadHtml(
532             val html: String,
533             val baseUrl: String? = null,
534             val mimeType: String? = null,
535             val encoding: String? = "utf-8",
536             val historyUrl: String? = null
537         ) : NavigationEvent
538 
539         data class PostUrl(
540             val url: String,
541             val postData: ByteArray
542         ) : NavigationEvent {
equalsnull543             override fun equals(other: Any?): Boolean {
544                 if (this === other) return true
545                 if (javaClass != other?.javaClass) return false
546 
547                 other as PostUrl
548 
549                 if (url != other.url) return false
550                 if (!postData.contentEquals(other.postData)) return false
551 
552                 return true
553             }
554 
hashCodenull555             override fun hashCode(): Int {
556                 var result = url.hashCode()
557                 result = 31 * result + postData.contentHashCode()
558                 return result
559             }
560         }
561     }
562 
563     private val navigationEvents: MutableSharedFlow<NavigationEvent> = MutableSharedFlow(replay = 1)
564 
565     // Use Dispatchers.Main to ensure that the webview methods are called on UI thread
handleNavigationEventsnull566     internal suspend fun WebView.handleNavigationEvents(): Nothing = withContext(Dispatchers.Main) {
567         navigationEvents.collect { event ->
568             when (event) {
569                 is NavigationEvent.Back -> goBack()
570                 is NavigationEvent.Forward -> goForward()
571                 is NavigationEvent.Reload -> reload()
572                 is NavigationEvent.StopLoading -> stopLoading()
573                 is NavigationEvent.LoadHtml -> loadDataWithBaseURL(
574                     event.baseUrl,
575                     event.html,
576                     event.mimeType,
577                     event.encoding,
578                     event.historyUrl
579                 )
580 
581                 is NavigationEvent.LoadUrl -> {
582                     loadUrl(event.url, event.additionalHttpHeaders)
583                 }
584 
585                 is NavigationEvent.PostUrl -> {
586                     postUrl(event.url, event.postData)
587                 }
588             }
589         }
590     }
591 
592     /**
593      * True when the web view is able to navigate backwards, false otherwise.
594      */
595     public var canGoBack: Boolean by mutableStateOf(false)
596         internal set
597 
598     /**
599      * True when the web view is able to navigate forwards, false otherwise.
600      */
601     public var canGoForward: Boolean by mutableStateOf(false)
602         internal set
603 
loadUrlnull604     public fun loadUrl(url: String, additionalHttpHeaders: Map<String, String> = emptyMap()) {
605         coroutineScope.launch {
606             navigationEvents.emit(
607                 NavigationEvent.LoadUrl(
608                     url,
609                     additionalHttpHeaders
610                 )
611             )
612         }
613     }
614 
loadHtmlnull615     public fun loadHtml(
616         html: String,
617         baseUrl: String? = null,
618         mimeType: String? = null,
619         encoding: String? = "utf-8",
620         historyUrl: String? = null
621     ) {
622         coroutineScope.launch {
623             navigationEvents.emit(
624                 NavigationEvent.LoadHtml(
625                     html,
626                     baseUrl,
627                     mimeType,
628                     encoding,
629                     historyUrl
630                 )
631             )
632         }
633     }
634 
postUrlnull635     public fun postUrl(
636         url: String,
637         postData: ByteArray
638     ) {
639         coroutineScope.launch {
640             navigationEvents.emit(
641                 NavigationEvent.PostUrl(
642                     url,
643                     postData
644                 )
645             )
646         }
647     }
648 
649     /**
650      * Navigates the webview back to the previous page.
651      */
navigateBacknull652     public fun navigateBack() {
653         coroutineScope.launch { navigationEvents.emit(NavigationEvent.Back) }
654     }
655 
656     /**
657      * Navigates the webview forward after going back from a page.
658      */
navigateForwardnull659     public fun navigateForward() {
660         coroutineScope.launch { navigationEvents.emit(NavigationEvent.Forward) }
661     }
662 
663     /**
664      * Reloads the current page in the webview.
665      */
reloadnull666     public fun reload() {
667         coroutineScope.launch { navigationEvents.emit(NavigationEvent.Reload) }
668     }
669 
670     /**
671      * Stops the current page load (if one is loading).
672      */
stopLoadingnull673     public fun stopLoading() {
674         coroutineScope.launch { navigationEvents.emit(NavigationEvent.StopLoading) }
675     }
676 }
677 
678 /**
679  * Creates and remembers a [WebViewNavigator] using the default [CoroutineScope] or a provided
680  * override.
681  */
682 @Composable
683 @Deprecated(
684     """
685 accompanist/web is deprecated and the API is no longer maintained.
686 We recommend forking the implementation and customising it to your needs.
687 For more information please visit https://google.github.io/accompanist/web
688 """
689 )
rememberWebViewNavigatornull690 public fun rememberWebViewNavigator(
691     coroutineScope: CoroutineScope = rememberCoroutineScope()
692 ): WebViewNavigator = remember(coroutineScope) { WebViewNavigator(coroutineScope) }
693 
694 /**
695  * A wrapper class to hold errors from the WebView.
696  */
697 @Immutable
698 @Deprecated(
699     """
700 accompanist/web is deprecated and the API is no longer maintained.
701 We recommend forking the implementation and customising it to your needs.
702 For more information please visit https://google.github.io/accompanist/web
703 """
704 )
705 public data class WebViewError(
706     /**
707      * The request the error came from.
708      */
709     val request: WebResourceRequest?,
710     /**
711      * The error that was reported.
712      */
713     val error: WebResourceError
714 )
715 
716 /**
717  * Creates a WebView state that is remembered across Compositions.
718  *
719  * @param url The url to load in the WebView
720  * @param additionalHttpHeaders Optional, additional HTTP headers that are passed to [WebView.loadUrl].
721  *                              Note that these headers are used for all subsequent requests of the WebView.
722  */
723 @Composable
724 @Deprecated(
725     """
726 accompanist/web is deprecated and the API is no longer maintained.
727 We recommend forking the implementation and customising it to your needs.
728 For more information please visit https://google.github.io/accompanist/web
729 """
730 )
rememberWebViewStatenull731 public fun rememberWebViewState(
732     url: String,
733     additionalHttpHeaders: Map<String, String> = emptyMap()
734 ): WebViewState =
735 // Rather than using .apply {} here we will recreate the state, this prevents
736     // a recomposition loop when the webview updates the url itself.
737     remember {
738         WebViewState(
739             WebContent.Url(
740                 url = url,
741                 additionalHttpHeaders = additionalHttpHeaders
742             )
743         )
744     }.apply {
745         this.content = WebContent.Url(
746             url = url,
747             additionalHttpHeaders = additionalHttpHeaders
748         )
749     }
750 
751 /**
752  * Creates a WebView state that is remembered across Compositions.
753  *
754  * @param data The uri to load in the WebView
755  */
756 @Composable
757 @Deprecated(
758     """
759 accompanist/web is deprecated and the API is no longer maintained.
760 We recommend forking the implementation and customising it to your needs.
761 For more information please visit https://google.github.io/accompanist/web
762 """
763 )
rememberWebViewStateWithHTMLDatanull764 public fun rememberWebViewStateWithHTMLData(
765     data: String,
766     baseUrl: String? = null,
767     encoding: String = "utf-8",
768     mimeType: String? = null,
769     historyUrl: String? = null
770 ): WebViewState =
771     remember {
772         WebViewState(WebContent.Data(data, baseUrl, encoding, mimeType, historyUrl))
773     }.apply {
774         this.content = WebContent.Data(
775             data, baseUrl, encoding, mimeType, historyUrl
776         )
777     }
778 
779 /**
780  * Creates a WebView state that is remembered across Compositions.
781  *
782  * @param url The url to load in the WebView
783  * @param postData The data to be posted to the WebView with the url
784  */
785 @Composable
786 @Deprecated(
787     """
788 accompanist/web is deprecated and the API is no longer maintained.
789 We recommend forking the implementation and customising it to your needs.
790 For more information please visit https://google.github.io/accompanist/web
791 """
792 )
rememberWebViewStatenull793 public fun rememberWebViewState(
794     url: String,
795     postData: ByteArray
796 ): WebViewState =
797 // Rather than using .apply {} here we will recreate the state, this prevents
798     // a recomposition loop when the webview updates the url itself.
799     remember {
800         WebViewState(
801             WebContent.Post(
802                 url = url,
803                 postData = postData
804             )
805         )
806     }.apply {
807         this.content = WebContent.Post(
808             url = url,
809             postData = postData
810         )
811     }
812 
813 /**
814  * Creates a WebView state that is remembered across Compositions and saved
815  * across activity recreation.
816  * When using saved state, you cannot change the URL via recomposition. The only way to load
817  * a URL is via a WebViewNavigator.
818  *
819  * @param data The uri to load in the WebView
820  * @sample com.google.accompanist.sample.webview.WebViewSaveStateSample
821  */
822 @Composable
823 @Deprecated(
824     """
825 accompanist/web is deprecated and the API is no longer maintained.
826 We recommend forking the implementation and customising it to your needs.
827 For more information please visit https://google.github.io/accompanist/web
828 """
829 )
rememberSaveableWebViewStatenull830 public fun rememberSaveableWebViewState(): WebViewState =
831     rememberSaveable(saver = WebStateSaver) {
832         WebViewState(WebContent.NavigatorOnly)
833     }
834 
835 @Deprecated(
836     """
837 accompanist/web is deprecated and the API is no longer maintained.
838 We recommend forking the implementation and customising it to your needs.
839 For more information please visit https://google.github.io/accompanist/web
840 """
841 )
<lambda>null842 public val WebStateSaver: Saver<WebViewState, Any> = run {
843     val pageTitleKey = "pagetitle"
844     val lastLoadedUrlKey = "lastloaded"
845     val stateBundle = "bundle"
846 
847     mapSaver(
848         save = {
849             val viewState = Bundle().apply { it.webView?.saveState(this) }
850             mapOf(
851                 pageTitleKey to it.pageTitle,
852                 lastLoadedUrlKey to it.lastLoadedUrl,
853                 stateBundle to viewState
854             )
855         },
856         restore = {
857             WebViewState(WebContent.NavigatorOnly).apply {
858                 this.pageTitle = it[pageTitleKey] as String?
859                 this.lastLoadedUrl = it[lastLoadedUrlKey] as String?
860                 this.viewState = it[stateBundle] as Bundle?
861             }
862         }
863     )
864 }
865