Skip to content

Commit 8c99d0f

Browse files
committed
Make Shift+Esc mark all columns as done instead of read
1 parent 558eb60 commit 8c99d0f

8 files changed

Lines changed: 120 additions & 29 deletions

File tree

packages/components/src/components/AppKeyboardShortcuts.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export const AppKeyboardShortcuts = React.memo(() => {
8585
useMultiKeyPressCallback(
8686
['Shift', 'Escape'],
8787
useCallback(() => {
88-
dispatch(actions.markEverythingAsReadWithConfirmation())
88+
dispatch(actions.clearAllColumnsWithConfirmation())
8989
}, []),
9090
)
9191

packages/components/src/components/common/Button.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ThemeColors } from '@devhub/core'
2-
import React, { useCallback, useRef, useState } from 'react'
2+
import React, { useCallback, useEffect, useRef, useState } from 'react'
33
import { StyleSheet, View, ViewProps } from 'react-native'
44

55
import { useHover } from '../../hooks/use-hover'
@@ -20,6 +20,7 @@ import {
2020
import { ThemedView } from '../themed/ThemedView'
2121

2222
export type ButtonProps = Omit<ThemedTouchableHighlightProps, 'children'> & {
23+
autoFocus?: boolean
2324
children:
2425
| React.ReactNode
2526
| ((colors: { foregroundThemeColor: keyof ThemeColors }) => React.ReactNode)
@@ -54,6 +55,7 @@ export const defaultButtonSize = 40 * scaleFactor
5455

5556
export function Button(props: ButtonProps) {
5657
const {
58+
autoFocus,
5759
children,
5860
colors,
5961
contentContainerStyle,
@@ -140,6 +142,11 @@ export function Button(props: ButtonProps) {
140142
),
141143
)
142144

145+
useEffect(() => {
146+
if (autoFocus && innerTouchableRef.current)
147+
innerTouchableRef.current.focus()
148+
}, [autoFocus])
149+
143150
return (
144151
<ThemedView
145152
ref={containerViewRef}
@@ -161,6 +168,7 @@ export function Button(props: ButtonProps) {
161168
<>
162169
<ThemedTouchableHighlight
163170
ref={innerTouchableRef}
171+
accessibilityRole="button"
164172
backgroundColor={undefined}
165173
underlayColor={backgroundHoverThemeColor}
166174
{...otherProps}

packages/components/src/components/context/DialogContext.tsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -327,18 +327,22 @@ const DialogView = React.memo(
327327
return 'primary'
328328
})()
329329
: 'neutral'
330+
331+
const disabled =
332+
(!button.onPress && button.style !== 'cancel') ||
333+
(buttonType === 'primary' &&
334+
renderInput &&
335+
!inputValue)
336+
330337
return (
331338
<Fragment
332339
key={`dialog-button-${button.text || index}`}
333340
>
334341
<Button
335-
disabled={
336-
(!button.onPress &&
337-
button.style !== 'cancel') ||
338-
(buttonType === 'primary' &&
339-
renderInput &&
340-
!inputValue)
342+
autoFocus={
343+
buttonType === 'primary' && !disabled
341344
}
345+
disabled={disabled}
342346
onPress={() => {
343347
if (button.onPress) {
344348
button.onPress(inputValue || '')

packages/components/src/components/modals/KeyboardShortcutsModal.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ export const keyboardShortcutsById = {
5050
keys: ['Shift R'],
5151
description: 'Mark column as read/unread',
5252
},
53-
markEverythingAsRead: {
53+
markEverythingAsDone: {
5454
keys: ['Shift Esc'],
55-
description: 'Mark everything as read, from all columns',
55+
description: 'Mark all columns as done',
5656
},
5757
toggleSave: { keys: ['S'], description: 'Save/unsave item' },
5858
toggleDoneAllFromColumn: {
@@ -94,7 +94,7 @@ export const keyboardShortcuts = [
9494
keyboardShortcutsById.selectNextColumn,
9595
keyboardShortcutsById.toggleRead,
9696
keyboardShortcutsById.toggleReadAllFromColumn,
97-
keyboardShortcutsById.markEverythingAsRead,
97+
keyboardShortcutsById.markEverythingAsDone,
9898
keyboardShortcutsById.toggleSave,
9999
keyboardShortcutsById.toggleDoneAllFromColumn,
100100
keyboardShortcutsById.moveColumnLeft,

packages/components/src/redux/actions/columns.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,16 @@ export function setColumnClearedAtFilter(payload: {
216216
return createAction('SET_COLUMN_CLEARED_AT_FILTER', payload)
217217
}
218218

219+
export function clearAllColumnsWithConfirmation(
220+
payload: { clearedAt?: string | null } = {},
221+
) {
222+
return createAction('CLEAR_ALL_COLUMNS_WITH_CONFIRMATION', payload)
223+
}
224+
225+
export function clearAllColumns(payload: { clearedAt?: string | null } = {}) {
226+
return createAction('CLEAR_ALL_COLUMNS', payload)
227+
}
228+
219229
export function changeIssueNumberFilter(payload: {
220230
columnId: string
221231
issueNumber: number

packages/components/src/redux/reducers/columns.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -694,13 +694,37 @@ export const columnsReducer: Reducer<State> = (
694694
const column = draft.byId[action.payload.columnId]
695695
if (!column) return
696696

697+
const now = new Date().toISOString()
698+
697699
column.filters = column.filters || {}
698700
column.filters.clearedAt =
699701
action.payload.clearedAt === null
700702
? undefined
701-
: action.payload.clearedAt || new Date().toISOString()
703+
: action.payload.clearedAt || now
702704

703-
draft.updatedAt = new Date().toISOString()
705+
draft.updatedAt = now
706+
})
707+
708+
case 'CLEAR_ALL_COLUMNS':
709+
return immer(state, draft => {
710+
if (!draft.byId) return
711+
712+
draft.allIds = draft.allIds || []
713+
714+
const now = new Date().toISOString()
715+
716+
draft.allIds.forEach(columnId => {
717+
const column = draft.byId![columnId]
718+
if (!column) return
719+
720+
column.filters = column.filters || {}
721+
column.filters.clearedAt =
722+
action.payload.clearedAt === null
723+
? undefined
724+
: action.payload.clearedAt || now
725+
726+
draft.updatedAt = now
727+
})
704728
})
705729

706730
case 'CHANGE_ISSUE_NUMBER_FILTER':

packages/components/src/redux/sagas/columns.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
import { AppState, InteractionManager } from 'react-native'
2-
import { all, call, put, select, takeLatest } from 'redux-saga/effects'
2+
import {
3+
all,
4+
call,
5+
put,
6+
select,
7+
takeEvery,
8+
takeLatest,
9+
} from 'redux-saga/effects'
310

411
import {
512
ActivityColumnSubscriptionCreation,
@@ -214,13 +221,12 @@ function* onDeleteColumn(
214221
}
215222
}
216223

217-
function* onSetClearedAt(
224+
function* onClearColumnOrColumns(
218225
action: ExtractActionFromActionCreator<
219-
typeof actions.setColumnClearedAtFilter
226+
typeof actions.setColumnClearedAtFilter | typeof actions.clearAllColumns
220227
>,
221228
) {
222-
if (!action.payload.clearedAt) return
223-
229+
if (action.payload.clearedAt === null) return
224230
yield put(actions.cleanupArchivedItems())
225231
}
226232

@@ -405,10 +411,13 @@ function* onColumnSubscriptionFilterChange(
405411

406412
export function* columnsSagas() {
407413
yield all([
408-
yield takeLatest('ADD_COLUMN_AND_SUBSCRIPTIONS', onAddColumn),
409-
yield takeLatest('MOVE_COLUMN', onMoveColumn),
410-
yield takeLatest('DELETE_COLUMN', onDeleteColumn),
411-
yield takeLatest('SET_COLUMN_CLEARED_AT_FILTER', onSetClearedAt),
414+
yield takeEvery('ADD_COLUMN_AND_SUBSCRIPTIONS', onAddColumn),
415+
yield takeEvery('MOVE_COLUMN', onMoveColumn),
416+
yield takeEvery('DELETE_COLUMN', onDeleteColumn),
417+
yield takeLatest(
418+
['SET_COLUMN_CLEARED_AT_FILTER', 'CLEAR_ALL_COLUMNS'],
419+
onClearColumnOrColumns,
420+
),
412421
yield takeLatest(
413422
[
414423
'CLEAR_COLUMN_FILTERS',

packages/components/src/redux/sagas/subscriptions.ts

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -794,14 +794,19 @@ function* onMarkEverythingAsReadWithConfirmation(
794794
>,
795795
) {
796796
const confirmed = yield new Promise(resolve => {
797-
confirm('Mark all columns as read?', 'This cannot be undone.', {
798-
confirmCallback() {
799-
resolve(true)
800-
},
801-
cancelCallback() {
802-
resolve(false)
797+
confirm(
798+
'Mark all as read?',
799+
'All your GitHub notifications and all columns will be marked as read. ' +
800+
'This cannot be undone.',
801+
{
802+
confirmCallback() {
803+
resolve(true)
804+
},
805+
cancelCallback() {
806+
resolve(false)
807+
},
803808
},
804-
})
809+
)
805810
})
806811

807812
if (!confirmed) return
@@ -810,6 +815,33 @@ function* onMarkEverythingAsReadWithConfirmation(
810815
yield _markAllGitHubNotificationsAsReadOrUnread({ unread: false })
811816
}
812817

818+
function* onClearAllColumnsWithConfirmation(
819+
_action: ExtractActionFromActionCreator<
820+
typeof actions.clearAllColumnsWithConfirmation
821+
>,
822+
) {
823+
const confirmed = yield new Promise(resolve => {
824+
confirm(
825+
'Clear all columns?',
826+
'All columns will become empty. ' +
827+
'Your GitHub notifications will be marked as read. ' +
828+
'This cannot be undone.',
829+
{
830+
confirmCallback() {
831+
resolve(true)
832+
},
833+
cancelCallback() {
834+
resolve(false)
835+
},
836+
},
837+
)
838+
})
839+
840+
if (!confirmed) return
841+
842+
yield put(actions.clearAllColumns())
843+
}
844+
813845
export function* subscriptionsSagas() {
814846
yield all([
815847
yield fork(init),
@@ -836,6 +868,10 @@ export function* subscriptionsSagas() {
836868
'MARK_EVERYTHING_AS_READ_WITH_CONFIRMATION',
837869
onMarkEverythingAsReadWithConfirmation,
838870
),
871+
yield takeLatest(
872+
'CLEAR_ALL_COLUMNS_WITH_CONFIRMATION',
873+
onClearAllColumnsWithConfirmation,
874+
),
839875
])
840876
}
841877

0 commit comments

Comments
 (0)