Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions app/app.android.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ button[variant='contained'] {
height: 40;
}

.sheetHeaderTitle {
font-size: 22;
margin-left: 8;
}

// a tonal chip: the surface has no glass here
.cardChip {
background-color: var(--colorPrimaryContainer);
Expand All @@ -22,3 +27,15 @@ button[variant='contained'] {
border-radius: 30;
border-width: 1;
}

// a field: 56 tall and 4 around
.formRow {
height: 64;
}

// the outline takes the accent while the field has the focus
textfield[variant='outline'] {
floating-color: var(--colorPrimary);
stroke-color: var(--colorPrimary);
stroke-inactive-color: var(--colorOutline);
}
17 changes: 17 additions & 0 deletions app/app.ios.scss
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ button[variant='contained'] {
height: 44;
}

.sheetHeaderTitle {
font-size: 17;
font-weight: bold;
text-align: center;
}

// capsule text fields: the system fill, 12% gray in light and 24% in dark
textfield[variant='outline'],
textview[variant='outline'] {
Expand All @@ -100,3 +106,14 @@ textview[variant='outline'] {
min-height: 84;
padding: 12 16;
}

// a field: 48 tall and 4 around
.formRow {
height: 56;
}

textfield[variant='outline']:focused,
textview[variant='outline']:focused {
border-color: var(--colorPrimary);
border-width: 1.5;
}
24 changes: 24 additions & 0 deletions app/components/common/SheetHeader.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<script lang="ts">
import { lc } from '@nativescript-community/l';
import { appIcon } from '~/utils/appIcons';
import { colors } from '~/variables';

export let title: string;
export let doneText: string;
export let doneEnabled = true;
export let onCancel: () => void;
export let onDone: () => void;
let { colorOnPrimary, colorOnSurface, colorPrimary } = $colors;
$: ({ colorOnPrimary, colorOnSurface, colorPrimary } = $colors);
$: doneColor = __IOS__ ? colorOnPrimary : colorPrimary;

// iOS: a glass Cancel pill and a prominent action. Android: a close icon and a text action
const cancelProps = __IOS__ ? { text: lc('cancel'), variant: 'glass' } : { src: appIcon('close'), variant: 'text' };
const doneVariant = __IOS__ ? 'contained' : 'text';
</script>

<gridlayout columns="auto,*,auto" padding="12 16 8 16" {...$$restProps}>
<uibutton accessibilityLabel={lc('cancel')} {...cancelProps} on:tap={onCancel} />
<label class="sheetHeaderTitle" col={1} color={colorOnSurface} text={title} verticalAlignment="center" />
<uibutton col={2} color={doneColor} isEnabled={doneEnabled} opacity={doneEnabled ? 1 : 0.45} text={doneText} variant={doneVariant} on:tap={onDone} />
</gridlayout>
4 changes: 3 additions & 1 deletion app/components/list/CardsList.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
DEFAULT_NB_COLUMNS_LANDSCAPE,
SETTINGS_CARD_ALWAYS_SHOW_NAME,
SETTINGS_NB_COLUMNS,
SETTINGS_NB_COLUMNS_LANDSCAPE
SETTINGS_NB_COLUMNS_LANDSCAPE,
SHEET_SOFT_INPUT_MODE
} from '~/utils/constants';
import { appIcon } from '~/utils/appIcons';
import { documentHasPKPassData } from '~/utils/pkpass';
Expand Down Expand Up @@ -82,6 +83,7 @@
const result = await showBottomSheet({
parent: this,
view: CreateCard,
windowSoftInputMode: SHEET_SOFT_INPUT_MODE,
ignoreTopSafeArea: true
});
DEV_LOG && console.log('CreateCard', result);
Expand Down
9 changes: 4 additions & 5 deletions app/components/view/CardEditSheet.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
import { lc } from '@nativescript-community/l';
import { Template } from '@nativescript-community/svelte-native/components';
import { TextField } from '@nativescript-community/ui-textfield';
import SheetHeader from '~/components/common/SheetHeader.svelte';
import { showBottomSheet } from '@nativescript-community/ui-bottomsheet/svelte';
import { showError } from '@shared/utils/showError';
import dayjs from 'dayjs';
import { ExtraFieldType, OCRDocument } from '~/models/OCRDocument';
import { qrcodeService } from '~/services/qrcode';
import { shortcutService } from '~/services/shortcuts';
import { appIcon } from '~/utils/appIcons';
import { SHEET_SOFT_INPUT_MODE } from '~/utils/constants';
import { pickColor } from '~/utils/ui';
import { colors } from '~/variables';
import ListItemAutoSize from '@shared/components/ListItemAutoSize.svelte';
Expand Down Expand Up @@ -108,6 +110,7 @@
parent: rootView,
skipCollapsedState: true,
view: ExtraFieldPicker,
windowSoftInputMode: SHEET_SOFT_INPUT_MODE,
props: { editing: !!field, ...(field?.extra || {}) }
});
if (!result) {
Expand Down Expand Up @@ -166,11 +169,7 @@
</script>

<gesturerootview bind:this={rootView} backgroundColor={__IOS__ ? colorBackground : colorSurface} rows="auto,*">
<gridlayout columns="auto,*,auto" padding="12 16 8 16">
<uibutton text={lc('cancel')} variant="text" on:tap={() => close(false)} />
<label col={1} color={colorOnSurface} fontSize={17} fontWeight="bold" text={lc('edit')} textAlignment="center" verticalAlignment="center" />
<uibutton col={2} text={lc('save')} variant="contained" on:tap={save} />
</gridlayout>
<SheetHeader doneText={lc('save')} onCancel={() => close(false)} onDone={save} title={lc('edit')} />
<collectionview row={1} {itemTemplateSelector} items={listItems}>
<Template key="name" let:item>
<textfield hint={lc('name')} margin="4 16 4 16" text={name} variant={__IOS__ ? 'none' : 'filled'} on:textChange={(e) => (name = e.value)} />
Expand Down
4 changes: 3 additions & 1 deletion app/components/view/CardView.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@
EVENT_DOCUMENT_UPDATED,
QRCODE_RESIZE_THRESHOLD,
SETTINGS_DOCUMENT_NAME_FORMAT,
SETTINGS_FORCE_WHITE_BACKGROUND_QRCODE
SETTINGS_FORCE_WHITE_BACKGROUND_QRCODE,
SHEET_SOFT_INPUT_MODE
} from '~/utils/constants';
import { appIcon } from '~/utils/appIcons';
import { optionsToMenuItems } from '~/utils/appMenu';
Expand Down Expand Up @@ -943,6 +944,7 @@
const saved = await showBottomSheet({
parent: page,
view: CardEditSheet,
windowSoftInputMode: SHEET_SOFT_INPUT_MODE,
detents: [{ fraction: 0.65 }, 'large'],
grabber: true,
props: { document }
Expand Down
60 changes: 38 additions & 22 deletions app/components/widgets/CreateCard.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import { FORMATS, getBarcodeFallbackString, qrcodeService } from '~/services/qrcode';
import { pickColor, showPopoverMenu } from '~/utils/ui';
import { colors } from '~/variables';
import { focusState } from '~/utils/svelte/actions';
import SheetHeader from '../common/SheetHeader.svelte';
import SvgView from '../common/SVGView.svelte';
</script>

Expand All @@ -21,6 +23,10 @@
let validCode = true;
const tMargin = '4 0 4 0';

function close() {
rootView.nativeView.bindingContext.closeCallback();
}

async function add() {
try {
if (!name || !color) {
Expand Down Expand Up @@ -80,26 +86,36 @@
}
</script>

<gesturerootview bind:this={rootView} columns="*,auto" padding={16} rows="auto,auto,auto,auto,auto,auto">
<label color={colorOnBackground} fontSize={20} fontWeight="bold" text={lc('create')} verticalAlignment="center" />
<stacklayout col={1} orientation="horizontal">
<label color={colorOnBackground} fontSize={16} text={lc('color')} verticalAlignment="center" />
<absolutelayout backgroundColor={color} borderColor={colorOutline} borderRadius="50%" borderWidth={2} height={40} marginLeft={10} width={40} on:tap={changeColor} />
</stacklayout>
<textfield colSpan={2} hint={lc('name')} margin={tMargin} row={1} text={name} variant="outline" on:textChange={(e) => (name = e.value)} />
<textfield colSpan={2} hint={lc('barcode')} margin={tMargin} row={2} text={code} variant="outline" on:textChange={onCodeTextChange} />
<textfield colSpan={2} editable={false} hint={lc('barcode_type')} margin={tMargin} row={3} text={codeFormat} textTransform="uppercase" variant="outline" on:tap={(e) => selectBarcodeFormat(e)} />
<SvgView backgroundColor="white" borderRadius={12} colSpan={2} height={100} item={{ svg }} row={4} stretch="aspectFit" visibility={code?.length ? 'visible' : 'collapse'} />
<label
colSpan={2}
fontSize={20}
fontWeight="bold"
row={4}
text={lc('invalid')}
textAlignment="center"
verticalAlignment="center"
visibility={code?.length && !validCode ? 'visible' : 'collapse'}
/>

<uibutton colSpan={2} horizontalAlignment="right" isEnabled={name?.length > 0} row={5} text={lc('add')} variant="contained" on:tap={add} />
<gesturerootview bind:this={rootView} rows="auto,auto">
<SheetHeader doneEnabled={name?.length > 0} doneText={lc('add')} onCancel={close} onDone={add} title={lc('create')} />
<gridlayout columns="*,auto" padding="0 16 16 16" row={1} rows="auto,auto,auto,auto,auto,auto">
<textfield colSpan={2} hint={lc('name')} margin={tMargin} text={name} use:focusState variant="outline" on:textChange={(e) => (name = e.value)} />
<textfield colSpan={2} hint={lc('barcode')} margin={tMargin} row={1} text={code} use:focusState variant="outline" on:textChange={onCodeTextChange} />
<textfield
colSpan={2}
editable={false}
hint={lc('barcode_type')}
margin={tMargin}
row={2}
text={codeFormat}
textTransform="uppercase"
variant="outline"
on:tap={(e) => selectBarcodeFormat(e)}
/>
<gridlayout class="formRow" colSpan={2} columns="*,auto" row={3} on:tap={changeColor}>
<label color={colorOnBackground} fontSize={17} margin="0 4" text={lc('color')} verticalAlignment="center" />
<absolutelayout backgroundColor={color} borderColor={colorOutline} borderRadius="50%" borderWidth={2} col={1} height={40} verticalAlignment="center" width={40} />
</gridlayout>
<SvgView backgroundColor="white" borderRadius={12} colSpan={2} height={100} item={{ svg }} row={4} stretch="aspectFit" visibility={code?.length ? 'visible' : 'collapse'} />
<label
colSpan={2}
fontSize={20}
fontWeight="bold"
row={4}
text={lc('invalid')}
textAlignment="center"
verticalAlignment="center"
visibility={code?.length && !validCode ? 'visible' : 'collapse'}
/>
</gridlayout>
</gesturerootview>
51 changes: 28 additions & 23 deletions app/components/widgets/ExtraFieldPicker.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@
import { showError } from '@shared/utils/showError';
import dayjs from 'dayjs';
import { formatDate } from '~/helpers/locale';
import SheetHeader from '~/components/common/SheetHeader.svelte';
import { focusState } from '~/utils/svelte/actions';
import { ExtraFieldType } from '~/models/OCRDocument';
import { pickDate, showPopoverMenu } from '~/utils/ui';
import { colors } from '~/variables';
</script>

<script lang="ts">
let { colorOnBackground, colorOnSurfaceVariant, colorOutlineVariant } = $colors;
$: ({ colorOnBackground, colorOnSurfaceVariant, colorOutlineVariant } = $colors);
let { colorOnSurfaceVariant, colorOutlineVariant } = $colors;
$: ({ colorOnSurfaceVariant, colorOutlineVariant } = $colors);

export let editing = false;
export let name = null;
Expand Down Expand Up @@ -91,6 +93,10 @@
}
}

function close() {
rootView.nativeView.bindingContext.closeCallback();
}

async function add() {
try {
if (!currentName || (!currentValue && currentType !== ExtraFieldType.Date)) {
Expand Down Expand Up @@ -123,25 +129,24 @@
}
</script>

<gesturerootview bind:this={rootView} padding={16} rows="auto,auto,auto,auto,auto">
<label color={colorOnBackground} fontSize={20} fontWeight="bold" marginBottom={16} text={editing ? lc('edit_extra_field') : lc('add_extra_field')} />
<gridlayout row={1}>
<textfield hint={lc('name')} margin={tMargin} paddingLeft={60} row={2} text={currentName} variant="outline" on:textChange={(e) => (currentName = e.value)} />
<uibutton class="icon-btn" color={colorOnSurfaceVariant} horizontalAlignment="left" text="mdi-menu-down" variant="text" verticalAlignment="middle" on:tap={selecteTemplateName} />
</gridlayout>
<textfield editable={false} hint={lc('type')} margin={tMargin} row={2} text={lc(currentType)} textTransform="uppercase" variant="outline" on:tap={(e) => selectType(e)} />

<textview
editable={currentType !== ExtraFieldType.Date}
hint={lc('value')}
keyboardType={getKeyboardType(currentType)}
margin={tMargin}
row={3}
text={currentType === ExtraFieldType.Date ? formatDate(currentTime, 'LL') : currentValue}
variant="outline"
on:textChange={(e) => (currentValue = e.value)}
on:tap={(e) => selectDate(e)}
/>

<uibutton horizontalAlignment="right" row={4} text={editing ? lc('edit') : lc('add')} variant="contained" on:tap={add} />
<gesturerootview bind:this={rootView} rows="auto,auto">
<SheetHeader doneText={editing ? lc('edit') : lc('add')} onCancel={close} onDone={add} title={editing ? lc('edit_extra_field') : lc('add_extra_field')} />
<stacklayout padding="0 16 16 16" row={1}>
<gridlayout>
<textfield hint={lc('name')} margin={tMargin} paddingLeft={60} text={currentName} use:focusState variant="outline" on:textChange={(e) => (currentName = e.value)} />
<uibutton class="icon-btn" color={colorOnSurfaceVariant} horizontalAlignment="left" text="mdi-menu-down" variant="text" verticalAlignment="middle" on:tap={selecteTemplateName} />
</gridlayout>
<textfield editable={false} hint={lc('type')} margin={tMargin} text={lc(currentType)} textTransform="uppercase" variant="outline" on:tap={(e) => selectType(e)} />
<textview
editable={currentType !== ExtraFieldType.Date}
hint={lc('value')}
keyboardType={getKeyboardType(currentType)}
margin={tMargin}
text={currentType === ExtraFieldType.Date ? formatDate(currentTime, 'LL') : currentValue}
use:focusState
variant="outline"
on:textChange={(e) => (currentValue = e.value)}
on:tap={(e) => selectDate(e)}
/>
</stacklayout>
</gesturerootview>
3 changes: 3 additions & 0 deletions app/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,6 @@ export const DOCUMENT_DATA_FILENAME = 'data.json';
export const DELETED_DOCUMENTS_DATA_FILENAME = 'deleted_documents.json';
export const DELETED_FOLDERS_DATA_FILENAME = 'deleted_folders.json';
export const VALID_MARKER_FILENAME = '.valid';

// SOFT_INPUT_ADJUST_RESIZE: a sheet with fields moves up with the keyboard
export const SHEET_SOFT_INPUT_MODE = __ANDROID__ ? 16 : undefined;
16 changes: 16 additions & 0 deletions app/utils/svelte/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { NativeViewElementNode } from '@nativescript-community/svelte-native/dom';
import type { TextBase } from '@nativescript/core';

/** css has no `:focus`: the field gets the `focused` pseudo class while it has the focus */
export function focusState(node: NativeViewElementNode<TextBase>) {
const onFocus = () => node.nativeView.addPseudoClass('focused');
const onBlur = () => node.nativeView.deletePseudoClass('focused');
node.addEventListener('focus', onFocus);
node.addEventListener('blur', onBlur);
return {
destroy() {
node.removeEventListener('focus', onFocus);
node.removeEventListener('blur', onBlur);
}
};
}
Loading