[Glitch] Introduce flat layout to contexts reducer
Port 4e718bbb25 to glitch-soc
			
			
This commit is contained in:
		
							parent
							
								
									546ce24295
								
							
						
					
					
						commit
						05d7c498ba
					
				
					 3 changed files with 103 additions and 63 deletions
				
			
		|  | @ -12,34 +12,13 @@ export const TIMELINE_SCROLL_TOP = 'TIMELINE_SCROLL_TOP'; | |||
| 
 | ||||
| export const TIMELINE_DISCONNECT = 'TIMELINE_DISCONNECT'; | ||||
| 
 | ||||
| export const TIMELINE_CONTEXT_UPDATE = 'CONTEXT_UPDATE'; | ||||
| 
 | ||||
| export function updateTimeline(timeline, status) { | ||||
|   return (dispatch, getState) => { | ||||
|     const parents = []; | ||||
| 
 | ||||
|     if (status.in_reply_to_id) { | ||||
|       let parent = getState().getIn(['statuses', status.in_reply_to_id]); | ||||
| 
 | ||||
|       while (parent && parent.get('in_reply_to_id')) { | ||||
|         parents.push(parent.get('id')); | ||||
|         parent = getState().getIn(['statuses', parent.get('in_reply_to_id')]); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     dispatch({ | ||||
|       type: TIMELINE_UPDATE, | ||||
|       timeline, | ||||
|       status, | ||||
|     }); | ||||
| 
 | ||||
|     if (parents.length > 0) { | ||||
|       dispatch({ | ||||
|         type: TIMELINE_CONTEXT_UPDATE, | ||||
|         status, | ||||
|         references: parents, | ||||
|       }); | ||||
|     } | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| import Immutable from 'immutable'; | ||||
| import React from 'react'; | ||||
| import { connect } from 'react-redux'; | ||||
| import PropTypes from 'prop-types'; | ||||
|  | @ -57,14 +58,50 @@ const messages = defineMessages({ | |||
| const makeMapStateToProps = () => { | ||||
|   const getStatus = makeGetStatus(); | ||||
| 
 | ||||
|   const mapStateToProps = (state, props) => ({ | ||||
|     status: getStatus(state, { id: props.params.statusId }), | ||||
|     settings: state.get('local_settings'), | ||||
|     ancestorsIds: state.getIn(['contexts', 'ancestors', props.params.statusId]), | ||||
|     descendantsIds: state.getIn(['contexts', 'descendants', props.params.statusId]), | ||||
|     askReplyConfirmation: state.getIn(['compose', 'text']).trim().length !== 0, | ||||
|   const mapStateToProps = (state, props) => { | ||||
|     const status = getStatus(state, { id: props.params.statusId }); | ||||
|     let ancestorsIds = Immutable.List(); | ||||
|     let descendantsIds = Immutable.List(); | ||||
| 
 | ||||
|     if (status) { | ||||
|       ancestorsIds = ancestorsIds.withMutations(mutable => { | ||||
|         function addAncestor(id) { | ||||
|           if (id) { | ||||
|             const inReplyTo = state.getIn(['contexts', 'inReplyTos', id]); | ||||
| 
 | ||||
|             mutable.unshift(id); | ||||
|             addAncestor(inReplyTo); | ||||
|           } | ||||
|         } | ||||
| 
 | ||||
|         addAncestor(status.get('in_reply_to_id')); | ||||
|       }); | ||||
| 
 | ||||
|       descendantsIds = descendantsIds.withMutations(mutable => { | ||||
|         function addDescendantOf(id) { | ||||
|           const replies = state.getIn(['contexts', 'replies', id]); | ||||
| 
 | ||||
|           if (replies) { | ||||
|             replies.forEach(reply => { | ||||
|               mutable.push(reply); | ||||
|               addDescendantOf(reply); | ||||
|             }); | ||||
|           } | ||||
|         } | ||||
| 
 | ||||
|         addDescendantOf(status.get('id')); | ||||
|       }); | ||||
|     } | ||||
| 
 | ||||
|     return { | ||||
|       status, | ||||
|       ancestorsIds, | ||||
|       descendantsIds, | ||||
|       settings: state.get('local_settings'), | ||||
|       askReplyConfirmation: state.getIn(['compose', 'text']).trim().length !== 0, | ||||
|     }; | ||||
|   }; | ||||
| 
 | ||||
|   return mapStateToProps; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,38 +3,62 @@ import { | |||
|   ACCOUNT_MUTE_SUCCESS, | ||||
| } from 'flavours/glitch/actions/accounts'; | ||||
| import { CONTEXT_FETCH_SUCCESS } from 'flavours/glitch/actions/statuses'; | ||||
| import { TIMELINE_DELETE, TIMELINE_CONTEXT_UPDATE } from 'flavours/glitch/actions/timelines'; | ||||
| import { TIMELINE_DELETE, TIMELINE_UPDATE } from 'flavours/glitch/actions/timelines'; | ||||
| import { Map as ImmutableMap, List as ImmutableList } from 'immutable'; | ||||
| 
 | ||||
| const initialState = ImmutableMap({ | ||||
|   ancestors: ImmutableMap(), | ||||
|   descendants: ImmutableMap(), | ||||
|   inReplyTos: ImmutableMap(), | ||||
|   replies: ImmutableMap(), | ||||
| }); | ||||
| 
 | ||||
| const normalizeContext = (state, id, ancestors, descendants) => { | ||||
|   const ancestorsIds   = ImmutableList(ancestors.map(ancestor => ancestor.id)); | ||||
|   const descendantsIds = ImmutableList(descendants.map(descendant => descendant.id)); | ||||
| const normalizeContext = (immutableState, id, ancestors, descendants) => immutableState.withMutations(state => { | ||||
|   state.update('inReplyTos', immutableAncestors => immutableAncestors.withMutations(inReplyTos => { | ||||
|     state.update('replies', immutableDescendants => immutableDescendants.withMutations(replies => { | ||||
|       function addReply({ id, in_reply_to_id }) { | ||||
|         if (in_reply_to_id) { | ||||
|           const siblings = replies.get(in_reply_to_id, ImmutableList()); | ||||
| 
 | ||||
|   return state.withMutations(map => { | ||||
|     map.setIn(['ancestors', id], ancestorsIds); | ||||
|     map.setIn(['descendants', id], descendantsIds); | ||||
|   }); | ||||
| }; | ||||
|           if (!siblings.includes(id)) { | ||||
|             const index = siblings.findLastIndex(sibling => sibling.id < id); | ||||
|             replies.set(in_reply_to_id, siblings.insert(index + 1, id)); | ||||
|           } | ||||
| 
 | ||||
|           inReplyTos.set(id, in_reply_to_id); | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       if (ancestors[0]) { | ||||
|         addReply({ id, in_reply_to_id: ancestors[0].id }); | ||||
|       } | ||||
| 
 | ||||
|       if (descendants[0]) { | ||||
|         addReply({ id: descendants[0].id, in_reply_to_id: id }); | ||||
|       } | ||||
| 
 | ||||
|       [ancestors, descendants].forEach(statuses => statuses.forEach(addReply)); | ||||
|     })); | ||||
|   })); | ||||
| }); | ||||
| 
 | ||||
| const deleteFromContexts = (immutableState, ids) => immutableState.withMutations(state => { | ||||
|   state.update('ancestors', immutableAncestors => immutableAncestors.withMutations(ancestors => { | ||||
|     state.update('descendants', immutableDescendants => immutableDescendants.withMutations(descendants => { | ||||
|   state.update('inReplyTos', immutableAncestors => immutableAncestors.withMutations(inReplyTos => { | ||||
|     state.update('replies', immutableDescendants => immutableDescendants.withMutations(replies => { | ||||
|       ids.forEach(id => { | ||||
|         descendants.get(id, ImmutableList()).forEach(descendantId => { | ||||
|           ancestors.update(descendantId, ImmutableList(), list => list.filterNot(itemId => itemId === id)); | ||||
|         }); | ||||
|         const inReplyToIdOfId = inReplyTos.get(id); | ||||
|         const repliesOfId = replies.get(id); | ||||
|         const siblings = replies.get(inReplyToIdOfId); | ||||
| 
 | ||||
|         ancestors.get(id, ImmutableList()).forEach(ancestorId => { | ||||
|           descendants.update(ancestorId, ImmutableList(), list => list.filterNot(itemId => itemId === id)); | ||||
|         }); | ||||
|         if (siblings) { | ||||
|           replies.set(inReplyToIdOfId, siblings.filterNot(sibling => sibling === id)); | ||||
|         } | ||||
| 
 | ||||
|         descendants.delete(id); | ||||
|         ancestors.delete(id); | ||||
| 
 | ||||
|         if (repliesOfId) { | ||||
|           repliesOfId.forEach(reply => inReplyTos.delete(reply)); | ||||
|         } | ||||
| 
 | ||||
|         inReplyTos.delete(id); | ||||
|         replies.delete(id); | ||||
|       }); | ||||
|     })); | ||||
|   })); | ||||
|  | @ -47,23 +71,23 @@ const filterContexts = (state, relationship, statuses) => { | |||
|   return deleteFromContexts(state, ownedStatusIds); | ||||
| }; | ||||
| 
 | ||||
| const updateContext = (state, status, references) => { | ||||
|   return state.update('descendants', map => { | ||||
|     references.forEach(parentId => { | ||||
|       map = map.update(parentId, ImmutableList(), list => { | ||||
|         if (list.includes(status.id)) { | ||||
|           return list; | ||||
| const updateContext = (state, status) => { | ||||
|   if (status.in_reply_to_id) { | ||||
|     return state.withMutations(mutable => { | ||||
|       const replies = mutable.getIn(['replies', status.in_reply_to_id], ImmutableList()); | ||||
| 
 | ||||
|       mutable.setIn(['inReplyTos', status.id], status.in_reply_to_id); | ||||
| 
 | ||||
|       if (!replies.includes(status.id)) { | ||||
|         mutable.setIn(['replies', status.id], replies.push(status.id)); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|         return list.push(status.id); | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     return map; | ||||
|   }); | ||||
|   return state; | ||||
| }; | ||||
| 
 | ||||
| export default function contexts(state = initialState, action) { | ||||
| export default function replies(state = initialState, action) { | ||||
|   switch(action.type) { | ||||
|   case ACCOUNT_BLOCK_SUCCESS: | ||||
|   case ACCOUNT_MUTE_SUCCESS: | ||||
|  | @ -72,8 +96,8 @@ export default function contexts(state = initialState, action) { | |||
|     return normalizeContext(state, action.id, action.ancestors, action.descendants); | ||||
|   case TIMELINE_DELETE: | ||||
|     return deleteFromContexts(state, [action.id]); | ||||
|   case TIMELINE_CONTEXT_UPDATE: | ||||
|     return updateContext(state, action.status, action.references); | ||||
|   case TIMELINE_UPDATE: | ||||
|     return updateContext(state, action.status); | ||||
|   default: | ||||
|     return state; | ||||
|   } | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue