Skip to content

Commit

Permalink
Merge pull request #20049 from wordpress-mobile/issue/20035-implement…
Browse files Browse the repository at this point in the history
…-web-view-basics

Site Monitor: Implement web view basics
  • Loading branch information
AjeshRPai authored Jan 29, 2024
2 parents 3c64c53 + 9362ef0 commit 9e1592f
Show file tree
Hide file tree
Showing 13 changed files with 734 additions and 109 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package org.wordpress.android.ui.sitemonitor

import android.content.Context
import android.view.View
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.viewinterop.AndroidView
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentContainerView
import androidx.fragment.app.FragmentTransaction
import androidx.fragment.app.commit
import androidx.fragment.app.findFragment

@Suppress("SwallowedException")
@Composable
fun SiteMonitorFragmentContainer(
modifier: Modifier = Modifier,
commit: FragmentTransaction.(containerId: Int) -> Unit
) {
val currentLocalView = LocalView.current
// Using the current view, check if a parent fragment exists.
// This will help ensure that the fragment are nested correctly.
// This assists in saving/restoring the fragments to their proper state
val parentFragment = remember(currentLocalView) {
try {
currentLocalView.findFragment<Fragment>()
} catch (e: IllegalStateException) {
null
}
}
val viewId by rememberSaveable { mutableIntStateOf(View.generateViewId()) }
val container = remember { mutableStateOf<FragmentContainerView?>(null) }
val viewSection: (Context) -> View = remember(currentLocalView) {
{ context ->
FragmentContainerView(context)
.apply { id = viewId }
.also {
val fragmentManager = parentFragment?.childFragmentManager
?: (context as? FragmentActivity)?.supportFragmentManager
fragmentManager?.commit { commit(it.id) }
container.value = it
}
}
}
AndroidView(
modifier = modifier,
factory = viewSection,
update = {}
)

// Be sure to clean up the fragments when the FragmentContainer is disposed
val localContext = LocalContext.current
DisposableEffect(currentLocalView, localContext, container) {
onDispose {
val fragmentManager = parentFragment?.childFragmentManager
?: (localContext as? FragmentActivity)?.supportFragmentManager
// Use the FragmentContainerView to find the inflated fragment
val existingFragment = fragmentManager?.findFragmentById(container.value?.id ?: 0)
if (existingFragment != null && !fragmentManager.isStateSaved) {
// A composable has been removed from the hierarchy if the state isn't saved
fragmentManager.commit {
remove(existingFragment)
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.wordpress.android.ui.sitemonitor

import javax.inject.Inject

class SiteMonitorMapper @Inject constructor(
private val siteMonitorUtils: SiteMonitorUtils
) {
fun toPrepared(url: String, addressToLoad: String, siteMonitorType: SiteMonitorType) = SiteMonitorUiState.Prepared(
model = SiteMonitorModel(
enableJavascript = true,
enableDomStorage = true,
userAgent = siteMonitorUtils.getUserAgent(),
enableChromeClient = true,
url = url,
addressToLoad = addressToLoad,
siteMonitorType = siteMonitorType
)
)

fun toNoNetworkError(buttonClick: () -> Unit) = SiteMonitorUiState.NoNetworkError(buttonClick = buttonClick)

fun toGenericError(buttonClick: () -> Unit) = SiteMonitorUiState.GenericError(buttonClick = buttonClick)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,24 @@ package org.wordpress.android.ui.sitemonitor

import android.annotation.SuppressLint
import android.os.Bundle
import android.util.SparseArray
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.MaterialTheme
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Scaffold
import androidx.compose.material.TabRow
import androidx.compose.material.Text
import androidx.compose.material3.Tab
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
import dagger.hilt.android.AndroidEntryPoint
import org.wordpress.android.R
import org.wordpress.android.WordPress
Expand All @@ -30,73 +31,101 @@ import org.wordpress.android.util.extensions.getSerializableExtraCompat

@AndroidEntryPoint
class SiteMonitorParentActivity: AppCompatActivity() {
val viewModel:SiteMonitorParentViewModel by viewModels()
private var savedStateSparseArray = SparseArray<Fragment.SavedState>()
private var currentSelectItemId = 0

@Suppress("DEPRECATION")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState != null) {
savedStateSparseArray = savedInstanceState.getSparseParcelableArray(
SAVED_STATE_CONTAINER_KEY
)
?: savedStateSparseArray
currentSelectItemId = savedInstanceState.getInt(SAVED_STATE_CURRENT_TAB_KEY)
}
setContent {
AppTheme {
viewModel.start(getSite())
SiteMonitorScreen()
Surface(
modifier = Modifier.fillMaxSize(),
) {
SiteMonitorScreen()
}
}
}
}

override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putSparseParcelableArray(SAVED_STATE_CONTAINER_KEY, savedStateSparseArray)
outState.putInt(SAVED_STATE_CURRENT_TAB_KEY, currentSelectItemId)
}

private fun getSite(): SiteModel {
return requireNotNull(intent.getSerializableExtraCompat(WordPress.SITE)) as SiteModel
}

companion object {
const val SAVED_STATE_CONTAINER_KEY = "ContainerKey"
const val SAVED_STATE_CURRENT_TAB_KEY = "CurrentTabKey"
}

@Composable
@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
fun SiteMonitorScreen(modifier: Modifier = Modifier) {
fun SiteMonitorScreen() {
var selectedTab by rememberSaveable { mutableStateOf(SiteMonitorTabItem.Metrics.route) }
Scaffold(
topBar = {
MainTopAppBar(
title = stringResource(id = R.string.site_monitoring),
navigationIcon = NavigationIcons.BackIcon,
onNavigationIconClick = onBackPressedDispatcher::onBackPressed,
)
},
content = {
TabScreen(modifier = modifier)
}
)
}

@Composable
@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
fun TabScreen(modifier: Modifier = Modifier) {
var tabIndex by remember { mutableStateOf(0) }

val tabs = listOf(
R.string.site_monitoring_tab_title_metrics,
R.string.site_monitoring_tab_title_php_logs,
R.string.site_monitoring_tab_title_web_server_logs
)
) { padding ->
Column(modifier = Modifier.padding(padding)) {
SiteMonitorTabHeader { clickTab ->
selectedTab = clickTab
}
SiteMonitorTabNavigation(selectedTab) { selectedTab ->
val item = enumValues<SiteMonitorTabItem>().find {
it.route == selectedTab
} ?: SiteMonitorTabItem.Metrics

Column(modifier = modifier.fillMaxWidth()) {
TabRow(
selectedTabIndex = tabIndex,
backgroundColor = MaterialTheme.colors.surface,
contentColor = MaterialTheme.colors.onSurface,
) {
tabs.forEachIndexed { index, title ->
Tab(text = { Text(stringResource(id = title)) },
selected = tabIndex == index,
onClick = { tabIndex = index }
SiteMonitorFragmentContainer(
modifier = Modifier.fillMaxSize(),
commit = getCommitFunction(
SiteMonitorTabFragment.newInstance(item.urlTemplate, item.siteMonitorType, getSite()),
item.route
)
)
}
}
when (tabIndex) {
0 -> SiteMonitoringWebView()
1 -> SiteMonitoringWebView()
2 -> SiteMonitoringWebView()
}
}
}

@Composable
fun SiteMonitoringWebView(){
Text(text = "SiteMonitoringWebView")
private fun getCommitFunction(
fragment : Fragment,
tag: String
): FragmentTransaction.(containerId: Int) -> Unit =
{
saveAndRetrieveFragment(supportFragmentManager, it, fragment)
replace(it, fragment, tag)
}

private fun saveAndRetrieveFragment(
supportFragmentManager: FragmentManager,
tabId: Int,
fragment: Fragment
) {
val currentFragment = supportFragmentManager.findFragmentById(currentSelectItemId)
if (currentFragment != null) {
savedStateSparseArray.put(
currentSelectItemId,
supportFragmentManager.saveFragmentInstanceState(currentFragment)
)
}
currentSelectItemId = tabId
fragment.setInitialSavedState(savedStateSparseArray[currentSelectItemId])
}
}

This file was deleted.

Loading

0 comments on commit 9e1592f

Please sign in to comment.