Add move all feeds to target Group feature
This commit is contained in:
		
							parent
							
								
									4f7ebb7958
								
							
						
					
					
						commit
						890ee337a4
					
				@ -5,6 +5,19 @@ import me.ash.reader.data.entity.Feed
 | 
			
		||||
 | 
			
		||||
@Dao
 | 
			
		||||
interface FeedDao {
 | 
			
		||||
    @Query(
 | 
			
		||||
        """
 | 
			
		||||
        UPDATE feed SET groupId = :targetGroupId
 | 
			
		||||
        WHERE groupId = :groupId
 | 
			
		||||
        AND accountId = :accountId
 | 
			
		||||
        """
 | 
			
		||||
    )
 | 
			
		||||
    suspend fun updateTargetGroupIdByGroupId(
 | 
			
		||||
        accountId: Int,
 | 
			
		||||
        groupId: String,
 | 
			
		||||
        targetGroupId: String
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    @Query(
 | 
			
		||||
        """
 | 
			
		||||
        UPDATE feed SET isFullContent = :isFullContent
 | 
			
		||||
 | 
			
		||||
@ -154,6 +154,10 @@ abstract class AbstractRssRepository constructor(
 | 
			
		||||
    suspend fun groupAllowNotification(group: Group, isNotification: Boolean) {
 | 
			
		||||
        feedDao.updateIsNotificationByGroupId(context.currentAccountId, group.id, isNotification)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    suspend fun groupMoveToTargetGroup(group: Group, targetGroup: Group) {
 | 
			
		||||
        feedDao.updateTargetGroupIdByGroupId(context.currentAccountId, group.id, targetGroup.id)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@HiltWorker
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,83 @@
 | 
			
		||||
package me.ash.reader.ui.page.home.drawer.group
 | 
			
		||||
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import androidx.compose.material.icons.Icons
 | 
			
		||||
import androidx.compose.material.icons.outlined.DriveFileMove
 | 
			
		||||
import androidx.compose.material3.Icon
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.material3.TextButton
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.rememberCoroutineScope
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.platform.LocalContext
 | 
			
		||||
import androidx.compose.ui.res.stringResource
 | 
			
		||||
import androidx.hilt.navigation.compose.hiltViewModel
 | 
			
		||||
import com.google.accompanist.pager.ExperimentalPagerApi
 | 
			
		||||
import me.ash.reader.R
 | 
			
		||||
import me.ash.reader.ui.component.Dialog
 | 
			
		||||
import me.ash.reader.ui.ext.collectAsStateValue
 | 
			
		||||
 | 
			
		||||
@OptIn(ExperimentalPagerApi::class)
 | 
			
		||||
@Composable
 | 
			
		||||
fun AllMoveToGroupDialog(
 | 
			
		||||
    modifier: Modifier = Modifier,
 | 
			
		||||
    groupName: String,
 | 
			
		||||
    viewModel: GroupOptionViewModel = hiltViewModel(),
 | 
			
		||||
) {
 | 
			
		||||
    val context = LocalContext.current
 | 
			
		||||
    val viewState = viewModel.viewState.collectAsStateValue()
 | 
			
		||||
    val scope = rememberCoroutineScope()
 | 
			
		||||
    val toastString =
 | 
			
		||||
        stringResource(R.string.all_move_to_group_toast, viewState.targetGroup?.name ?: "")
 | 
			
		||||
 | 
			
		||||
    Dialog(
 | 
			
		||||
        visible = viewState.allMoveToGroupDialogVisible,
 | 
			
		||||
        onDismissRequest = {
 | 
			
		||||
            viewModel.dispatch(GroupOptionViewAction.HideAllMoveToGroupDialog)
 | 
			
		||||
        },
 | 
			
		||||
        icon = {
 | 
			
		||||
            Icon(
 | 
			
		||||
                imageVector = Icons.Outlined.DriveFileMove,
 | 
			
		||||
                contentDescription = stringResource(R.string.move_to_group),
 | 
			
		||||
            )
 | 
			
		||||
        },
 | 
			
		||||
        title = {
 | 
			
		||||
            Text(text = stringResource(R.string.move_to_group))
 | 
			
		||||
        },
 | 
			
		||||
        text = {
 | 
			
		||||
            Text(
 | 
			
		||||
                text = stringResource(
 | 
			
		||||
                    R.string.all_move_to_group_tip,
 | 
			
		||||
                    groupName,
 | 
			
		||||
                    viewState.targetGroup?.name ?: "",
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
        },
 | 
			
		||||
        confirmButton = {
 | 
			
		||||
            TextButton(
 | 
			
		||||
                onClick = {
 | 
			
		||||
                    viewModel.dispatch(GroupOptionViewAction.AllMoveToGroup {
 | 
			
		||||
                        viewModel.dispatch(GroupOptionViewAction.HideAllMoveToGroupDialog)
 | 
			
		||||
                        viewModel.dispatch(GroupOptionViewAction.Hide(scope))
 | 
			
		||||
                        Toast.makeText(context, toastString, Toast.LENGTH_SHORT).show()
 | 
			
		||||
                    })
 | 
			
		||||
                }
 | 
			
		||||
            ) {
 | 
			
		||||
                Text(
 | 
			
		||||
                    text = stringResource(R.string.confirm),
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        dismissButton = {
 | 
			
		||||
            TextButton(
 | 
			
		||||
                onClick = {
 | 
			
		||||
                    viewModel.dispatch(GroupOptionViewAction.HideAllMoveToGroupDialog)
 | 
			
		||||
                }
 | 
			
		||||
            ) {
 | 
			
		||||
                Text(
 | 
			
		||||
                    text = stringResource(R.string.cancel),
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
@ -2,6 +2,8 @@ package me.ash.reader.ui.page.home.drawer.group
 | 
			
		||||
 | 
			
		||||
import androidx.compose.animation.animateContentSize
 | 
			
		||||
import androidx.compose.foundation.layout.*
 | 
			
		||||
import androidx.compose.foundation.lazy.LazyRow
 | 
			
		||||
import androidx.compose.foundation.lazy.items
 | 
			
		||||
import androidx.compose.foundation.rememberScrollState
 | 
			
		||||
import androidx.compose.foundation.verticalScroll
 | 
			
		||||
import androidx.compose.material.ExperimentalMaterialApi
 | 
			
		||||
@ -135,12 +137,48 @@ fun GroupOptionDrawer(
 | 
			
		||||
                    }
 | 
			
		||||
                    Spacer(modifier = Modifier.height(26.dp))
 | 
			
		||||
 | 
			
		||||
//                    AddToGroup(
 | 
			
		||||
//                        groups = groups,
 | 
			
		||||
//                        selectedGroupId = selectedGroupId,
 | 
			
		||||
//                        onGroupClick = onGroupClick,
 | 
			
		||||
//                        onAddNewGroup = onAddNewGroup,
 | 
			
		||||
//                    )
 | 
			
		||||
                    Subtitle(text = stringResource(R.string.move_to_group))
 | 
			
		||||
                    Spacer(modifier = Modifier.height(10.dp))
 | 
			
		||||
 | 
			
		||||
                    if (viewState.groups.size > 6) {
 | 
			
		||||
                        LazyRow {
 | 
			
		||||
                            items(viewState.groups) {
 | 
			
		||||
                                if (it.id != group?.id) {
 | 
			
		||||
                                    SelectionChip(
 | 
			
		||||
                                        modifier = Modifier.animateContentSize(),
 | 
			
		||||
                                        content = it.name,
 | 
			
		||||
                                        selected = false,
 | 
			
		||||
                                    ) {
 | 
			
		||||
                                        GroupOptionViewModel.dispatch(
 | 
			
		||||
                                            GroupOptionViewAction.ShowAllMoveToGroupDialog(it)
 | 
			
		||||
                                        )
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                                Spacer(modifier = Modifier.width(10.dp))
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        FlowRow(
 | 
			
		||||
                            mainAxisAlignment = MainAxisAlignment.Start,
 | 
			
		||||
                            crossAxisSpacing = 10.dp,
 | 
			
		||||
                            mainAxisSpacing = 10.dp,
 | 
			
		||||
                        ) {
 | 
			
		||||
                            viewState.groups.forEach {
 | 
			
		||||
                                if (it.id != group?.id) {
 | 
			
		||||
                                    SelectionChip(
 | 
			
		||||
                                        modifier = Modifier.animateContentSize(),
 | 
			
		||||
                                        content = it.name,
 | 
			
		||||
                                        selected = false,
 | 
			
		||||
                                    ) {
 | 
			
		||||
                                        GroupOptionViewModel.dispatch(
 | 
			
		||||
                                            GroupOptionViewAction.ShowAllMoveToGroupDialog(it)
 | 
			
		||||
                                        )
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    Spacer(modifier = Modifier.height(6.dp))
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@ -152,4 +190,5 @@ fun GroupOptionDrawer(
 | 
			
		||||
    DeleteGroupDialog(groupName = group?.name ?: "")
 | 
			
		||||
    AllAllowNotificationDialog(groupName = group?.name ?: "")
 | 
			
		||||
    AllParseFullContentDialog(groupName = group?.name ?: "")
 | 
			
		||||
}
 | 
			
		||||
    AllMoveToGroupDialog(groupName = group?.name ?: "")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -49,18 +49,27 @@ class GroupOptionViewModel @Inject constructor(
 | 
			
		||||
            is GroupOptionViewAction.ShowDeleteDialog -> changeDeleteDialogVisible(true)
 | 
			
		||||
            is GroupOptionViewAction.HideDeleteDialog -> changeDeleteDialogVisible(false)
 | 
			
		||||
            is GroupOptionViewAction.Delete -> delete(action.callback)
 | 
			
		||||
 | 
			
		||||
            is GroupOptionViewAction.ShowAllAllowNotificationDialog ->
 | 
			
		||||
                changeAllAllowNotificationDialogVisible(true)
 | 
			
		||||
            is GroupOptionViewAction.HideAllAllowNotificationDialog ->
 | 
			
		||||
                changeAllAllowNotificationDialogVisible(false)
 | 
			
		||||
            is GroupOptionViewAction.AllAllowNotification ->
 | 
			
		||||
                allAllowNotification(action.isNotification, action.callback)
 | 
			
		||||
 | 
			
		||||
            is GroupOptionViewAction.ShowAllParseFullContentDialog ->
 | 
			
		||||
                changeAllParseFullContentDialogVisible(true)
 | 
			
		||||
            is GroupOptionViewAction.HideAllParseFullContentDialog ->
 | 
			
		||||
                changeAllParseFullContentDialogVisible(false)
 | 
			
		||||
            is GroupOptionViewAction.AllParseFullContent ->
 | 
			
		||||
                allParseFullContent(action.isFullContent, action.callback)
 | 
			
		||||
 | 
			
		||||
            is GroupOptionViewAction.ShowAllMoveToGroupDialog ->
 | 
			
		||||
                changeAllMoveToGroupDialogVisible(action.targetGroup, true)
 | 
			
		||||
            is GroupOptionViewAction.HideAllMoveToGroupDialog ->
 | 
			
		||||
                changeAllMoveToGroupDialogVisible(visible = false)
 | 
			
		||||
            is GroupOptionViewAction.AllMoveToGroup ->
 | 
			
		||||
                allMoveToGroup(action.callback)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -142,15 +151,39 @@ class GroupOptionViewModel @Inject constructor(
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun allMoveToGroup(callback: () -> Unit) {
 | 
			
		||||
        _viewState.value.group?.let { group ->
 | 
			
		||||
            _viewState.value.targetGroup?.let { targetGroup ->
 | 
			
		||||
                viewModelScope.launch(Dispatchers.IO) {
 | 
			
		||||
                    rssRepository.get().groupMoveToTargetGroup(group, targetGroup)
 | 
			
		||||
                    withContext(Dispatchers.Main) {
 | 
			
		||||
                        callback()
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun changeAllMoveToGroupDialogVisible(targetGroup: Group? = null, visible: Boolean) {
 | 
			
		||||
        _viewState.update {
 | 
			
		||||
            it.copy(
 | 
			
		||||
                targetGroup = if (visible) targetGroup else null,
 | 
			
		||||
                allMoveToGroupDialogVisible = visible,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@OptIn(ExperimentalMaterialApi::class)
 | 
			
		||||
data class GroupOptionViewState(
 | 
			
		||||
    var drawerState: ModalBottomSheetState = ModalBottomSheetState(ModalBottomSheetValue.Hidden),
 | 
			
		||||
    val group: Group? = null,
 | 
			
		||||
    val targetGroup: Group? = null,
 | 
			
		||||
    val groups: List<Group> = emptyList(),
 | 
			
		||||
    val allAllowNotificationDialogVisible: Boolean = false,
 | 
			
		||||
    val allParseFullContentDialogVisible: Boolean = false,
 | 
			
		||||
    val allMoveToGroupDialogVisible: Boolean = false,
 | 
			
		||||
    val deleteDialogVisible: Boolean = false,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@ -186,4 +219,14 @@ sealed class GroupOptionViewAction {
 | 
			
		||||
 | 
			
		||||
    object ShowAllAllowNotificationDialog : GroupOptionViewAction()
 | 
			
		||||
    object HideAllAllowNotificationDialog : GroupOptionViewAction()
 | 
			
		||||
 | 
			
		||||
    data class AllMoveToGroup(
 | 
			
		||||
        val callback: () -> Unit = {}
 | 
			
		||||
    ) : GroupOptionViewAction()
 | 
			
		||||
 | 
			
		||||
    data class ShowAllMoveToGroupDialog(
 | 
			
		||||
        val targetGroup: Group
 | 
			
		||||
    ) : GroupOptionViewAction()
 | 
			
		||||
 | 
			
		||||
    object HideAllMoveToGroupDialog : GroupOptionViewAction()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -39,6 +39,9 @@
 | 
			
		||||
    <string name="all_parse_full_content_toast">全文解析 \"%1$s\" 分组中的文章</string>
 | 
			
		||||
    <string name="all_deny_parse_full_content_toast">不再全文解析 \"%1$s\" 分组中的文章</string>
 | 
			
		||||
    <string name="add_to_group">添加到组</string>
 | 
			
		||||
    <string name="move_to_group">移动到组</string>
 | 
			
		||||
    <string name="all_move_to_group_tip">将 \"%1$s\" 分组中的所有订阅源移动至 \"%2$s\" 分组。</string>
 | 
			
		||||
    <string name="all_move_to_group_toast">已全部移动至 \"%1$s\" 分组</string>
 | 
			
		||||
    <string name="create_new_group">新建分组</string>
 | 
			
		||||
    <string name="name">名称</string>
 | 
			
		||||
    <string name="open_with">打开 %1$s</string>
 | 
			
		||||
 | 
			
		||||
@ -39,6 +39,9 @@
 | 
			
		||||
    <string name="all_parse_full_content_toast">Full content parsing of all articles in the \"%1$s\" group</string>
 | 
			
		||||
    <string name="all_deny_parse_full_content_toast">No more full content parsing of all articles in the \"%1$s\" group</string>
 | 
			
		||||
    <string name="add_to_group">Add to Group</string>
 | 
			
		||||
    <string name="move_to_group">Move to Group</string>
 | 
			
		||||
    <string name="all_move_to_group_tip">Move all feeds in the \"%1$s\" group to the \"%2$s\" group.</string>
 | 
			
		||||
    <string name="all_move_to_group_toast">Moved all to \"%1$s\" group</string>
 | 
			
		||||
    <string name="create_new_group">Create New Group</string>
 | 
			
		||||
    <string name="name">Name</string>
 | 
			
		||||
    <string name="open_with">Open %1$s</string>
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user