List cleanup on remove (#1069)

* 💄 Hide Add to List option on own profile

*  Remove Lists tab when last list is removed

*  Add listener to list delete on profile screen

*  Only show save changes in list modal when changes are made
zio/stable
Foysal Ahamed 2023-07-28 18:04:27 +02:00 committed by GitHub
parent 38d78e16bf
commit eec300d772
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 60 additions and 12 deletions

View File

@ -217,6 +217,8 @@ export class ListModel {
records.map(record => createDel(record.uri)),
),
})
this.rootStore.emitListDeleted(this.uri)
}
async subscribe() {

View File

@ -48,9 +48,24 @@ export class ListsListModel {
return this.hasLoaded && !this.hasContent
}
/**
* Removes posts from the feed upon deletion.
*/
onListDeleted(uri: string) {
this.lists = this.lists.filter(l => l.uri !== uri)
}
// public api
// =
/**
* Register any event listeners. Returns a cleanup function.
*/
registerListeners() {
const sub = this.rootStore.onListDeleted(this.onListDeleted.bind(this))
return () => sub.remove()
}
async refresh() {
return this.loadMore(true)
}

View File

@ -188,6 +188,14 @@ export class RootStoreModel {
DeviceEventEmitter.emit('post-deleted', uri)
}
// a list was deleted by the local user
onListDeleted(handler: (uri: string) => void): EmitterSubscription {
return DeviceEventEmitter.addListener('list-deleted', handler)
}
emitListDeleted(uri: string) {
DeviceEventEmitter.emit('list-deleted', uri)
}
// the session has started and been fully hydrated
onSessionLoaded(handler: () => void): EmitterSubscription {
return DeviceEventEmitter.addListener('session-loaded', handler)

View File

@ -87,7 +87,10 @@ export class ProfileUiModel {
}
get selectedView() {
return this.selectorItems[this.selectedViewIndex]
// If, for whatever reason, the selected view index is not available, default back to posts
// This can happen when the user was focused on a view but performed an action that caused
// the view to disappear (e.g. deleting the last list in their list of lists https://imgflip.com/i/7txu1y)
return this.selectorItems[this.selectedViewIndex] || Sections.Posts
}
get uiItems() {

View File

@ -20,6 +20,7 @@ import {sanitizeHandle} from 'lib/strings/handles'
import {s} from 'lib/styles'
import {usePalette} from 'lib/hooks/usePalette'
import {isDesktopWeb, isAndroid} from 'platform/detection'
import isEqual from 'lodash.isequal'
export const snapPoints = ['fullscreen']
@ -37,6 +38,9 @@ export const Component = observer(
const pal = usePalette('default')
const palPrimary = usePalette('primary')
const palInverted = usePalette('inverted')
const [originalSelections, setOriginalSelections] = React.useState<
string[]
>([])
const [selected, setSelected] = React.useState<string[]>([])
const listsList: ListsListModel = React.useMemo(
@ -51,7 +55,9 @@ export const Component = observer(
listsList.refresh()
memberships.fetch().then(
() => {
setSelected(memberships.memberships.map(m => m.value.list))
const ids = memberships.memberships.map(m => m.value.list)
setOriginalSelections(ids)
setSelected(ids)
},
err => {
store.log.error('Failed to fetch memberships', {err})
@ -156,6 +162,10 @@ export const Component = observer(
)
}, [onPressNewMuteList])
// Only show changes button if there are some items on the list to choose from AND user has made changes in selection
const canSaveChanges =
!listsList.isEmpty && !isEqual(selected, originalSelections)
return (
<View testID="listAddRemoveUserModal" style={s.hContentRegion}>
<Text style={[styles.title, pal.text]}>Add {displayName} to Lists</Text>
@ -178,16 +188,18 @@ export const Component = observer(
onAccessibilityEscape={onPressCancel}
label="Cancel"
/>
<Button
testID="saveBtn"
type="primary"
onPress={onPressSave}
style={styles.footerBtn}
accessibilityLabel="Save changes"
accessibilityHint=""
onAccessibilityEscape={onPressSave}
label="Save Changes"
/>
{canSaveChanges && (
<Button
testID="saveBtn"
type="primary"
onPress={onPressSave}
style={styles.footerBtn}
accessibilityLabel="Save changes"
accessibilityHint=""
onAccessibilityEscape={onPressSave}
label="Save Changes"
/>
)}
</View>
</View>
)

View File

@ -56,6 +56,13 @@ export const ProfileScreen = withAuthRequired(
setHasSetup(false)
}, [route.params.name])
// We don't need this to be reactive, so we can just register the listeners once
useEffect(() => {
const listCleanup = uiState.lists.registerListeners()
return () => listCleanup()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
useFocusEffect(
React.useCallback(() => {
const softResetSub = store.onScreenSoftReset(onSoftReset)
@ -126,6 +133,7 @@ export const ProfileScreen = withAuthRequired(
/>
)
}, [uiState, onRefresh, route.params.hideBackButton])
const Footer = React.useMemo(() => {
return uiState.showLoadingMoreFooter ? LoadingMoreFooter : undefined
}, [uiState.showLoadingMoreFooter])