[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_DISCONNECT = 'TIMELINE_DISCONNECT'; | ||||||
| 
 | 
 | ||||||
| export const TIMELINE_CONTEXT_UPDATE = 'CONTEXT_UPDATE'; |  | ||||||
| 
 |  | ||||||
| export function updateTimeline(timeline, status) { | export function updateTimeline(timeline, status) { | ||||||
|   return (dispatch, getState) => { |   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({ |     dispatch({ | ||||||
|       type: TIMELINE_UPDATE, |       type: TIMELINE_UPDATE, | ||||||
|       timeline, |       timeline, | ||||||
|       status, |       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 React from 'react'; | ||||||
| import { connect } from 'react-redux'; | import { connect } from 'react-redux'; | ||||||
| import PropTypes from 'prop-types'; | import PropTypes from 'prop-types'; | ||||||
|  | @ -57,13 +58,49 @@ const messages = defineMessages({ | ||||||
| const makeMapStateToProps = () => { | const makeMapStateToProps = () => { | ||||||
|   const getStatus = makeGetStatus(); |   const getStatus = makeGetStatus(); | ||||||
| 
 | 
 | ||||||
|   const mapStateToProps = (state, props) => ({ |   const mapStateToProps = (state, props) => { | ||||||
|     status: getStatus(state, { id: props.params.statusId }), |     const status = getStatus(state, { id: props.params.statusId }); | ||||||
|     settings: state.get('local_settings'), |     let ancestorsIds = Immutable.List(); | ||||||
|     ancestorsIds: state.getIn(['contexts', 'ancestors', props.params.statusId]), |     let descendantsIds = Immutable.List(); | ||||||
|     descendantsIds: state.getIn(['contexts', 'descendants', props.params.statusId]), | 
 | ||||||
|     askReplyConfirmation: state.getIn(['compose', 'text']).trim().length !== 0, |     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; |   return mapStateToProps; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -3,38 +3,62 @@ import { | ||||||
|   ACCOUNT_MUTE_SUCCESS, |   ACCOUNT_MUTE_SUCCESS, | ||||||
| } from 'flavours/glitch/actions/accounts'; | } from 'flavours/glitch/actions/accounts'; | ||||||
| import { CONTEXT_FETCH_SUCCESS } from 'flavours/glitch/actions/statuses'; | 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'; | import { Map as ImmutableMap, List as ImmutableList } from 'immutable'; | ||||||
| 
 | 
 | ||||||
| const initialState = ImmutableMap({ | const initialState = ImmutableMap({ | ||||||
|   ancestors: ImmutableMap(), |   inReplyTos: ImmutableMap(), | ||||||
|   descendants: ImmutableMap(), |   replies: ImmutableMap(), | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| const normalizeContext = (state, id, ancestors, descendants) => { | const normalizeContext = (immutableState, id, ancestors, descendants) => immutableState.withMutations(state => { | ||||||
|   const ancestorsIds   = ImmutableList(ancestors.map(ancestor => ancestor.id)); |   state.update('inReplyTos', immutableAncestors => immutableAncestors.withMutations(inReplyTos => { | ||||||
|   const descendantsIds = ImmutableList(descendants.map(descendant => descendant.id)); |     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 => { |           if (!siblings.includes(id)) { | ||||||
|     map.setIn(['ancestors', id], ancestorsIds); |             const index = siblings.findLastIndex(sibling => sibling.id < id); | ||||||
|     map.setIn(['descendants', id], descendantsIds); |             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 => { | const deleteFromContexts = (immutableState, ids) => immutableState.withMutations(state => { | ||||||
|   state.update('ancestors', immutableAncestors => immutableAncestors.withMutations(ancestors => { |   state.update('inReplyTos', immutableAncestors => immutableAncestors.withMutations(inReplyTos => { | ||||||
|     state.update('descendants', immutableDescendants => immutableDescendants.withMutations(descendants => { |     state.update('replies', immutableDescendants => immutableDescendants.withMutations(replies => { | ||||||
|       ids.forEach(id => { |       ids.forEach(id => { | ||||||
|         descendants.get(id, ImmutableList()).forEach(descendantId => { |         const inReplyToIdOfId = inReplyTos.get(id); | ||||||
|           ancestors.update(descendantId, ImmutableList(), list => list.filterNot(itemId => itemId === id)); |         const repliesOfId = replies.get(id); | ||||||
|         }); |         const siblings = replies.get(inReplyToIdOfId); | ||||||
| 
 | 
 | ||||||
|         ancestors.get(id, ImmutableList()).forEach(ancestorId => { |         if (siblings) { | ||||||
|           descendants.update(ancestorId, ImmutableList(), list => list.filterNot(itemId => itemId === id)); |           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); |   return deleteFromContexts(state, ownedStatusIds); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const updateContext = (state, status, references) => { | const updateContext = (state, status) => { | ||||||
|   return state.update('descendants', map => { |   if (status.in_reply_to_id) { | ||||||
|     references.forEach(parentId => { |     return state.withMutations(mutable => { | ||||||
|       map = map.update(parentId, ImmutableList(), list => { |       const replies = mutable.getIn(['replies', status.in_reply_to_id], ImmutableList()); | ||||||
|         if (list.includes(status.id)) { |  | ||||||
|           return list; |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         return list.push(status.id); |       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 map; |   return state; | ||||||
|   }); |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export default function contexts(state = initialState, action) { | export default function replies(state = initialState, action) { | ||||||
|   switch(action.type) { |   switch(action.type) { | ||||||
|   case ACCOUNT_BLOCK_SUCCESS: |   case ACCOUNT_BLOCK_SUCCESS: | ||||||
|   case ACCOUNT_MUTE_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); |     return normalizeContext(state, action.id, action.ancestors, action.descendants); | ||||||
|   case TIMELINE_DELETE: |   case TIMELINE_DELETE: | ||||||
|     return deleteFromContexts(state, [action.id]); |     return deleteFromContexts(state, [action.id]); | ||||||
|   case TIMELINE_CONTEXT_UPDATE: |   case TIMELINE_UPDATE: | ||||||
|     return updateContext(state, action.status, action.references); |     return updateContext(state, action.status); | ||||||
|   default: |   default: | ||||||
|     return state; |     return state; | ||||||
|   } |   } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue