diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 3c1c1c54..6aa3cc23 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -62,6 +62,7 @@ dependencies {
implementation("androidx.compose.material3:material3")
implementation("androidx.navigation:navigation-compose:2.7.6")
implementation("com.github.fengdai.compose:pulltorefresh:0.2.0")
+ implementation ("androidx.compose.material:material:1.6.8")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
@@ -69,4 +70,5 @@ dependencies {
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
+
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 9c61fa55..d1057b00 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -10,10 +10,11 @@
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
+ android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
- android:usesCleartextTraffic="true"
android:supportsRtl="true"
android:theme="@style/Theme.Composewebview"
+ android:usesCleartextTraffic="true"
tools:targetApi="31">
-
-
-
diff --git a/app/src/main/java/com/kevinnzou/webview/sample/BasicWebViewSample.kt b/app/src/main/java/com/kevinnzou/webview/sample/BasicWebViewSample.kt
index 6d07bc22..f67e710b 100644
--- a/app/src/main/java/com/kevinnzou/webview/sample/BasicWebViewSample.kt
+++ b/app/src/main/java/com/kevinnzou/webview/sample/BasicWebViewSample.kt
@@ -144,7 +144,6 @@ class BasicWebViewSample : ComponentActivity() {
}
}
}
-
WebView(
state = state,
modifier = Modifier
diff --git a/app/src/main/java/com/kevinnzou/webview/sample/PullToRefreshWebViewSample.kt b/app/src/main/java/com/kevinnzou/webview/sample/PullToRefreshWebViewSample.kt
index 48971124..fed47785 100644
--- a/app/src/main/java/com/kevinnzou/webview/sample/PullToRefreshWebViewSample.kt
+++ b/app/src/main/java/com/kevinnzou/webview/sample/PullToRefreshWebViewSample.kt
@@ -1,90 +1,330 @@
package com.kevinnzou.webview.sample
import android.annotation.SuppressLint
-import android.graphics.Bitmap
import android.os.Bundle
import android.util.Log
+import android.webkit.WebChromeClient
import android.webkit.WebView
+import android.webkit.WebViewClient
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
-import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material.ExperimentalMaterialApi
+import androidx.compose.material.Surface
+import androidx.compose.material.pullrefresh.PullRefreshIndicator
+import androidx.compose.material.pullrefresh.pullRefresh
+import androidx.compose.material.pullrefresh.rememberPullRefreshState
+import androidx.compose.material3.LinearProgressIndicator
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableFloatStateOf
+import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import com.github.fengdai.compose.pulltorefresh.PullToRefresh
-import com.github.fengdai.compose.pulltorefresh.rememberPullToRefreshState
-import com.kevinnzou.web.AccompanistWebViewClient
-import com.kevinnzou.web.WebView
-import com.kevinnzou.web.rememberWebViewNavigator
-import com.kevinnzou.web.rememberWebViewState
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.viewinterop.AndroidView
import com.kevinnzou.webview.ui.theme.ComposewebviewTheme
-import kotlinx.coroutines.delay
class PullToRefreshWebViewSample : ComponentActivity() {
- val initialUrl = "https://github.com/KevinnZou/compose-webview"
+// val initialUrl = "https://stackoverflow.com/questions/69199334/trying-to-add-a-refresh-method-to-a-webview-and-having-issues"
+ val initialUrl = "https://www.thelinehotel.com/wp-admin"
+
- @OptIn(ExperimentalMaterial3Api::class)
@SuppressLint("SetJavaScriptEnabled")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ComposewebviewTheme {
- val state = rememberWebViewState(url = initialUrl)
- val navigator = rememberWebViewNavigator()
- var textFieldValue by remember(state.lastLoadedUrl) {
- mutableStateOf(state.lastLoadedUrl)
- }
- var refreshing by remember { mutableStateOf(false) }
- LaunchedEffect(refreshing) {
- if (refreshing) {
- navigator.reload()
- delay(1200)
- refreshing = false
+ /* val state = rememberWebViewState(url = initialUrl)
+ val navigator = rememberWebViewNavigator()
+ var textFieldValue by remember(state.lastLoadedUrl) {
+ mutableStateOf(state.lastLoadedUrl)
+ }
+ val refreshScope = rememberCoroutineScope()
+ var refreshing by remember { mutableStateOf(false) }
+
+ val webClient = remember {
+ object : AccompanistWebViewClient() {
+ override fun onPageStarted(
+ view: WebView,
+ url: String?,
+ favicon: Bitmap?
+ ) {
+ super.onPageStarted(view, url, favicon)
+ Log.d("Accompanist WebView", "Page started loading for $url")
+ }
+ }
+ }
+
+ fun refresh() = refreshScope.launch {
+ refreshing = true
+ delay(1500)
+ refreshing = false
+ }
+
+ val pullRefreshState = rememberPullRefreshState(refreshing, ::refresh)
+
+ LaunchedEffect(key1 = refreshing) {
+ Log.d("saqiii", "onCreate: $refreshing")
+ if (refreshing) {
+ navigator.reload()
+ delay(1000)
+ refreshing = false
+ }
+ }
+
+ Box(
+ Modifier
+ .fillMaxSize()
+ .pullRefresh(pullRefreshState),
+ contentAlignment = Alignment.Center
+ ) {
+ WebView(
+ state = state,
+ modifier = Modifier
+ .background(Color.White)
+ .fillMaxSize(),
+ navigator = navigator,
+ onCreated = { webView ->
+ webView.settings.javaScriptEnabled = true
+ },
+ client = webClient
+ )
+ PullRefreshIndicator(
+ refreshing, pullRefreshState,
+ Modifier
+ .wrapContentSize()
+ .align(Alignment.TopCenter)
+ )
+ }*/
+ WebViewPage(initialUrl)
+ }
+ }
+ }
+}
+
+@OptIn(ExperimentalMaterialApi::class)
+@Composable
+fun WebViewPage2(url: String) {
+ val context = LocalContext.current
+
+ var isRefreshing by remember { mutableStateOf(false) }
+
+ //WEB-VIEW
+ var contentHeight by remember { mutableIntStateOf(0) }
+ val webView = remember(context) {
+ WebView(context).apply {
+ settings.javaScriptEnabled = true
+ settings.useWideViewPort = true
+ setBackgroundColor(0x000000)
+ webChromeClient = object : WebChromeClient()
+ {
+ override fun onProgressChanged(view: WebView?, newProgress: Int) {
+ LinearProgressIndicatorProgress = newProgress / 100f
+ }
+ }
+ webViewClient = object : WebViewClient() {
+ override fun onPageFinished(
+ view: WebView?,
+ url: String?
+ ) {
+ isRefreshing = false
+ view?.evaluateJavascript(
+ "(function() { return document.body.scrollHeight; })();"
+ ) { height ->
+ contentHeight = height?.toInt() ?: 0
+ Log.d("saqiii", "onPageFinished:$contentHeight")
}
}
+ }
+ loadUrl(url)
+ }
+ }
- PullToRefresh(
- state = rememberPullToRefreshState(isRefreshing = refreshing),
- onRefresh = { refreshing = true }
+ val pullRefreshState = rememberPullRefreshState(
+ refreshing = isRefreshing,
+ onRefresh = {
+ isRefreshing = true
+ webView.reload()
+ }
+ )
+
+ //PROGRESS INDICATOR FOR WEB-VIEW
+ Surface(
+ modifier = Modifier
+ .fillMaxSize()
+ ) {
+ CompositionLocalProvider(LocalContext provides context) {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .pullRefresh(pullRefreshState)
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .verticalScroll(rememberScrollState())
) {
- Column(
- modifier = Modifier.verticalScroll(state = rememberScrollState())
- ) {
- // A custom WebViewClient and WebChromeClient can be provided via subclassing
- val webClient = remember {
- object : AccompanistWebViewClient() {
- override fun onPageStarted(
- view: WebView,
- url: String?,
- favicon: Bitmap?
- ) {
- super.onPageStarted(view, url, favicon)
- Log.d("Accompanist WebView", "Page started loading for $url")
- }
- }
+ if (LinearProgressIndicatorProgress < 1f) {
+ LinearProgressIndicator(
+ progress = LinearProgressIndicatorProgress,
+ color = Color(0xffae52de),
+ modifier = Modifier.fillMaxWidth()
+ )
+ }
+ AndroidView(
+ factory = { webView },
+ modifier = if (contentHeight < 700) {
+ Modifier
+ .fillMaxSize()
+ .weight(1f)
+ } else {
+ Modifier
+ .fillMaxSize()
+
}
+ )
+ }
+ //PULL-TO-REFRESH
+ PullRefreshIndicator(
+ refreshing = isRefreshing,
+ state = pullRefreshState,
+ contentColor = Color(0xffae52de),
+ modifier = Modifier.align(Alignment.TopCenter)
+ )
- WebView(
- state = state,
- modifier = Modifier
- .fillMaxSize(),
- navigator = navigator,
- onCreated = { webView ->
- webView.settings.javaScriptEnabled = true
- },
- client = webClient
+ if (isRefreshing) {
+ Text(
+ text = "Pull to refresh",
+ color = Color(0xffae52de),
+ modifier = Modifier
+ .align(Alignment.TopCenter)
+ .padding(top = 60.dp)
+ )
+ }
+ }
+ }
+ LaunchedEffect(webView) {
+ webView.webViewClient = object : WebViewClient() {
+ override fun onPageFinished(view: WebView?, url: String?) {
+ isRefreshing = false
+ }
+ }
+ }
+ }
+}
+@OptIn(ExperimentalMaterialApi::class)
+@Composable
+fun WebViewPage(url: String) {
+ val context = LocalContext.current
+
+ var isRefreshing by remember { mutableStateOf(false) }
+ var LinearProgressIndicatorProgress by remember { mutableFloatStateOf(0f) }
+ var contentHeight by remember { mutableIntStateOf(0) }
+
+ // Remember the WebView instance
+ val webView = remember {
+ WebView(context).apply {
+ settings.javaScriptEnabled = true
+ settings.useWideViewPort = true
+ setBackgroundColor(0x000000)
+ webChromeClient = object : WebChromeClient() {
+ override fun onProgressChanged(view: WebView?, newProgress: Int) {
+ LinearProgressIndicatorProgress = newProgress / 100f
+ }
+ }
+ webViewClient = object : WebViewClient() {
+ override fun onPageFinished(view: WebView?, url: String?) {
+ isRefreshing = false
+ view?.evaluateJavascript(
+ "(function() { return document.body.scrollHeight; })();"
+ ) { height ->
+ height?.toIntOrNull()?.let {
+ contentHeight = it
+ Log.d("WebViewPage", "Content height: $contentHeight")
+ }
+ }
+ }
+ }
+ loadUrl(url)
+ }
+ }
+
+ val pullRefreshState = rememberPullRefreshState(
+ refreshing = isRefreshing,
+ onRefresh = {
+ isRefreshing = true
+ webView.reload()
+ }
+ )
+
+ // Progress indicator for WebView
+ Surface(modifier = Modifier.fillMaxSize()) {
+ CompositionLocalProvider(LocalContext provides context) {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .pullRefresh(pullRefreshState)
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .verticalScroll(rememberScrollState())
+ ) {
+ if (LinearProgressIndicatorProgress < 1f) {
+ LinearProgressIndicator(
+ progress = LinearProgressIndicatorProgress,
+ color = Color(0xffae52de),
+ modifier = Modifier.fillMaxWidth()
)
}
+ AndroidView(
+ factory = { webView },
+ modifier = if (contentHeight < 700) {
+ Modifier
+ .fillMaxSize()
+ .weight(1f)
+ } else {
+ Modifier.fillMaxSize()
+ }
+ )
+ }
+ // Pull-to-refresh indicator
+ PullRefreshIndicator(
+ refreshing = isRefreshing,
+ state = pullRefreshState,
+ contentColor = Color(0xffae52de),
+ modifier = Modifier.align(Alignment.TopCenter)
+ )
+
+ if (isRefreshing) {
+ Text(
+ text = "Pull to refresh",
+ color = Color(0xffae52de),
+ modifier = Modifier
+ .align(Alignment.TopCenter)
+ .padding(top = 60.dp)
+ )
}
}
}
}
-}
\ No newline at end of file
+}
+
+
+private var LinearProgressIndicatorProgress by mutableFloatStateOf(0f)
\ No newline at end of file
diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml
new file mode 100644
index 00000000..dca93c07
--- /dev/null
+++ b/app/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/web/src/main/java/com/kevinnzou/web/WebView.kt b/web/src/main/java/com/kevinnzou/web/WebView.kt
index cb60d0f3..812345eb 100644
--- a/web/src/main/java/com/kevinnzou/web/WebView.kt
+++ b/web/src/main/java/com/kevinnzou/web/WebView.kt
@@ -19,7 +19,7 @@
package com.kevinnzou.web
import android.content.Context
-import android.view.ViewGroup.LayoutParams
+import android.view.ViewGroup
import android.webkit.WebView
import android.widget.FrameLayout
import androidx.activity.compose.BackHandler
@@ -57,7 +57,7 @@ import androidx.compose.ui.viewinterop.AndroidView
* @sample com.google.accompanist.sample.webview.BasicWebViewSample
*/
@Composable
-public fun WebView(
+fun WebView(
state: WebViewState,
modifier: Modifier = Modifier,
captureBackPresses: Boolean = true,
@@ -74,20 +74,19 @@ public fun WebView(
// layout params here.
val width =
if (constraints.hasFixedWidth)
- LayoutParams.MATCH_PARENT
+ ViewGroup.LayoutParams.MATCH_PARENT
else
- LayoutParams.WRAP_CONTENT
+ ViewGroup.LayoutParams.WRAP_CONTENT
val height =
if (constraints.hasFixedHeight)
- LayoutParams.MATCH_PARENT
+ ViewGroup.LayoutParams.MATCH_PARENT
else
- LayoutParams.WRAP_CONTENT
+ ViewGroup.LayoutParams.WRAP_CONTENT
val layoutParams = FrameLayout.LayoutParams(
width,
height
)
-
WebView(
state,
layoutParams,
@@ -129,7 +128,7 @@ public fun WebView(
* @param factory An optional WebView factory for using a custom subclass of WebView
*/
@Composable
-public fun WebView(
+fun WebView(
state: WebViewState,
layoutParams: FrameLayout.LayoutParams,
modifier: Modifier = Modifier,
@@ -146,7 +145,6 @@ public fun WebView(
BackHandler(captureBackPresses && navigator.canGoBack) {
webView?.goBack()
}
-
webView?.let { wv ->
LaunchedEffect(wv, navigator) {
with(navigator) {
@@ -155,6 +153,7 @@ public fun WebView(
}
LaunchedEffect(wv, state) {
+
snapshotFlow { state.content }.collect { content ->
when (content) {
is WebContent.Url -> {
@@ -201,13 +200,10 @@ public fun WebView(
factory = { context ->
(factory?.invoke(context) ?: WebView(context)).apply {
onCreated(this)
-
this.layoutParams = layoutParams
-
state.viewState?.let {
this.restoreState(it)
}
-
webChromeClient = chromeClient
webViewClient = client
}.also { state.webView = it }
@@ -218,3 +214,6 @@ public fun WebView(
}
)
}
+
+
+