Add a subscribe feed dialog

This commit is contained in:
Ash 2022-03-06 05:29:23 +08:00
parent f260175f25
commit 5fff554bba
5 changed files with 160 additions and 22 deletions

View File

@ -81,7 +81,8 @@ dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.5.0-alpha01"
implementation "androidx.compose.material3:material3:1.0.0-alpha04"
implementation "androidx.compose.material:material:1.2.0-alpha03"
implementation "androidx.compose.material3:material3:1.0.0-alpha05"
implementation "androidx.compose.material:material-icons-extended:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'

View File

@ -214,7 +214,7 @@ private fun ArticleItem(
if (isStarredFilter || articleWithFeed.article.isUnread) {
1f
} else {
0.75f
0.7f
}
)
) {

View File

@ -6,23 +6,30 @@ import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.*
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.material.TextField
import androidx.compose.material.TextFieldDefaults
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material.icons.rounded.Add
import androidx.compose.material.icons.rounded.ExpandMore
import androidx.compose.material.icons.rounded.Refresh
import androidx.compose.material.icons.rounded.*
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.*
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController
@ -40,8 +47,10 @@ import me.ash.reader.ui.page.home.HomeViewAction
import me.ash.reader.ui.page.home.HomeViewModel
import me.ash.reader.ui.util.collectAsStateValue
import me.ash.reader.ui.widget.*
import java.io.InputStream
@ExperimentalComposeUiApi
@ExperimentalAnimationApi
@ExperimentalMaterial3Api
@ExperimentalPagerApi
@ -55,17 +64,9 @@ fun FeedPage(
filter: Filter,
groupAndFeedOnClick: (currentGroup: Group?, currentFeed: Feed?) -> Unit = { _, _ -> },
) {
val context = LocalContext.current
val viewState = viewModel.viewState.collectAsStateValue()
val syncState = RssRepository.syncState.collectAsStateValue()
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) {
Log.i("RLog", "launcher: ${it}")
it?.let { uri ->
context.contentResolver.openInputStream(uri)?.let { inputStream ->
viewModel.dispatch(FeedViewAction.AddFromFile(inputStream))
}
}
}
var addFeedDialogVisible by remember { mutableStateOf(false) }
LaunchedEffect(homeViewModel.filterState) {
homeViewModel.filterState.collect { state ->
@ -88,6 +89,13 @@ fun FeedPage(
Box(
modifier.fillMaxSize()
) {
AddFeedDialog(
visible = addFeedDialogVisible,
hiddenFunction = { addFeedDialogVisible = false },
openInputStreamCallback = {
viewModel.dispatch(FeedViewAction.AddFromFile(it))
},
)
TopTitleBox(
title = viewState.account?.name ?: "未知账户",
description = if (syncState.isSyncing) {
@ -132,7 +140,7 @@ fun FeedPage(
)
}
IconButton(onClick = {
launcher.launch("*/*")
addFeedDialogVisible = true
}) {
Icon(
modifier = Modifier.size(26.dp),
@ -186,6 +194,107 @@ fun FeedPage(
}
}
@ExperimentalComposeUiApi
@Composable
private fun AddFeedDialog(
visible: Boolean,
hiddenFunction: () -> Unit,
openInputStreamCallback: (InputStream) -> Unit,
) {
val context = LocalContext.current
var inputString by remember { mutableStateOf("") }
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) {
it?.let { uri ->
context.contentResolver.openInputStream(uri)?.let { inputStream ->
openInputStreamCallback(inputStream)
}
}
}
val focusRequester = remember { FocusRequester() }
val localFocusManager = LocalFocusManager.current
val localSoftwareKeyboardController = LocalSoftwareKeyboardController.current
Dialog(
visible = visible,
onDismissRequest = hiddenFunction,
icon = {
Icon(
imageVector = Icons.Rounded.RssFeed,
contentDescription = "Subscribe",
)
},
title = { Text("订阅") },
text = {
Spacer(modifier = Modifier.height(10.dp))
TextField(
modifier = Modifier
.focusRequester(focusRequester)
.onFocusChanged { if(it.isFocused) localSoftwareKeyboardController?.hide() }
.focusable(),
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.Transparent,
cursorColor = MaterialTheme.colorScheme.onSurface,
textColor = MaterialTheme.colorScheme.onSurface,
focusedIndicatorColor = MaterialTheme.colorScheme.primary,
),
value = inputString,
onValueChange = {
inputString = it
},
placeholder = {
Text(
text = "订阅源或站点链接",
color = MaterialTheme.colorScheme.outline.copy(alpha = 0.7f)
)
},
singleLine = true,
trailingIcon = {
IconButton(onClick = {}) {
Icon(
imageVector = Icons.Rounded.ContentPaste,
contentDescription = "Paste",
tint = MaterialTheme.colorScheme.primary
)
}
},
keyboardActions = KeyboardActions(
onDone = {
hiddenFunction()
}
)
)
Spacer(modifier = Modifier.height(10.dp))
},
confirmButton = {
TextButton(
enabled = inputString.isNotEmpty(),
onClick = {
hiddenFunction()
}
) {
Text(
text = "搜索",
color = if (inputString.isNotEmpty()) {
Color.Unspecified
} else {
MaterialTheme.colorScheme.outline.copy(alpha = 0.7f)
}
)
}
},
dismissButton = {
TextButton(
onClick = {
launcher.launch("*/*")
hiddenFunction()
}
) {
Text("导入OPML文件")
}
},
)
}
@ExperimentalAnimationApi
@Composable
private fun ColumnScope.GroupList(
@ -230,9 +339,6 @@ private fun ColumnScope.FeedList(
feeds: List<Feed>,
onClick: (currentFeed: Feed?) -> Unit = {},
) {
// LaunchedEffect(feeds) {
//
// }
AnimatedVisibility(
visible = visible,
enter = fadeIn() + expandVertically(),

View File

@ -22,7 +22,7 @@ fun CanBeDisabledIconButton(
IconButton(
modifier = Modifier.alpha(
if (disabled) {
0.75f
0.7f
} else {
1f
}

View File

@ -0,0 +1,31 @@
package me.ash.reader.ui.widget
import androidx.compose.animation.*
import androidx.compose.material3.AlertDialog
import androidx.compose.runtime.Composable
@Composable
fun Dialog(
visible: Boolean,
onDismissRequest: () -> Unit = {},
icon: @Composable (() -> Unit)? = null,
title: @Composable (() -> Unit)? = null,
text: @Composable (() -> Unit)? = null,
confirmButton: @Composable () -> Unit,
dismissButton: @Composable (() -> Unit)? = null,
) {
AnimatedVisibility(
visible = visible,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically(),
) {
AlertDialog(
onDismissRequest = onDismissRequest,
icon = icon,
title = title,
text = text,
confirmButton = confirmButton,
dismissButton = dismissButton,
)
}
}