1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-11-27 08:21:03 +02:00

Mobile: Accessibility: Improve screen reader accessibility of the tag list (#11420)

This commit is contained in:
Henry Heino 2024-11-20 03:37:09 -08:00 committed by GitHub
parent 5dcbf4ce4a
commit c9608cf4a1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 103 additions and 115 deletions

View File

@ -766,6 +766,7 @@ packages/app-mobile/components/screens/UpgradeSyncTargetScreen.js
packages/app-mobile/components/screens/dropbox-login.js
packages/app-mobile/components/screens/encryption-config.js
packages/app-mobile/components/screens/status.js
packages/app-mobile/components/screens/tags.js
packages/app-mobile/components/side-menu-content.js
packages/app-mobile/components/testing/TestProviderStack.js
packages/app-mobile/components/voiceTyping/VoiceTypingDialog.js

1
.gitignore vendored
View File

@ -742,6 +742,7 @@ packages/app-mobile/components/screens/UpgradeSyncTargetScreen.js
packages/app-mobile/components/screens/dropbox-login.js
packages/app-mobile/components/screens/encryption-config.js
packages/app-mobile/components/screens/status.js
packages/app-mobile/components/screens/tags.js
packages/app-mobile/components/side-menu-content.js
packages/app-mobile/components/testing/TestProviderStack.js
packages/app-mobile/components/voiceTyping/VoiceTypingDialog.js

View File

@ -1,114 +0,0 @@
const React = require('react');
const { View, Text, FlatList, StyleSheet, TouchableOpacity } = require('react-native');
const { connect } = require('react-redux');
const Tag = require('@joplin/lib/models/Tag').default;
const { themeStyle } = require('../global-style');
const { ScreenHeader } = require('../ScreenHeader');
const { _ } = require('@joplin/lib/locale');
const { BaseScreenComponent } = require('../base-screen');
class TagsScreenComponent extends BaseScreenComponent {
static navigationOptions() {
return { header: null };
}
constructor() {
super();
this.state = {
tags: [],
};
this.tagList_renderItem = this.tagList_renderItem.bind(this);
this.tagList_keyExtractor = this.tagList_keyExtractor.bind(this);
this.tagItem_press = this.tagItem_press.bind(this);
}
styles() {
if (this.styles_) return this.styles_;
const theme = themeStyle(this.props.themeId);
this.styles_ = StyleSheet.create({
listItem: {
flexDirection: 'row',
borderBottomWidth: 1,
borderBottomColor: theme.dividerColor,
alignItems: 'flex-start',
paddingLeft: theme.marginLeft,
paddingRight: theme.marginRight,
paddingTop: theme.itemMarginTop,
paddingBottom: theme.itemMarginBottom,
},
listItemText: {
flex: 1,
color: theme.color,
fontSize: theme.fontSize,
},
});
return this.styles_;
}
tagItem_press(event) {
this.props.dispatch({ type: 'SIDE_MENU_CLOSE' });
this.props.dispatch({
type: 'NAV_GO',
routeName: 'Notes',
tagId: event.id,
});
}
tagList_renderItem(event) {
const tag = event.item;
return (
<TouchableOpacity
onPress={() => {
this.tagItem_press({ id: tag.id });
}}
>
<View style={this.styles().listItem}>
<Text style={this.styles().listItemText}>{tag.title}</Text>
</View>
</TouchableOpacity>
);
}
tagList_keyExtractor(item) {
return item.id;
}
async componentDidMount() {
const tags = await Tag.allWithNotes();
tags.sort((a, b) => {
return a.title.toLowerCase() < b.title.toLowerCase() ? -1 : +1;
});
this.setState({ tags: tags });
}
render() {
const theme = themeStyle(this.props.themeId);
const rootStyle = {
flex: 1,
backgroundColor: theme.backgroundColor,
};
return (
<View style={rootStyle}>
<ScreenHeader title={_('Tags')} parentComponent={this} showSearchButton={false} />
<FlatList style={{ flex: 1 }} data={this.state.tags} renderItem={this.tagList_renderItem} keyExtractor={this.tagList_keyExtractor} />
</View>
);
}
}
const TagsScreen = connect(state => {
return {
themeId: state.settings.theme,
};
})(TagsScreenComponent);
module.exports = { TagsScreen };

View File

@ -0,0 +1,100 @@
import * as React from 'react';
import { View, Text, FlatList, StyleSheet, TouchableOpacity } from 'react-native';
import { connect } from 'react-redux';
import Tag from '@joplin/lib/models/Tag';
import { themeStyle } from '../global-style';
import { ScreenHeader } from '../ScreenHeader';
import { _ } from '@joplin/lib/locale';
import { AppState } from '../../utils/types';
import { TagEntity } from '@joplin/lib/services/database/types';
import { useCallback, useMemo, useState } from 'react';
import { Dispatch } from 'redux';
import useAsyncEffect from '@joplin/lib/hooks/useAsyncEffect';
interface Props {
dispatch: Dispatch;
themeId: number;
}
const useStyles = (themeId: number) => {
return useMemo(() => {
const theme = themeStyle(themeId);
return StyleSheet.create({
listItem: {
flexDirection: 'row',
borderBottomWidth: 1,
borderBottomColor: theme.dividerColor,
alignItems: 'flex-start',
paddingLeft: theme.marginLeft,
paddingRight: theme.marginRight,
paddingTop: theme.itemMarginTop,
paddingBottom: theme.itemMarginBottom,
},
listItemText: {
flex: 1,
color: theme.color,
fontSize: theme.fontSize,
},
rootStyle: theme.rootStyle,
});
}, [themeId]);
};
const TagsScreenComponent: React.FC<Props> = props => {
const [tags, setTags] = useState<TagEntity[]>([]);
const styles = useStyles(props.themeId);
type TagItemPressEvent = { id: string };
useAsyncEffect(async () => {
const tags = await Tag.allWithNotes();
tags.sort((a, b) => {
return a.title.toLowerCase() < b.title.toLowerCase() ? -1 : +1;
});
setTags(tags);
}, []);
const onTagItemPress = useCallback((event: TagItemPressEvent) => {
props.dispatch({ type: 'SIDE_MENU_CLOSE' });
props.dispatch({
type: 'NAV_GO',
routeName: 'Notes',
tagId: event.id,
});
}, [props.dispatch]);
type RenderItemEvent = { item: TagEntity };
const onRenderItem = useCallback(({ item }: RenderItemEvent) => {
return (
<TouchableOpacity
onPress={() => onTagItemPress({ id: item.id })}
accessibilityRole='button'
accessibilityHint={_('Shows notes for tag')}
>
<View style={styles.listItem}>
<Text style={styles.listItemText}>{item.title}</Text>
</View>
</TouchableOpacity>
);
}, [onTagItemPress, styles]);
return (
<View style={styles.rootStyle}>
<ScreenHeader title={_('Tags')} showSearchButton={false} />
<FlatList style={{ flex: 1 }} data={tags} renderItem={onRenderItem} keyExtractor={tag => tag.id} />
</View>
);
};
const TagsScreen = connect((state: AppState) => {
return {
themeId: state.settings.theme,
};
})(TagsScreenComponent);
export default TagsScreen;

View File

@ -56,7 +56,7 @@ import RevisionService from '@joplin/lib/services/RevisionService';
import JoplinDatabase from '@joplin/lib/JoplinDatabase';
import Database from '@joplin/lib/database';
import NotesScreen from './components/screens/Notes';
const { TagsScreen } = require('./components/screens/tags.js');
import TagsScreen from './components/screens/tags';
import ConfigScreen from './components/screens/ConfigScreen/ConfigScreen';
const { FolderScreen } = require('./components/screens/folder.js');
import LogScreen from './components/screens/LogScreen';