From 264de0a2d9ccf8b565afaa1ab752da51d496f714 Mon Sep 17 00:00:00 2001 From: jackie-yellow Date: Sat, 13 May 2023 18:30:21 +0800 Subject: [PATCH] =?UTF-8?q?:construction:=20=20=20=20=20=20=20=20=20=20=20?= =?UTF-8?q?=20=20=20=20=20=20=E5=B0=86=E5=BC=B9=E5=87=BA=E6=A1=86=E9=83=A8?= =?UTF-8?q?=E5=88=86=E7=BB=84=E4=BB=B6=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/src/main/AndroidManifest.xml | 3 +- .../info/bagen/dwebbrowser/SplashActivity.kt | 2 +- .../dwebbrowser/database/WebSiteModel.kt | 7 +- .../microService/browser/BrowserActivity.kt | 4 +- .../microService/browser/BrowserController.kt | 2 +- .../ui/browser/BrowserListOfBook.kt | 283 ++++++++++++++ .../ui/browser/BrowserListOfHistory.kt | 116 ++++++ .../ui/browser/{ios => }/BrowserMain.kt | 2 +- .../ui/browser/{ios => }/BrowserPopup.kt | 369 ++++-------------- .../ui/browser/{ios => }/BrowserSearch.kt | 75 ++-- .../ui/browser/{ios => }/BrowserView.kt | 46 ++- .../ui/browser/{ios => }/BrowserViewModel.kt | 21 +- .../ui/browser/{ios => }/BrowserWeb.kt | 2 +- .../ui/browser/android/BrowserView.kt | 42 -- .../ui/browser/android/BrowserViewModel.kt | 8 - 15 files changed, 573 insertions(+), 409 deletions(-) create mode 100644 android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserListOfBook.kt create mode 100644 android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserListOfHistory.kt rename android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/{ios => }/BrowserMain.kt (99%) rename android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/{ios => }/BrowserPopup.kt (53%) rename android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/{ios => }/BrowserSearch.kt (88%) rename android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/{ios => }/BrowserView.kt (92%) rename android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/{ios => }/BrowserViewModel.kt (95%) rename android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/{ios => }/BrowserWeb.kt (98%) delete mode 100644 android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/android/BrowserView.kt delete mode 100644 android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/android/BrowserViewModel.kt diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 115e2b81d9..66bbb75297 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -65,7 +65,8 @@ android:name="info.bagen.dwebbrowser.microService.browser.BrowserActivity" android:exported="true" android:label="@string/app_name" - android:theme="@style/Theme.plaoc" /> + android:theme="@style/Theme.plaoc" + android:screenOrientation="portrait" /> - @Query("SELECT * FROM $WebSiteTableName WHERE type IN (:type)") + @Query("SELECT * FROM $WebSiteTableName WHERE type IN (:type) limit 500") fun loadAllByTypeObserve(type: WebSiteType): LiveData> @Query( diff --git a/android/app/src/main/java/info/bagen/dwebbrowser/microService/browser/BrowserActivity.kt b/android/app/src/main/java/info/bagen/dwebbrowser/microService/browser/BrowserActivity.kt index 8483eab364..5950c5c9e2 100644 --- a/android/app/src/main/java/info/bagen/dwebbrowser/microService/browser/BrowserActivity.kt +++ b/android/app/src/main/java/info/bagen/dwebbrowser/microService/browser/BrowserActivity.kt @@ -12,7 +12,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.core.view.WindowCompat import info.bagen.dwebbrowser.microService.browser.BrowserNMM.Companion.browserController -import info.bagen.dwebbrowser.ui.browser.ios.BrowserView +import info.bagen.dwebbrowser.ui.browser.BrowserView import info.bagen.dwebbrowser.ui.camera.QRCodeIntent import info.bagen.dwebbrowser.ui.camera.QRCodeScanning import info.bagen.dwebbrowser.ui.camera.QRCodeScanningView @@ -36,7 +36,7 @@ class BrowserActivity : AppCompatActivity() { browserController.effect(activity = this@BrowserActivity) Box(modifier = Modifier.background(Color.Black)) { BrowserView(viewModel = browserController.browserViewModel) - QRCodeScanningView(this@BrowserActivity, qrCodeViewModel) + // QRCodeScanningView(this@BrowserActivity, qrCodeViewModel) LoadingView(browserController.showLoading) } } diff --git a/android/app/src/main/java/info/bagen/dwebbrowser/microService/browser/BrowserController.kt b/android/app/src/main/java/info/bagen/dwebbrowser/microService/browser/BrowserController.kt index 9808fea3f9..ba5fec1405 100644 --- a/android/app/src/main/java/info/bagen/dwebbrowser/microService/browser/BrowserController.kt +++ b/android/app/src/main/java/info/bagen/dwebbrowser/microService/browser/BrowserController.kt @@ -18,7 +18,7 @@ import info.bagen.dwebbrowser.microService.sys.dns.nativeFetch import info.bagen.dwebbrowser.microService.sys.jmm.JmmMetadata import info.bagen.dwebbrowser.network.HttpClient import info.bagen.dwebbrowser.network.base.byteBufferToString -import info.bagen.dwebbrowser.ui.browser.ios.BrowserViewModel +import info.bagen.dwebbrowser.ui.browser.BrowserViewModel import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import org.http4k.core.Uri diff --git a/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserListOfBook.kt b/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserListOfBook.kt new file mode 100644 index 0000000000..7779b6df3d --- /dev/null +++ b/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserListOfBook.kt @@ -0,0 +1,283 @@ +package info.bagen.dwebbrowser.ui.browser + +import androidx.compose.animation.* +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Close +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import info.bagen.dwebbrowser.R +import info.bagen.dwebbrowser.database.WebSiteDatabase +import info.bagen.dwebbrowser.database.WebSiteInfo +import info.bagen.dwebbrowser.database.WebSiteType +import info.bagen.dwebbrowser.microService.helper.ioAsyncExceptionHandler +import info.bagen.dwebbrowser.microService.helper.mainAsyncExceptionHandler +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +@Composable +fun BrowserListOfBook( + viewModel: BookViewModel = BookViewModel(), + modifier: Modifier = Modifier, + noFoundTip: (@Composable () -> Unit)? = null, + onOpenSetting: (() -> Unit)? = null, + onSearch: (String) -> Unit +) { + if (viewModel.bookList.isNotEmpty()) { + BookListContent(viewModel, modifier, onOpenSetting) { onSearch(it) } + return + } + + noFoundTip?.let { it() } + ?: Box(modifier = Modifier.fillMaxWidth()) { + Text( + text = "暂无数据", + modifier = Modifier + .align(Alignment.TopCenter) + .padding(top = 100.dp) + ) + } +} + +@OptIn(ExperimentalAnimationApi::class, ExperimentalMaterial3Api::class) +@Composable +private fun BookListContent( + viewModel: BookViewModel = BookViewModel(), + modifier: Modifier = Modifier, + onOpenSetting: (() -> Unit)? = null, + onSearch: (String) -> Unit +) { + var count by remember { mutableStateOf(0) } // 初始值为 0 + AnimatedContent( + targetState = count, + transitionSpec = { + if (targetState > initialState) { + // 数字变大时,进入的界面从右向左变深划入,退出的界面从右向左变浅划出 + slideInHorizontally { fullWidth -> fullWidth } + fadeIn() with slideOutHorizontally { fullWidth -> -fullWidth } + fadeOut() + } else { + // 数字变小时,进入的数字从左向右变深划入,退出的数字从左向右变浅划出 + slideInHorizontally { fullWidth -> -fullWidth } + fadeIn() with slideOutHorizontally { fullWidth -> fullWidth } + fadeOut() + } + } + ) { targetCount -> + if (targetCount == 0) { + LazyColumnView(viewModel, modifier, onSearch = { onSearch(it) }) { + viewModel.currentWebSiteInfo = it + count = 1 + onOpenSetting?.let { open -> open() } + } + } else { + BookManagerView(viewModel) { count = 0 } + } + } +} + +@Composable +private fun BookManagerView(viewModel: BookViewModel, onBack: () -> Unit) { + val focusRequester = FocusRequester() + val scope = rememberCoroutineScope() + LaunchedEffect(focusRequester) { + delay(500) + focusRequester.requestFocus() + } + val webSiteInfo = viewModel.currentWebSiteInfo + ?: WebSiteInfo(title = "无", url = "无", type = WebSiteType.Book) + val title = remember { mutableStateOf(webSiteInfo.title) } + val url = remember { mutableStateOf(webSiteInfo.url) } + + Column(modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { + Row( + modifier = Modifier + .fillMaxWidth() + .height(56.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = ImageVector.vectorResource(id = R.drawable.ic_more), + contentDescription = "Backup", + modifier = Modifier + .graphicsLayer(rotationZ = 90f) + .clickable { onBack() } + .size(48.dp) + .padding(12.dp) + ) + Text(text = "编辑书签", modifier = Modifier.weight(1f)) + Text( + text = "存储", modifier = Modifier + .padding(horizontal = 12.dp) + .clickable { + scope.launch(ioAsyncExceptionHandler) { + WebSiteDatabase.INSTANCE + .websiteDao() + .update( + WebSiteInfo( + webSiteInfo.id, + title.value, + url.value, + webSiteInfo.type, + webSiteInfo.timeMillis, + webSiteInfo.icon + ) + ) + onBack() + } + }, + color = MaterialTheme.colorScheme.primary + ) + } + + Column( + modifier = Modifier + .fillMaxWidth() + .padding(10.dp) + .height(100.dp) + .clip(RoundedCornerShape(8.dp)) + .background(MaterialTheme.colorScheme.background) + ) { + Row(verticalAlignment = Alignment.CenterVertically) { + webSiteInfo.icon?.let { bitmap -> + Icon( + bitmap = bitmap, + contentDescription = "icon", + modifier = Modifier + .padding(12.dp) + .size(48.dp) + ) + } ?: Icon( + ImageVector.vectorResource(R.drawable.ic_main_book), + contentDescription = "icon", + modifier = Modifier + .padding(12.dp) + .size(48.dp) + ) + + Column(modifier = Modifier.weight(1f)) { + CustomTextField( + value = title.value, + onValueChange = { title.value = it }, + modifier = Modifier + .height(48.dp) + .focusRequester(focusRequester), + trailingIcon = { + Icon( + Icons.Filled.Close, + contentDescription = "Close", + modifier = Modifier + .size(24.dp) + .clip(CircleShape) + .background(MaterialTheme.colorScheme.outlineVariant) + .padding(2.dp) + ) + } + ) + Divider() + CustomTextField( + value = url.value, + onValueChange = { url.value = it }, + modifier = Modifier.height(48.dp), + trailingIcon = { + Icon( + Icons.Filled.Close, + contentDescription = "Close", + modifier = Modifier + .size(24.dp) + .clip(CircleShape) + .background(MaterialTheme.colorScheme.outlineVariant) + .padding(2.dp) + ) + } + ) + } + } + } + + Button( + modifier = Modifier.fillMaxWidth().padding(horizontal = 50.dp), + onClick = { + scope.launch(ioAsyncExceptionHandler) { + WebSiteDatabase.INSTANCE.websiteDao().delete(webSiteInfo) + onBack() + } + }) { + Text(text = "删除") + } + } +} + +@Composable +private fun LazyColumnView( + viewModel: BookViewModel, + modifier: Modifier = Modifier, + onSearch: (String) -> Unit, + openSetting: (WebSiteInfo) -> Unit +) { + LazyColumn(modifier = modifier.background(MaterialTheme.colorScheme.background)) { + items(viewModel.bookList) { webSiteInfo -> + Column(modifier = Modifier.fillMaxWidth()) { + ListItem( + headlineContent = { + Text(text = webSiteInfo.title, maxLines = 1, overflow = TextOverflow.Ellipsis) + }, + modifier = Modifier.clickable { + onSearch(webSiteInfo.url) + }, + leadingContent = { + webSiteInfo.icon?.let { icon -> + Icon(bitmap = icon, contentDescription = webSiteInfo.title, Modifier.size(18.dp)) + } ?: Icon( + ImageVector.vectorResource(R.drawable.ic_main_book), + webSiteInfo.title, + Modifier.size(22.dp) + ) + }, + trailingContent = { + Icon( + ImageVector.vectorResource(id = R.drawable.ic_more), + contentDescription = "Expand", + modifier = Modifier + .clickable { openSetting(webSiteInfo) } + .size(22.dp) + .graphicsLayer(rotationZ = -90f) + ) + } + ) + } + Divider() + } + } +} + +class BookViewModel : ViewModel() { + val bookList: MutableList = mutableStateListOf() + var currentWebSiteInfo: WebSiteInfo? = null + + init { + viewModelScope.launch(mainAsyncExceptionHandler) { + WebSiteDatabase.INSTANCE.websiteDao().loadAllByTypeObserve(WebSiteType.Book) + .observeForever { + bookList.clear() + it.forEach { webSiteInfo -> + bookList.add(webSiteInfo) + } + } + } + } +} \ No newline at end of file diff --git a/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserListOfHistory.kt b/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserListOfHistory.kt new file mode 100644 index 0000000000..8820604b27 --- /dev/null +++ b/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserListOfHistory.kt @@ -0,0 +1,116 @@ +package info.bagen.dwebbrowser.ui.browser + +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.Divider +import androidx.compose.material3.ListItem +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import info.bagen.dwebbrowser.database.WebSiteDatabase +import info.bagen.dwebbrowser.database.WebSiteInfo +import info.bagen.dwebbrowser.database.WebSiteType +import info.bagen.dwebbrowser.microService.helper.mainAsyncExceptionHandler +import kotlinx.coroutines.launch +import java.time.LocalDate + +@OptIn(ExperimentalFoundationApi::class) +@Composable +fun BrowserListOfHistory( + viewModel: HistoryViewModel = HistoryViewModel(), + modifier: Modifier = Modifier, + noFoundTip: (@Composable () -> Unit)? = null, + onSearch: (String) -> Unit +) { + if (viewModel.historyList.isEmpty()) { + noFoundTip?.let { it() } + ?: Box(modifier = Modifier.fillMaxWidth()) { + Text( + text = "暂无数据", + modifier = Modifier + .align(Alignment.TopCenter) + .padding(top = 100.dp) + ) + } + return + } + + LazyColumn(modifier = modifier) { + viewModel.historyList.forEach { webSiteInfoList -> + stickyHeader { + Text( + text = webSiteInfoList.key, + modifier = Modifier + .fillMaxWidth() + .background(MaterialTheme.colorScheme.outlineVariant) + .padding(10.dp) + ) + } + items(webSiteInfoList.value) { webSiteInfo -> + ListItem( + headlineContent = { + Text(text = webSiteInfo.title, maxLines = 1, overflow = TextOverflow.Ellipsis) + }, + supportingContent = { + Text(text = webSiteInfo.url, maxLines = 1, overflow = TextOverflow.Ellipsis) + }, + modifier = Modifier.clickable { + onSearch(webSiteInfo.url) + } + ) + Divider() + } + } + } +} + +data class WebSiteInfoList( + val key: String, + val value: MutableList, +) + +class HistoryViewModel : ViewModel() { + val historyList: MutableList = mutableStateListOf() + + init { + viewModelScope.launch(mainAsyncExceptionHandler) { + WebSiteDatabase.INSTANCE.websiteDao().loadAllByTypeObserve(WebSiteType.History) + .observeForever { + if (historyList.isEmpty()) { // 如果是空的,属于第一次加载,整体填充 + var currentKey: String? = null + var list: MutableList = mutableListOf() + it.forEach { webSiteInfo -> + val stickyName = webSiteInfo.getStickyName() + if (currentKey != stickyName) { + currentKey?.let { key -> + historyList.add(0, WebSiteInfoList(key, list)) + } + currentKey = stickyName + list = mutableListOf() + } + list.add(0, webSiteInfo) + } + currentKey?.let { key -> historyList.add(0, WebSiteInfoList(key, list)) } + } else { + val today = LocalDate.now().toEpochDay() + val list: MutableList = mutableListOf() + it.filterIndexed { _, webSiteInfo -> webSiteInfo.timeMillis == today } + .forEach { webSiteInfo -> list.add(0, webSiteInfo) } + historyList.removeIf { webSiteInfoList -> webSiteInfoList.key == "今天" } + historyList.add(0, WebSiteInfoList("今天", list)) + } + } + } + } +} \ No newline at end of file diff --git a/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/ios/BrowserMain.kt b/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserMain.kt similarity index 99% rename from android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/ios/BrowserMain.kt rename to android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserMain.kt index e709679e34..3c1350a620 100644 --- a/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/ios/BrowserMain.kt +++ b/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserMain.kt @@ -1,4 +1,4 @@ -package info.bagen.dwebbrowser.ui.browser.ios +package info.bagen.dwebbrowser.ui.browser import androidx.compose.animation.core.* import androidx.compose.foundation.ExperimentalFoundationApi diff --git a/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/ios/BrowserPopup.kt b/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserPopup.kt similarity index 53% rename from android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/ios/BrowserPopup.kt rename to android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserPopup.kt index 878357a5af..c5f016ca84 100644 --- a/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/ios/BrowserPopup.kt +++ b/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserPopup.kt @@ -1,14 +1,14 @@ -package info.bagen.dwebbrowser.ui.browser.ios +package info.bagen.dwebbrowser.ui.browser import android.Manifest -import android.annotation.SuppressLint -import android.util.Log import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.DrawableRes import androidx.annotation.StringRes import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.* +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn @@ -17,10 +17,6 @@ import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.KeyboardActions -import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Done import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment @@ -33,7 +29,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.asImageBitmap -import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalConfiguration @@ -41,20 +36,18 @@ import androidx.compose.ui.res.imageResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.unit.* +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import info.bagen.dwebbrowser.R -import info.bagen.dwebbrowser.database.WebSiteDatabase -import info.bagen.dwebbrowser.database.WebSiteInfo -import info.bagen.dwebbrowser.database.WebSiteType -import info.bagen.dwebbrowser.datastore.WebsiteDB -import info.bagen.dwebbrowser.microService.helper.ioAsyncExceptionHandler -import info.bagen.dwebbrowser.ui.entity.* +import info.bagen.dwebbrowser.ui.entity.BrowserBaseView +import info.bagen.dwebbrowser.ui.entity.BrowserMainView +import info.bagen.dwebbrowser.ui.entity.BrowserWebView import info.bagen.dwebbrowser.ui.theme.DimenBottomBarHeight -import info.bagen.dwebbrowser.ui.view.ListItemDeleteView import info.bagen.dwebbrowser.util.BitmapUtil +import kotlinx.coroutines.delay import kotlinx.coroutines.launch private val screenHeight: Dp @@ -93,34 +86,17 @@ class TabItem( @Composable internal fun BrowserPopView(viewModel: BrowserViewModel) { var selectedTabIndex by remember { mutableStateOf(0) } - var popupViewState = PopupViewState.Options - val tabs = when (viewModel.uiState.currentBrowserBaseView.value) { - is BrowserWebView -> { - listOf( - TabItem(R.string.browser_nav_option, R.drawable.ic_main_option, PopupViewState.Options), - TabItem(R.string.browser_nav_book, R.drawable.ic_main_book, PopupViewState.BookList), - TabItem( - R.string.browser_nav_history, R.drawable.ic_main_history, PopupViewState.HistoryList - ), - ) - } - else -> { - listOf( - TabItem(R.string.browser_nav_book, R.drawable.ic_main_book, PopupViewState.BookList), - TabItem( - R.string.browser_nav_history, R.drawable.ic_main_history, PopupViewState.HistoryList - ), - ) - } - }.also { - popupViewState = - if (it.size > selectedTabIndex) it[selectedTabIndex].entry else it.first().entry - } + var popupViewState = remember { mutableStateOf(PopupViewState.Options) } + val tabs = listOf( + TabItem(R.string.browser_nav_option, R.drawable.ic_main_option, PopupViewState.Options), + TabItem(R.string.browser_nav_book, R.drawable.ic_main_book, PopupViewState.BookList), + TabItem(R.string.browser_nav_history, R.drawable.ic_main_history, PopupViewState.HistoryList), + ) LaunchedEffect(selectedTabIndex) { snapshotFlow { selectedTabIndex }.collect { if (it < tabs.size && it >= 0) { - popupViewState = tabs[it].entry + popupViewState.value = tabs[it].entry } } } @@ -146,14 +122,31 @@ internal fun BrowserPopView(viewModel: BrowserViewModel) { } // 显示具体内容部分,其中又可以分为三个部分类型,操作页,书签列表,历史列表 +@OptIn(ExperimentalMaterial3Api::class) @Composable private fun PopContentView( - popupViewState: PopupViewState, viewModel: BrowserViewModel + popupViewState: MutableState, viewModel: BrowserViewModel ) { - Box(modifier = Modifier.fillMaxSize()) { - when (popupViewState) { - PopupViewState.BookList -> PopContentBookListItem(viewModel) - PopupViewState.HistoryList -> PopContentHistoryListItem {} //PopContentHistoryListItem(viewModel) + val bookViewModel = remember { BookViewModel() } + val historyViewModel = remember { HistoryViewModel() } + val scope = rememberCoroutineScope() + + Box(modifier = Modifier.fillMaxSize().navigationBarsPadding()) { + when (popupViewState.value) { + PopupViewState.BookList -> BrowserListOfBook( + bookViewModel, + onOpenSetting = { + scope.launch { + delay(500) + viewModel.uiState.bottomSheetScaffoldState.bottomSheetState.expand() + } + } + ) { + viewModel.handleIntent(BrowserIntent.SearchWebView(it)) + } + PopupViewState.HistoryList -> BrowserListOfHistory(historyViewModel) { + viewModel.handleIntent(BrowserIntent.SearchWebView(it)) + } else -> PopContentOptionItem(viewModel) } } @@ -161,6 +154,7 @@ private fun PopContentView( @Composable private fun PopContentOptionItem(viewModel: BrowserViewModel) { + // 判断权限 val launcher = rememberLauncherForActivityResult(contract = ActivityResultContracts.RequestPermission(), onResult = { isGranted -> @@ -169,272 +163,63 @@ private fun PopContentOptionItem(viewModel: BrowserViewModel) { viewModel.handleIntent(BrowserIntent.ShareWebSiteInfo) } }) - LazyColumn { - item { - Spacer( - modifier = Modifier - .fillMaxWidth() - .height(10.dp) - ) - } + LazyColumn( + modifier = Modifier + .fillMaxSize() + .background(MaterialTheme.colorScheme.outlineVariant) + ) { // 分享和添加书签 item { - Box(modifier = Modifier - .fillMaxWidth() - .height(50.dp) - .padding(horizontal = 10.dp) - .clip(RoundedCornerShape(8.dp)) - .background(MaterialTheme.colorScheme.background) - .clickable { - viewModel.handleIntent(BrowserIntent.SaveBookWebSiteInfo) - }) { - Row(modifier = Modifier.fillMaxSize(), verticalAlignment = CenterVertically) { - Text( - text = "添加书签", modifier = Modifier - .weight(1f) - .padding(horizontal = 10.dp) - ) + ListItem( + modifier = Modifier + .padding(horizontal = 10.dp, vertical = 5.dp) + .clip(RoundedCornerShape(8.dp)) + .clickable { viewModel.handleIntent(BrowserIntent.SaveBookWebSiteInfo) }, + colors = ListItemDefaults.colors( + containerColor = MaterialTheme.colorScheme.background, + ), + headlineContent = { Text(text = "添加书签") }, + trailingContent = { Icon( imageVector = ImageVector.vectorResource(id = R.drawable.ic_main_book), contentDescription = null, - modifier = Modifier - .padding(15.dp) - .size(30.dp) + modifier = Modifier.size(32.dp) ) } - - } + ) } + item { - Spacer( + ListItem( modifier = Modifier - .fillMaxWidth() - .height(10.dp) - ) - Box(modifier = Modifier - .fillMaxWidth() - .height(50.dp) - .padding(horizontal = 10.dp) - .clip(RoundedCornerShape(8.dp)) - .background(MaterialTheme.colorScheme.background) - .clickable { - launcher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE) // 请求权限 - //viewModel.handleIntent(BrowserIntent.ShareWebSiteInfo) - }) { - Row(modifier = Modifier.fillMaxSize(), verticalAlignment = CenterVertically) { - Text( - text = "分享", modifier = Modifier - .weight(1f) - .padding(horizontal = 10.dp) - ) + .padding(horizontal = 10.dp, vertical = 5.dp) + .clip(RoundedCornerShape(8.dp)) + .clickable { launcher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE) /*请求权限*/ }, + colors = ListItemDefaults.colors(containerColor = MaterialTheme.colorScheme.background), + headlineContent = { Text(text = "分享") }, + trailingContent = { Icon( imageVector = ImageVector.vectorResource(id = R.drawable.ic_main_share), - contentDescription = null, - modifier = Modifier - .padding(15.dp) - .size(30.dp) + contentDescription = "Share", + modifier = Modifier.size(32.dp) ) } - } + ) } item { - Spacer( + ListItem( modifier = Modifier - .fillMaxWidth() - .height(10.dp) - ) - Box(modifier = Modifier - .fillMaxWidth() - .height(50.dp) - .padding(horizontal = 10.dp) - .clip(RoundedCornerShape(8.dp)) - .background(MaterialTheme.colorScheme.background) - .clickable { - launcher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE) // 请求权限 - //viewModel.handleIntent(BrowserIntent.ShareWebSiteInfo) - }) { - Row(modifier = Modifier.fillMaxSize(), verticalAlignment = CenterVertically) { - Text( - text = "无痕浏览", modifier = Modifier - .weight(1f) - .padding(horizontal = 10.dp) - ) + .padding(horizontal = 10.dp, vertical = 5.dp) + .clip(RoundedCornerShape(8.dp)), + colors = ListItemDefaults.colors(containerColor = MaterialTheme.colorScheme.background), + headlineContent = { Text(text = "无痕浏览") }, + trailingContent = { Switch( checked = viewModel.isNoTrace.value, - onCheckedChange = { viewModel.saveBrowserMode(it) }, - modifier = Modifier - .height(30.dp) - .padding(15.dp) + onCheckedChange = { viewModel.saveBrowserMode(it) } ) } - } - } - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun BoxScope.PopContentBookListItem(viewModel: BrowserViewModel) { - if (viewModel.uiState.bookWebsiteList.isEmpty()) { - Text( - text = "未发现书签列表", modifier = Modifier - .align(TopCenter) - .padding(top = screenHeight / 5) - ) - return - } - val scope = rememberCoroutineScope() - LazyColumn { - items(viewModel.uiState.bookWebsiteList.size) { index -> - val webSiteInfo = viewModel.uiState.bookWebsiteList[index] - ListItemDeleteView( - onClick = { - scope.launch { - viewModel.uiState.bottomSheetScaffoldState.bottomSheetState.hide() - viewModel.handleIntent(BrowserIntent.SearchWebView(webSiteInfo.url)) - } - }, - onDelete = { - viewModel.handleIntent(BrowserIntent.DeleteWebSiteList(ListType.Book, webSiteInfo, false)) - }, - enableExpand = true, - expandContent = { - ExpandTextFiled("书签名称", webSiteInfo.title) { - webSiteInfo.title = it - WebsiteDB.saveBookWebsiteInfo(webSiteInfo) - } - ExpandTextFiled("网址详情", webSiteInfo.url) { - webSiteInfo.url = it - WebsiteDB.saveBookWebsiteInfo(webSiteInfo) - } - } - ) { - Row( - modifier = Modifier - .fillMaxWidth() - .height(50.dp), verticalAlignment = CenterVertically - ) { - Icon( - imageVector = ImageVector.vectorResource(id = R.drawable.ic_main_book), - contentDescription = "Book", - modifier = Modifier - .padding(10.dp) - .size(30.dp) - ) - Text( - text = webSiteInfo.title, fontSize = 16.sp, maxLines = 1, modifier = Modifier.weight(1f) - ) - Icon( - imageVector = ImageVector.vectorResource(R.drawable.ic_more), - contentDescription = "More", - modifier = Modifier - .padding(10.dp) - .size(30.dp) - .graphicsLayer(rotationX = 90f) - ) - } - } - } - } -} - -@Composable -fun ExpandTextFiled( - label: String, - title: String, - modifier: Modifier = Modifier.fillMaxWidth(), - onValueChanged: (String) -> Unit -) { - var text by remember { mutableStateOf(title) } - OutlinedTextField( - value = text, - onValueChange = { text = it }, - modifier = modifier - .background(MaterialTheme.colorScheme.surface) - .padding(10.dp), - label = { Text(text = label) }, - singleLine = true, - maxLines = 1, - keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), - keyboardActions = KeyboardActions(onDone = { - if (text.isEmpty()) return@KeyboardActions - onValueChanged(text) - }), - trailingIcon = { - Icon(Icons.Default.Done, contentDescription = "Done") - } - ) -} - -@SuppressLint("RememberReturnType", "CoroutineCreationDuringComposition") -@OptIn(ExperimentalFoundationApi::class) -@Composable -private fun BoxScope.PopContentHistoryListItem(onSearch: (String) -> Unit) { - val historyWebsiteMap = remember { mutableStateMapOf>() } - val webSiteDao = WebSiteDatabase.INSTANCE.websiteDao() - val scope = rememberCoroutineScope() - scope.launch(ioAsyncExceptionHandler) { - webSiteDao.loadAllByType(WebSiteType.History).forEach { webSiteInfo -> - historyWebsiteMap.getOrPut(webSiteInfo.getStickyName()) { - mutableListOf() - }.also { list -> - list.add(webSiteInfo) - } - } - } - - if (historyWebsiteMap.isEmpty()) { - Text( - text = "未发现历史记录", modifier = Modifier - .align(TopCenter) - .padding(top = screenHeight / 5) - ) - return - } - Box { - LazyColumn { - historyWebsiteMap.toSortedMap { o1, o2 -> - if (o1 < o2) 1 else -1 - }.forEach { (key, value) -> - stickyHeader { - Text( - text = key, - modifier = Modifier - .fillMaxWidth() - .height(30.dp) - .background(MaterialTheme.colorScheme.outlineVariant) - .padding(horizontal = 10.dp, vertical = 6.dp) - ) - } - items(value.size) { index -> - val webSiteInfo = value[index] - ListItemDeleteView( - onClick = { onSearch(webSiteInfo.url) }, - onDelete = { webSiteDao.delete(webSiteInfo) } - ) { - Column( - modifier = Modifier - .fillMaxWidth() - .align(Alignment.CenterStart) - ) { - Text( - text = webSiteInfo.title, - fontSize = 16.sp, - maxLines = 1, - modifier = Modifier.height(25.dp), - color = MaterialTheme.colorScheme.onSurface - ) - Text( - text = webSiteInfo.url, - color = MaterialTheme.colorScheme.onSurfaceVariant, - fontSize = 12.sp, - maxLines = 1, - modifier = Modifier.height(20.dp) - ) - } - } - } - } + ) } } } diff --git a/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/ios/BrowserSearch.kt b/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserSearch.kt similarity index 88% rename from android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/ios/BrowserSearch.kt rename to android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserSearch.kt index a6bd80c778..dd68d3a500 100644 --- a/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/ios/BrowserSearch.kt +++ b/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserSearch.kt @@ -1,4 +1,4 @@ -package info.bagen.dwebbrowser.ui.browser.ios +package info.bagen.dwebbrowser.ui.browser import android.annotation.SuppressLint import android.view.KeyEvent @@ -17,6 +17,7 @@ import androidx.compose.material.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Close import androidx.compose.material3.Divider +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.* import androidx.compose.ui.Alignment @@ -25,12 +26,10 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester -import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.input.key.onKeyEvent import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.stringResource -import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.ImeAction @@ -38,7 +37,6 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.core.view.WindowInsetsCompat import coil.compose.AsyncImage import info.bagen.dwebbrowser.R import info.bagen.dwebbrowser.database.WebSiteDatabase @@ -49,46 +47,10 @@ import info.bagen.dwebbrowser.ui.entity.BrowserWebView import io.ktor.util.reflect.* import kotlinx.coroutines.delay -/** - * 提供给外部调用的 搜索界面,可以含有BrowserViewModel - */ -@Composable -fun BrowserSearchView(viewModel: BrowserViewModel) { - if (viewModel.uiState.showSearchView.value) { - val inputText = viewModel.uiState.inputText.value - val text = if (inputText.startsWith("file:///android_asset") || - inputText == stringResource(id = R.string.browser_search_hint) - ) { - "" - } else { - inputText - } - val imeShowed = remember { mutableStateOf(false) } - - LaunchedEffect(imeShowed) { - snapshotFlow { viewModel.uiState.currentInsets.value }.collect { - imeShowed.value = it.getInsets(WindowInsetsCompat.Type.ime()).bottom > 0 - } - } - - SearchView( - text = text, - imeShowed = imeShowed, - onClose = { - viewModel.uiState.showSearchView.value = false - }, - onSearch = { url -> // 第一个是搜索关键字,第二个是搜索地址 - viewModel.uiState.showSearchView.value = false - viewModel.saveLastKeyword(url) - viewModel.handleIntent(BrowserIntent.SearchWebView(url)) - }) - } -} - /** * 组件: 搜索组件 */ -@OptIn(ExperimentalComposeUiApi::class) +@OptIn(ExperimentalComposeUiApi::class, ExperimentalMaterial3Api::class) @Composable internal fun SearchView( text: String, @@ -113,10 +75,10 @@ internal fun SearchView( modifier = Modifier .fillMaxSize() .background(MaterialTheme.colorScheme.background.copy(0.5f)) - .clickable(indication = null, onClick = { + /*.clickable(indication = null, onClick = { focusManager.clearFocus() onClose() - }, interactionSource = remember { MutableInteractionSource() }) + }, interactionSource = remember { MutableInteractionSource() })*/ ) { Box( modifier = Modifier @@ -125,6 +87,16 @@ internal fun SearchView( .padding(bottom = dimenBottomHeight) ) { //HomePage() + Text( + text = "取消", + modifier = Modifier + .align(Alignment.TopEnd) + .padding(20.dp) + .clickable { onClose() }, + fontSize = 16.sp, + color = MaterialTheme.colorScheme.primary + ) + searchPreview?.let { it() } ?: SearchPreview( show = searchPreviewState, @@ -248,6 +220,7 @@ internal fun CustomTextField( } } +@OptIn(ExperimentalMaterial3Api::class) @SuppressLint("NewApi") @Composable internal fun SearchPreview( // 输入搜索内容后,显示的搜索信息 @@ -267,16 +240,24 @@ internal fun SearchPreview( // 输入搜索内容后,显示的搜索信息 Box( modifier = Modifier .fillMaxWidth() - .padding(vertical = 8.dp) + .padding(vertical = 20.dp) ) { - Text(text = "搜索", modifier = Modifier.align(Alignment.Center), fontSize = 16.sp) - Icon(imageVector = ImageVector.vectorResource(id = R.drawable.ic_main_close), + Text(text = "搜索", modifier = Modifier.align(Alignment.Center), fontSize = 20.sp) + /*Icon(imageVector = ImageVector.vectorResource(id = R.drawable.ic_main_close), contentDescription = "Close", modifier = Modifier .padding(end = 16.dp) .size(24.dp) .align(Alignment.CenterEnd) - .clickable { onClose() }) + .clickable { onClose() })*/ + Text( + text = "取消", + modifier = Modifier + .align(Alignment.TopEnd) + .clickable { onClose() }, + fontSize = 16.sp, + color = MaterialTheme.colorScheme.primary + ) } } item { // 搜索引擎 diff --git a/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/ios/BrowserView.kt b/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserView.kt similarity index 92% rename from android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/ios/BrowserView.kt rename to android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserView.kt index caca4afe98..de94484435 100644 --- a/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/ios/BrowserView.kt +++ b/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserView.kt @@ -1,7 +1,6 @@ -package info.bagen.dwebbrowser.ui.browser.ios +package info.bagen.dwebbrowser.ui.browser import android.annotation.SuppressLint -import android.net.Uri import androidx.activity.compose.BackHandler import androidx.annotation.DrawableRes import androidx.annotation.StringRes @@ -42,6 +41,7 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.core.view.WindowInsetsCompat import com.google.accompanist.web.LoadingState import info.bagen.dwebbrowser.R import info.bagen.dwebbrowser.ui.entity.BrowserBaseView @@ -90,6 +90,7 @@ fun BrowserView(viewModel: BrowserViewModel) { } } } + rememberModalBottomSheetState() BottomSheetScaffold(modifier = Modifier.navigationBarsPadding(), scaffoldState = viewModel.uiState.bottomSheetScaffoldState, @@ -155,10 +156,11 @@ private fun BrowserViewContent(viewModel: BrowserViewModel) { beyondBoundsPageCount = 5, userScrollEnabled = false ) { currentPage -> - when (val item = viewModel.uiState.browserViewList[currentPage]) { + BrowserViewContentWeb(viewModel, viewModel.uiState.browserViewList[currentPage]) + /*when (val item = viewModel.uiState.browserViewList[currentPage]) { is BrowserMainView -> BrowserViewContentMain(viewModel, item) is BrowserWebView -> BrowserViewContentWeb(viewModel, item) - } + }*/ } } } @@ -517,3 +519,39 @@ private fun SearchTextField( } } } + +/** + * 提供给外部调用的 搜索界面,可以含有BrowserViewModel + */ +@Composable +fun BrowserSearchView(viewModel: BrowserViewModel) { + if (viewModel.uiState.showSearchView.value) { + val inputText = viewModel.uiState.currentBrowserBaseView.value.state.lastLoadedUrl ?: "" + val text = if (inputText.startsWith("file:///android_asset") || + inputText == stringResource(id = R.string.browser_search_hint) + ) { + "" + } else { + inputText + } + val imeShowed = remember { mutableStateOf(false) } + + LaunchedEffect(imeShowed) { + snapshotFlow { viewModel.uiState.currentInsets.value }.collect { + imeShowed.value = it.getInsets(WindowInsetsCompat.Type.ime()).bottom > 0 + } + } + + SearchView( + text = text, + imeShowed = imeShowed, + onClose = { + viewModel.uiState.showSearchView.value = false + }, + onSearch = { url -> // 第一个是搜索关键字,第二个是搜索地址 + viewModel.uiState.showSearchView.value = false + viewModel.saveLastKeyword(url) + viewModel.handleIntent(BrowserIntent.SearchWebView(url)) + }) + } +} \ No newline at end of file diff --git a/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/ios/BrowserViewModel.kt b/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserViewModel.kt similarity index 95% rename from android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/ios/BrowserViewModel.kt rename to android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserViewModel.kt index dffba3ab22..0a9d8c44e1 100644 --- a/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/ios/BrowserViewModel.kt +++ b/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserViewModel.kt @@ -1,4 +1,4 @@ -package info.bagen.dwebbrowser.ui.browser.ios +package info.bagen.dwebbrowser.ui.browser import android.content.Intent import android.net.Uri @@ -12,8 +12,8 @@ import androidx.compose.foundation.pager.PagerState import androidx.compose.material3.* import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateListOf -import androidx.compose.runtime.mutableStateMapOf import androidx.compose.runtime.mutableStateOf +import androidx.compose.ui.graphics.asImageBitmap import androidx.core.view.WindowInsetsCompat import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -46,10 +46,10 @@ import java.util.concurrent.atomic.AtomicInteger data class BrowserUIState @OptIn( ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class ) constructor( - val browserViewList: MutableList = mutableStateListOf(), // 多浏览器列表 + val browserViewList: MutableList = mutableStateListOf(), // 多浏览器列表 // val historyWebsiteMap: MutableMap> = mutableStateMapOf(), // 历史列表 val bookWebsiteList: MutableList = mutableStateListOf(), // 书签列表 - val currentBrowserBaseView: MutableState, + val currentBrowserBaseView: MutableState, val pagerStateContent: PagerState = PagerState(0), // 用于表示展示内容 val pagerStateNavigator: PagerState = PagerState(0), // 用于表示下面搜索框等内容 val myInstallApp: MutableMap = JmmNMM.getAndUpdateJmmNmmApps(), // 系统安装的应用 @@ -248,7 +248,7 @@ class BrowserViewModel(val browserController: BrowserController) : ViewModel() { } is BrowserIntent.SaveHistoryWebSiteInfo -> { action.url?.let { - if (!isNoTrace.value) { // 无痕模式,不保存历史搜索记录 + if (!isNoTrace.value && !it.startsWith("file:///android_asset/")) { // 无痕模式,不保存历史搜索记录 WebSiteDatabase.INSTANCE.websiteDao().insert( WebSiteInfo(title = action.title ?: it, url = it, type = WebSiteType.History) ) @@ -258,8 +258,15 @@ class BrowserViewModel(val browserController: BrowserController) : ViewModel() { is BrowserIntent.SaveBookWebSiteInfo -> { uiState.currentBrowserBaseView.value.let { if (it is BrowserWebView) { - WebsiteDB.saveBookWebsiteInfo( - WebSiteInfo(title = it.state.pageTitle ?: "", url = it.state.lastLoadedUrl ?: "", type = WebSiteType.Book) + val url = it.state.lastLoadedUrl ?: "" + if (url.isEmpty() || url.startsWith("file:///android_asset/")) return@let + WebSiteDatabase.INSTANCE.websiteDao().insert( + WebSiteInfo( + title = it.state.pageTitle ?: "", + url = url, + type = WebSiteType.Book, + icon = it.state.pageIcon?.asImageBitmap() + ) ) handleIntent(BrowserIntent.ShowSnackbarMessage("添加书签成功")) } diff --git a/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/ios/BrowserWeb.kt b/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserWeb.kt similarity index 98% rename from android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/ios/BrowserWeb.kt rename to android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserWeb.kt index 868a654ffc..548d891f0d 100644 --- a/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/ios/BrowserWeb.kt +++ b/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/BrowserWeb.kt @@ -1,4 +1,4 @@ -package info.bagen.dwebbrowser.ui.browser.ios +package info.bagen.dwebbrowser.ui.browser import android.annotation.SuppressLint import android.view.MotionEvent diff --git a/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/android/BrowserView.kt b/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/android/BrowserView.kt deleted file mode 100644 index 3d6e6299dd..0000000000 --- a/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/android/BrowserView.kt +++ /dev/null @@ -1,42 +0,0 @@ -package info.bagen.dwebbrowser.ui.browser.android - -import androidx.compose.animation.core.tween -import androidx.compose.animation.slideInVertically -import androidx.compose.animation.slideOutVertically -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material.BottomSheetScaffold -import androidx.compose.material.ExperimentalMaterialApi -import androidx.compose.material.rememberBottomSheetScaffoldState -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier - -private val bottomEnterAnimator = slideInVertically(animationSpec = tween(300),//动画时长1s - initialOffsetY = { - it//初始位置在负一屏的位置,也就是说初始位置我们看不到,动画动起来的时候会从负一屏位置滑动到屏幕位置 - }) -private val bottomExitAnimator = slideOutVertically(animationSpec = tween(300),//动画时长1s - targetOffsetY = { - it//初始位置在负一屏的位置,也就是说初始位置我们看不到,动画动起来的时候会从负一屏位置滑动到屏幕位置 - }) - -@OptIn(ExperimentalMaterialApi::class) -@Composable -private fun BrowserView(viewModel: BrowserViewModel) { - val scaffoldState = rememberBottomSheetScaffoldState() - - BottomSheetScaffold( - sheetContent = { - Box(modifier = Modifier.fillMaxSize()) { - Text(text = "我是控制项", modifier = Modifier.align(Alignment.Center)) - } - }, - scaffoldState = scaffoldState - ) { - Box(modifier = Modifier.fillMaxSize()) { - Text(text = "我是内容", modifier = Modifier.align(Alignment.Center)) - } - } -} \ No newline at end of file diff --git a/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/android/BrowserViewModel.kt b/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/android/BrowserViewModel.kt deleted file mode 100644 index e192595f33..0000000000 --- a/android/app/src/main/java/info/bagen/dwebbrowser/ui/browser/android/BrowserViewModel.kt +++ /dev/null @@ -1,8 +0,0 @@ -package info.bagen.dwebbrowser.ui.browser.android - -import androidx.lifecycle.ViewModel -import info.bagen.dwebbrowser.microService.browser.BrowserController - -class BrowserViewModel(val browserController: BrowserController) : ViewModel() { - -} \ No newline at end of file