2024-02-06 09:14:22 +00:00
import QtQuick 2.15
import StatusQ 0.1
import AppLayouts . Communities . controls 1.0
import SortFilterProxyModel 0.2
import StatusQ . Core . Utils 0.1 as StatusQUtils
import utils 1.0
/// Helper component for editing channel permissions
/// This component will create the necessary temporary models to be used until the changes are saved
QtObject {
id: root
// Input properties
// Model containing all channels
required property var channelsModel
// Model containing all permissions for the current community
required property var permissionsModel
// Channel ID
required property string channelId
// Channel name
required property string name
// Channel color
required property string color
// Channel emoji
required property string emoji
// Specify whether the channel is being edited or created
required property bool newChannelMode
// Output properties
// The edited channel permissions model
readonly property alias channelPermissionsModel: d . channelPermissionsModel
// Live model of channels contaning the temporarely edited channel
readonly property alias liveChannelsModel: d . liveChannelsModel
readonly property alias dirtyPermissions: d . channelPermissionsModel . dirty
// Input functions
// Function creating a new permission based on the given arguments
function appendPermission ( holdings , channels , permissionType , isPrivate ) {
d . appendPermission ( holdings , channels , permissionType , isPrivate )
}
// Function editing a permission based on the given arguments
function editPermission ( key , permissionType , holdings , channels , isPrivate ) {
d . editPermission ( key , permissionType , holdings , channels , isPrivate )
}
// Function removing a permission by index
function removePermission ( index ) {
2024-02-06 09:31:36 +00:00
return channelPermissionsModel . remove ( index , 1 ) ;
2024-02-06 09:14:22 +00:00
}
// Output functions
// Function returning the list of added permissions
// The returned list contains the permissions that were added since the last reset
// Each item contains a map of role names and data value pairs as defined in the model
function getAddedPermissions ( ) {
return d . flattenPermissions ( channelPermissionsModel . getInsertedItems ( ) )
}
// Function returning the list of removed permissions
// The returned list contains the permissions that were removed since the last reset
// This list contains the permissions that are no longer available in the root.channelPermissionsModel, but are still available in the root.permissionsModel
// Each item contains a map of role names and data value pairs as defined in the model
function getRemovedPermissions ( ) {
return d . flattenPermissions ( channelPermissionsModel . getRemovedItems ( ) )
}
// Function returning the list of edited permissions
// The returned list contains the permissions that were edited since the last reset
// Each item contains a map of role names and data value pairs as defined in the model
function getEditedPermissions ( ) {
return d . flattenPermissions ( channelPermissionsModel . getEditedItems ( ) )
}
// This function resets the temporary models
// The dirtyPermissions property will be set to false
function reset ( ) {
d . reset ( )
}
//internals
readonly property QtObject d: QtObject {
id: d
signal resetDone ( )
function reset ( ) {
channelPermissionsModel . revert ( ) ;
liveChannelsModel . revert ( ) ;
d . resetDone ( ) ;
}
function appendPermission ( holdings , channels , permissionType , isPrivate ) {
var permissionsModelData = {
id: Utils.uuid ( ) ,
key: Utils . uuid ( ) ,
holdingsListModel: d . newHoldingsModel ( holdings ) ,
channelsListModel: d . newChannelsModel ( channels ) ,
"permissionType" : permissionType ,
"isPrivate" : isPrivate
} ;
d . channelPermissionsModel . append ( permissionsModelData )
}
function editPermission ( key , permissionType , holdings , channels , isPrivate ) {
const index = StatusQUtils . ModelUtils . indexOf ( d . channelPermissionsModel , "key" , key )
if ( index === - 1 )
return
const permissionItem = d . channelPermissionsModel . get ( index )
d . channelPermissionsModel . set ( index , {
"permissionType" : permissionType ,
"channelsListModel" : d . newEditedChannelsModel ( channels , permissionItem . channelsListModel ) ,
"holdingsListModel" : d . newEditedHoldingsModel ( holdings , permissionItem . holdingsListModel ) ,
"isPrivate" : isPrivate
} )
}
// Creates a new channel model to be used in the permissions model
// Expected roles: "key"
function newChannelsModel ( channelsArray ) {
var channelsModel = selfDestroyingModel . createObject ( d . channelPermissionsModel ) ;
for ( var i = 0 ; i < channelsArray . length ; i ++ ) {
channelsModel . append ( { key: channelsArray [ i ] . key } )
}
return channelsModel ;
}
// Creates a new writable channel model on top of base model to be used in the permissions model
function newEditedChannelsModel ( channelsArray , baseModel ) {
var channelsModel = selfDestroyingWritableModel . createObject ( d . channelPermissionsModel , { sourceModel: baseModel } ) ;
const count = channelsModel . rowCount ( )
for ( var i = 0 ; i < count ; i ++ ) {
const ok = channelsModel . remove ( 0 )
console . assert ( ok
, "Failed to remove channel" )
}
for ( var i = 0 ; i < channelsArray . length ; i ++ ) {
const ok = channelsModel . append ( {
key: channelsArray [ i ] . key ,
} )
console . assert ( ok , "Failed to append channel" ) ;
}
return channelsModel ;
}
// Creates a new holdings model to be used in the permissions model
function newHoldingsModel ( holdingsArray , sourceModel ) {
var holdingsModel = selfDestroyingModel . createObject ( d . channelPermissionsModel ) ;
for ( var i = 0 ; i < holdingsArray . length ; i ++ ) {
holdingsModel . append ( holdingsArray [ i ] ) ;
}
return holdingsModel ;
}
function newEditedHoldingsModel ( holdingsArray , baseModel ) {
var holdingsModel = selfDestroyingWritableModel . createObject ( d . channelPermissionsModel , { sourceModel: baseModel } ) ;
const count = holdingsModel . rowCount ( )
for ( var i = 0 ; i < count ; i ++ ) {
const ok = holdingsModel . remove ( 0 )
console . assert ( ok , "Failed to remove holding" )
}
for ( var i = 0 ; i < holdingsArray . length ; i ++ ) {
const ok = holdingsModel . append ( holdingsArray [ i ] )
console . assert ( ok , "Failed to append holding" ) ;
}
return holdingsModel ;
}
function flattenPermissions ( permissionsItems ) {
for ( var i = 0 ; i < permissionsItems . length ; i ++ ) {
permissionsItems [ i ] . holdingsListModel = StatusQUtils . ModelUtils . modelToArray ( permissionsItems [ i ] . holdingsListModel )
permissionsItems [ i ] . channelsListModel = StatusQUtils . ModelUtils . modelToArray ( permissionsItems [ i ] . channelsListModel )
}
return permissionsItems
}
property Connections chatIdConnections: Connections {
target: root
enabled: root . newChannelMode
property string previousChannelId: ""
Component.onCompleted: previousChannelId = root . channelId
/// go through all the channels and replace the old channel id with the new one
function onChannelIdChanged ( ) {
if ( previousChannelId === root . channelId )
return ;
if ( previousChannelId == "" ) {
previousChannelId = root . channelId ;
return ;
}
for ( var i = 0 ; i < liveChannelsModel . rowCount ( ) ; i ++ ) {
if ( liveChannelsModel . get ( i ) . itemId === previousChannelId ) {
liveChannelsModel . set ( i , { itemId: root . channelId } )
break ;
}
}
for ( var i = 0 ; i < channelPermissionsModel . rowCount ( ) ; i ++ ) {
const currentItem = channelPermissionsModel . get ( i )
const channelsListModel = currentItem . channelsListModel
for ( var j = 0 ; j < channelsListModel . rowCount ( ) ; j ++ ) {
if ( channelsListModel . get ( j ) . key === previousChannelId ) {
channelsListModel . set ( j , { key: root . channelId } )
break ;
}
}
}
previousChannelId = root . channelId ;
}
}
2024-05-03 10:25:59 +00:00
readonly property var filteredPermissionsModel: SortFilterProxyModel {
sourceModel: root . permissionsModel
filters: [
FastExpressionFilter {
function filterPredicate ( id , permissionType ) {
2024-09-27 17:28:27 +00:00
return ! PermissionTypes . isCommunityPermission ( permissionType )
2024-05-03 10:25:59 +00:00
}
expression: {
return filterPredicate ( model . id , model . permissionType )
}
expectedRoles: [ "id" , "permissionType" ]
}
]
}
2024-02-06 09:14:22 +00:00
// Channel permissions model containing the temporarely edited permissions
property WritableProxyModel channelPermissionsModel: WritableProxyModel {
2024-05-03 15:51:25 +00:00
sourceModel: d . filteredPermissionsModel
2024-02-06 09:14:22 +00:00
}
// Channels model containing the temporarely edited channel
property WritableProxyModel liveChannelsModel: WritableProxyModel {
id: newChannelModel
function updateCurrentChannelProperty ( nameAndValue ) {
const index = StatusQUtils . ModelUtils . indexOf ( newChannelModel , "itemId" , root . channelId )
if ( index !== - 1 ) {
newChannelModel . set ( index , nameAndValue )
}
}
Component.onCompleted: {
if ( ! root . newChannelMode )
return ;
console . assert ( newChannelModel . append ( {
itemId: root . channelId ,
name: root . name ,
emoji: root . emoji ,
color: root . color
} ) , "Failed to add channel to channelsModel" )
}
property Connections channelConnections: Connections {
target: root
function onColorChanged ( ) {
newChannelModel . updateCurrentChannelProperty ( { "color" : root . color } )
}
function onNameChanged ( ) {
newChannelModel . updateCurrentChannelProperty ( { "name" : root . name } )
}
function onEmojiChanged ( ) {
newChannelModel . updateCurrentChannelProperty ( { "emoji" : root . emoji } )
}
}
sourceModel: root . channelsModel
}
// Used for dynamic model creation using Component.createObject
property Component selfDestroyingModel: Component {
ListModel {
id: model
Component.onCompleted: d . resetDone . connect ( model . destroy )
Component.onDestruction: d . resetDone . disconnect ( model . destroy )
}
}
property Component selfDestroyingWritableModel: Component {
WritableProxyModel {
id: model
Component.onCompleted: d . resetDone . connect ( model . destroy )
Component.onDestruction: d . resetDone . disconnect ( model . destroy )
}
}
}
}