mirror of
https://github.com/bulwarkmail/native.git
synced 2026-10-31 08:06:36 +00:00
fix: give user folders a folder icon even when their name looks like a system folder #80
This commit is contained in:
@@ -46,6 +46,7 @@ import {
|
||||
type NotificationMutes,
|
||||
} from '../lib/notification-mutes';
|
||||
import { serverSupportsEmailPush } from '../lib/push-notifications';
|
||||
import { mailboxIconKind, type MailboxIconKind } from '../lib/mailbox-icon';
|
||||
|
||||
const CHEVRON_SLOT = 20;
|
||||
const INDENT_STEP = 12;
|
||||
@@ -64,41 +65,28 @@ const UNIFIED_ROLES: UnifiedRole[] = ['sent', 'drafts', 'archive', 'junk', 'tras
|
||||
// in for them (#495).
|
||||
const HIDDEN_WITH_VIRTUAL_ROW = new Set(['scheduled']);
|
||||
|
||||
// Distinct icons for the special-use roles (#288), then a name-based guess
|
||||
// for servers that don't set roles, then a plain folder.
|
||||
function iconFor(
|
||||
role: string | null | undefined,
|
||||
name: string | undefined,
|
||||
hasChildren: boolean,
|
||||
isExpanded: boolean,
|
||||
): AppIcon {
|
||||
switch (role) {
|
||||
case 'inbox': return Inbox;
|
||||
case 'sent': return Send;
|
||||
case 'drafts': return FileIcon;
|
||||
case 'trash': return Trash2;
|
||||
case 'junk':
|
||||
case 'spam': return Ban;
|
||||
case 'archive': return Archive;
|
||||
case 'important': return Flag;
|
||||
case 'flagged': return Star;
|
||||
case 'all': return Mails;
|
||||
case 'memos': return StickyNote;
|
||||
case 'scheduled': return Clock;
|
||||
case 'snoozed': return AlarmClock;
|
||||
case 'shared': return Users;
|
||||
default: break;
|
||||
}
|
||||
const lower = (name ?? '').toLowerCase();
|
||||
if (lower.includes('inbox')) return Inbox;
|
||||
if (lower.includes('sent')) return Send;
|
||||
if (lower.includes('draft')) return FileIcon;
|
||||
if (lower.includes('trash') || lower.includes('deleted')) return Trash2;
|
||||
if (lower.includes('junk') || lower.includes('spam')) return Ban;
|
||||
if (lower.includes('archive')) return Archive;
|
||||
if (lower.includes('star') || lower.includes('flag')) return Star;
|
||||
if (hasChildren) return isExpanded ? FolderOpen : Folder;
|
||||
return Folder;
|
||||
// Distinct icons for the special-use roles (#288), else a plain folder: by
|
||||
// role only, never by name (lib/mailbox-icon.ts, #80).
|
||||
const ICONS: Record<MailboxIconKind, AppIcon> = {
|
||||
inbox: Inbox,
|
||||
sent: Send,
|
||||
drafts: FileIcon,
|
||||
trash: Trash2,
|
||||
junk: Ban,
|
||||
archive: Archive,
|
||||
important: Flag,
|
||||
flagged: Star,
|
||||
all: Mails,
|
||||
memos: StickyNote,
|
||||
scheduled: Clock,
|
||||
snoozed: AlarmClock,
|
||||
shared: Users,
|
||||
folder: Folder,
|
||||
'folder-open': FolderOpen,
|
||||
};
|
||||
|
||||
function iconFor(role: string | null | undefined, hasChildren: boolean, isExpanded: boolean): AppIcon {
|
||||
return ICONS[mailboxIconKind(role, hasChildren, isExpanded)];
|
||||
}
|
||||
|
||||
const ROLE_COLOR_FIXED: Record<string, string> = {
|
||||
@@ -745,7 +733,7 @@ export default function SidebarDrawer({ visible, onClose, docked = false }: Side
|
||||
};
|
||||
}, [mailboxes, accountSnapshots, activeAccountId, unifiedCrossAccount, includeGroupInUnified]);
|
||||
|
||||
const unifiedIcon = (role: UnifiedRole): AppIcon => iconFor(role, undefined, false, false);
|
||||
const unifiedIcon = (role: UnifiedRole): AppIcon => iconFor(role, false, false);
|
||||
|
||||
const slideX = React.useRef(new Animated.Value(-Dimensions.get('window').width)).current;
|
||||
const overlayOpacity = React.useRef(new Animated.Value(0)).current;
|
||||
@@ -1139,7 +1127,7 @@ export default function SidebarDrawer({ visible, onClose, docked = false }: Side
|
||||
// tapping it only opens or closes that account's folders.
|
||||
const Icon = node.isAccountNode
|
||||
? Users
|
||||
: iconFor(node.role, node.name, hasChildren, isExpanded);
|
||||
: iconFor(node.role, hasChildren, isExpanded);
|
||||
const isSelected = !node.isAccountNode && !tagViewActive && node.id === currentMailboxId;
|
||||
return (
|
||||
<SidebarRow
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { readFileSync } from 'fs';
|
||||
import path from 'path';
|
||||
import { mailboxIconKind } from '../mailbox-icon';
|
||||
|
||||
describe('mailboxIconKind', () => {
|
||||
it('gives each special-use role its icon', () => {
|
||||
expect(mailboxIconKind('sent', false, false)).toBe('sent');
|
||||
expect(mailboxIconKind('junk', false, false)).toBe('junk');
|
||||
expect(mailboxIconKind('spam', false, false)).toBe('junk');
|
||||
expect(mailboxIconKind('trash', true, true)).toBe('trash');
|
||||
});
|
||||
|
||||
// native #80: a sieve-sorted folder "web/sentry" got the Sent icon.
|
||||
it('gives a user folder a folder icon whatever its name says', () => {
|
||||
for (const name of ['sentry', 'Sent Items', 'Drafts old', 'memory', 'spam-reports', 'archive 2019']) {
|
||||
expect(mailboxIconKind(null, false, false), name).toBe('folder');
|
||||
}
|
||||
expect(mailboxIconKind(undefined, true, true)).toBe('folder-open');
|
||||
expect(mailboxIconKind(null, true, false)).toBe('folder');
|
||||
});
|
||||
|
||||
it('is what the sidebar uses, with no guess from the folder name', () => {
|
||||
const source = readFileSync(path.join(process.cwd(), 'src/components/SidebarDrawer.tsx'), 'utf8');
|
||||
expect(source).toContain('mailboxIconKind(');
|
||||
expect(source).not.toMatch(/lower\.includes\('(?:sent|inbox|draft|trash|junk|archive|star)'\)/);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
// Which icon a folder in the sidebar gets: one per special-use role (#288),
|
||||
// else a plain folder. By role only, as the webmail does
|
||||
// (components/layout/sidebar.tsx): a guess from the name gave a user folder
|
||||
// "web/sentry" the Sent icon (native #80, webmail #1235), and a folder that
|
||||
// holds no sent mail must not look like one that does.
|
||||
|
||||
export type MailboxIconKind =
|
||||
| 'inbox' | 'sent' | 'drafts' | 'trash' | 'junk' | 'archive' | 'important' | 'flagged'
|
||||
| 'all' | 'memos' | 'scheduled' | 'snoozed' | 'shared' | 'folder' | 'folder-open';
|
||||
|
||||
const ROLE_ICONS: Record<string, MailboxIconKind> = {
|
||||
inbox: 'inbox',
|
||||
sent: 'sent',
|
||||
drafts: 'drafts',
|
||||
trash: 'trash',
|
||||
junk: 'junk',
|
||||
spam: 'junk',
|
||||
archive: 'archive',
|
||||
important: 'important',
|
||||
flagged: 'flagged',
|
||||
all: 'all',
|
||||
memos: 'memos',
|
||||
scheduled: 'scheduled',
|
||||
snoozed: 'snoozed',
|
||||
shared: 'shared',
|
||||
};
|
||||
|
||||
export function mailboxIconKind(
|
||||
role: string | null | undefined,
|
||||
hasChildren: boolean,
|
||||
isExpanded: boolean,
|
||||
): MailboxIconKind {
|
||||
const byRole = role ? ROLE_ICONS[role] : undefined;
|
||||
if (byRole) return byRole;
|
||||
return hasChildren && isExpanded ? 'folder-open' : 'folder';
|
||||
}
|
||||
Reference in New Issue
Block a user