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