Skip to content

Commit aa67ac9

Browse files
committed
Merge remote-tracking branch 'origin/main'
2 parents 8ed8aec + f3dc37b commit aa67ac9

22 files changed

Lines changed: 579 additions & 126 deletions

app/components/list/CardListCell.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@
267267
on:close={(e) => onFullCardItemTouch(item, { action: 'up' })}> -->
268268
<gridlayout {height} width="100%" {...$$restProps}>
269269
<gridlayout id="cardItemTemplate" class="cardItemTemplate" prop:mainContent {...getItemHolderParams(layout, item, $nbColumns)} on:tap on:longPress>
270-
{#if pkPassCell}
270+
{#if CARD_APP && pkPassCell}
271271
<PKPassCardCell {item} {itemWidth} {layout} pkpass={item.doc.pages[0]?.pkpass} />
272272
{:else}
273273
<RotableImageView {...getItemRotableImageParams(item)} />

app/components/pkpass/PKPassCardCell.svelte

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
<script lang="ts">
22
import { lang } from '~/helpers/locale';
3-
import { PKPass, PKPassData, PKPassField, PKPassStructure, PKPassTransitType } from '~/models/PKPass';
3+
import { PKPass, PKPassData, PKPassField, PKPassStructure, PKPassStyle, PKPassTransitType, PKPassType } from '~/models/PKPass';
44
import { getFieldTextAlignment, getTransitIcon } from '~/utils/pkpass';
55
import { colors } from '~/variables';
66
import { Item } from '~/components/list/MainList.svelte';
7+
import { Color } from '@nativescript/core';
78
89
const FIELD_LINE_HEIGHT = 15;
910
@@ -43,9 +44,9 @@
4344
4445
function updatePkPass(pkpass: PKPass) {
4546
passData = pkpass?.passData;
46-
foregroundColor = passData?.foregroundColor || colorOnBackground;
47-
labelColor = passData.labelColor || colorOnBackground;
4847
backgroundColor = passData?.backgroundColor || colorSurface;
48+
foregroundColor = passData?.foregroundColor || (new Color(backgroundColor).getBrightness() < 145 ? 'white' : 'black');
49+
labelColor = passData.labelColor || (new Color(backgroundColor).getBrightness() < 145 ? 'white' : 'black');
4950
// Apple PKPass image specifications - prefer @2x for quality
5051
logoImage = pkpass?.images?.logo2x || pkpass?.images?.logo; // Max 160x50 points
5152
iconImage = pkpass?.images?.icon2x || pkpass?.images?.icon; // 29x29 points
@@ -79,8 +80,7 @@
7980
// Get formatted field label
8081
function getFieldLabel(field: any): string {
8182
if (!field) return null;
82-
const label = field.label || field.key;
83-
return pkpass.getLocalizedValue(label, lang).toUpperCase() + '\n';
83+
return pkpass.getLocalizedFieldLabel(field, lang).toUpperCase() + '\n';
8484
}
8585
8686
function getLocalizedText(text: string): string {
@@ -90,11 +90,16 @@
9090

9191
<!-- Credit card sized layout with scalable content -->
9292
<gridlayout {backgroundColor} borderRadius={12 * scaleFactor} {...$$restProps}>
93+
{#if stripImage && pkpass?.passType === PKPassType.ESpass}
94+
<image noRatioEnforce={true} opacity={0.3} rowSpan={4} src={stripImage} stretch="aspectFill" width="100%" />
95+
{/if}
9396
<!-- Strip or thumbnail banner at top if available -->
94-
<image colSpan={3} height={60 * scaleFactor} row={0} src={stripImage || thumbnailImage} stretch="aspectFill" visibility={stripImage || thumbnailImage ? 'visible' : 'collapse'} />
97+
{#if pkpass?.passType === PKPassType.PKPass}
98+
<image colSpan={3} height={60 * scaleFactor} row={0} src={stripImage || thumbnailImage} stretch="aspectFill" visibility={stripImage || thumbnailImage ? 'visible' : 'collapse'} />
99+
{/if}
95100

96101
<!-- Content container with proper padding -->
97-
<gridlayout padding={12 * scaleFactor} rows="auto,*,auto,auto">
102+
<gridlayout padding={12 * scaleFactor} rows={`auto,${pkpass?.getPassStyle() === PKPassStyle.BoardingPass ? '*' : 'auto'},auto,auto`}>
98103
<!-- Top row: Logo/Icon + Name (limited width) + Important right-side data -->
99104
<gridlayout columns="auto,*,auto" marginBottom={5 * scaleFactor} row={0}>
100105
<!-- Left: Logo (max 80px scaled) or Icon (20px scaled) + Name -->

app/components/pkpass/PKPassView.svelte

Lines changed: 76 additions & 38 deletions
Large diffs are not rendered by default.

app/components/view/CardView.svelte

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,13 @@
300300
function onSelectedIndex(event) {
301301
currentQRCodeIndex = event.object.selectedIndex;
302302
}
303+
function geAllPages() {
304+
const selected: { page: OCRPage; document: OCRDocument }[] = [];
305+
items.forEach((d, index) => {
306+
selected.push({ page: d.page, document });
307+
});
308+
return selected;
309+
}
303310
function getSelectedPages() {
304311
const selected: { page: OCRPage; document: OCRDocument }[] = [];
305312
items.forEach((d, index) => {
@@ -770,6 +777,7 @@
770777
onClose: async (item) => {
771778
try {
772779
let result;
780+
DEV_LOG && console.log('item.id', item.id);
773781
switch (item.id) {
774782
case 'share':
775783
result = await showImageExportPopover(event);
@@ -823,26 +831,26 @@
823831
} else {
824832
// Filter options based on PKPass document
825833
826-
const allOptions = [
827-
{ id: 'rename', name: lc('rename'), icon: 'mdi-rename' },
828-
{ id: 'select_all', name: lc('select_all'), icon: 'mdi-select-all' },
829-
{ id: 'reorder', name: lc('reorder_pages'), icon: 'mdi-reorder-horizontal' }
830-
] as any[];
834+
const allOptions = [{ id: 'rename', name: lc('rename'), icon: 'mdi-rename' }] as any[];
831835
832836
if (!isPKPassDocument) {
833837
if (hasImages) {
834838
allOptions.push(
835839
...[
840+
{ id: 'select_all', name: lc('select_all'), icon: 'mdi-select-all' },
841+
{ id: 'reorder', name: lc('reorder_pages'), icon: 'mdi-reorder-horizontal' },
836842
{ id: 'transform', name: lc('transform_images'), icon: 'mdi-auto-fix' },
837843
{ id: 'ocr', name: lc('ocr_document'), icon: 'mdi-text-recognition' }
838844
]
839845
);
840846
}
847+
} else {
848+
allOptions.push({ id: 'share', name: lc('share_images'), icon: 'mdi-share-variant' });
841849
}
842850
allOptions.push(...[{ id: 'delete', name: lc('delete'), icon: 'mdi-delete', color: colorError }]);
843851
844852
// For PKPass documents, only allow delete (of the whole document)
845-
const options = new ObservableArray(isPKPassDocument ? allOptions.filter((opt) => opt.id === 'delete') : allOptions);
853+
const options = new ObservableArray(allOptions);
846854
return showPopoverMenu({
847855
options,
848856
anchor: event.object,
@@ -853,6 +861,9 @@
853861
case 'rename':
854862
editingTitle = true;
855863
break;
864+
case 'share':
865+
await showImagePopoverMenu(geAllPages(), event.object);
866+
break;
856867
case 'select_all':
857868
selectAll();
858869
break;
@@ -1344,7 +1355,7 @@
13441355

13451356
<page bind:this={page} id="cardview" actionBarHidden={true} statusBarColor={topBackgroundColor} {statusBarStyle}>
13461357
<gridlayout class="pageContent" backgroundColor={topBackgroundColor} columns={$isLandscape ? 'auto,*' : '*'} rows={$isLandscape ? 'auto,*' : 'auto,auto,*'}>
1347-
{#if isPKPassDocument}
1358+
{#if CARD_APP && isPKPassDocument}
13481359
<pager bind:this={pager} items={document.pages} row={2} transformers="zoomOut" on:selectedIndexChange={onSelectedIndex}>
13491360
<Template let:item>
13501361
<stacklayout padding="0">

app/i18n/en.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@
159159
"expanded": "expanded",
160160
"export": "export",
161161
"export_folder": "export folder",
162+
"export_as_espass": "Export as ESpass",
163+
"export_as_pkpass": "Export as PKPass",
162164
"export_passbooks": "export Passbooks",
163165
"export_settings": "export settings",
164166
"export_settings_desc": "export all application settings so that you can import them later",
@@ -395,6 +397,8 @@
395397
"share": "share",
396398
"share_application": "share application",
397399
"share_images": "share images",
400+
"share_as_espass": "Share as ESpass",
401+
"share_as_pkpass": "Share as PKPass",
398402
"share_passbooks": "share Passbooks",
399403
"show_fullscreen_images": "fullscreen",
400404
"show_love": "If you like the project please share some love or even contribute",

app/models/PKPass.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@ import { formatCurrency } from '@shared/helpers/format';
33
import dayjs from 'dayjs';
44

55
/**
6-
* PKPass model representing an Apple Wallet Pass
7-
* Based on Apple's PassKit specification
6+
* PKPass model representing a wallet pass (Apple PKPass or ESpass)
7+
* Based on Apple's PassKit specification and ESpass open standard
88
*/
99

10+
export enum PKPassType {
11+
PKPass = 'pkpass',
12+
ESpass = 'espass'
13+
}
14+
1015
export enum PKPassStyle {
1116
BoardingPass = 'boardingPass',
1217
Coupon = 'coupon',
@@ -135,6 +140,9 @@ export class PKPass extends Observable {
135140
id: string;
136141
page_id: string; // Changed from document_id to page_id
137142

143+
// Pass type identifier (pkpass or espass)
144+
passType: PKPassType = PKPassType.PKPass;
145+
138146
// PKPass data
139147
passData: PKPassData;
140148
images: PKPassImages;
@@ -147,10 +155,11 @@ export class PKPass extends Observable {
147155
createdDate: number;
148156
modifiedDate?: number;
149157

150-
constructor(id: string, pageId: string) {
158+
constructor(id: string, pageId: string, passType: PKPassType = PKPassType.PKPass) {
151159
super();
152160
this.id = id;
153161
this.page_id = pageId;
162+
this.passType = passType;
154163
this.createdDate = Date.now();
155164
}
156165

@@ -207,6 +216,11 @@ export class PKPass extends Observable {
207216
return this.passData.voided === true;
208217
}
209218

219+
getLocalizedFieldLabel(field: any, currentLang: string): string {
220+
if (!field) return null;
221+
const label = field.label || field.key;
222+
return this.getLocalizedValue(label, currentLang);
223+
}
210224
/**
211225
* Get localized value for a given key based on current app language
212226
* @param key The key to localize
@@ -323,7 +337,7 @@ export class PKPass extends Observable {
323337
}
324338

325339
static fromJSON(jsonObj: any): PKPass {
326-
const pass = new PKPass(jsonObj.id, jsonObj.page_id || jsonObj.document_id); // Support both old and new schema
340+
const pass = new PKPass(jsonObj.id, jsonObj.page_id || jsonObj.document_id, jsonObj.passType || PKPassType.PKPass); // Support both old and new schema
327341
Object.assign(pass, {
328342
passData: typeof jsonObj.passData === 'string' ? JSON.parse(jsonObj.passData) : jsonObj.passData,
329343
images: typeof jsonObj.images === 'string' ? JSON.parse(jsonObj.images) : jsonObj.images,
@@ -339,6 +353,7 @@ export class PKPass extends Observable {
339353
return {
340354
id: this.id,
341355
page_id: this.page_id,
356+
passType: this.passType,
342357
passData: this.passData,
343358
images: this.images,
344359
// passJsonPath: this.passJsonPath,

app/services/documents.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { doInBatch } from '@shared/utils/batch';
66
import SqlQuery from 'kiss-orm/dist/Queries/SqlQuery';
77
import CrudRepository from 'kiss-orm/dist/Repositories/CrudRepository';
88
import { DocFolder, Document, IDocFolder, OCRDocument, OCRPage, Page, Tag } from '~/models/OCRDocument';
9-
import { PKPass } from '~/models/PKPass';
9+
import { PKPass, PKPassType } from '~/models/PKPass';
1010
import { EVENT_DOCUMENT_DELETED, SETTINGS_ROOT_DATA_FOLDER } from '~/utils/constants';
1111
import { groupByArray } from '@shared/utils';
1212
import DatabaseInterface from 'kiss-orm/dist/Databases/DatabaseInterface';
@@ -203,6 +203,10 @@ export class PKPassRepository extends BaseRepository<PKPass, PKPass> {
203203
});
204204
}
205205

206+
migrations = {
207+
addPassType: sql`ALTER TABLE PKPass ADD COLUMN passType TEXT NOT NULL DEFAULT 'pkpass'`
208+
};
209+
206210
async createTables() {
207211
return this.database.query(sql`
208212
CREATE TABLE IF NOT EXISTS "PKPass" (
@@ -225,6 +229,7 @@ export class PKPassRepository extends BaseRepository<PKPass, PKPass> {
225229
cleanUndefined({
226230
id: pkpass.id,
227231
page_id: pkpass.page_id,
232+
passType: pkpass.passType || PKPassType.PKPass,
228233
passData: JSON.stringify(pkpass.passData),
229234
images: JSON.stringify(pkpass.images),
230235
// passJsonPath: pkpass.passJsonPath,
@@ -261,7 +266,7 @@ export class PKPassRepository extends BaseRepository<PKPass, PKPass> {
261266

262267
async createModelFromAttributes(attributes: any): Promise<PKPass> {
263268
const { images, passData, ...other } = attributes;
264-
const model = new PKPass(attributes.id, attributes.page_id || attributes.document_id); // Support both for migration
269+
const model = new PKPass(attributes.id, attributes.page_id || attributes.document_id, attributes.passType || PKPassType.PKPass); // Support both for migration
265270
Object.assign(model, {
266271
...other,
267272
passData: typeof passData === 'string' ? JSON.parse(passData) : passData,

app/utils/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export const SEPARATOR = '/';
5353
export const IMG_FORMAT = 'jpg';
5454
export const PDF_EXT = '.pdf';
5555
export const PKPASS_EXT = '.pkpass';
56+
export const ESPASS_EXT = '.espass';
5657
export const CARD_RATIO = 0.629;
5758
export const IMAGE_DECODE_HEIGHT = Math.max(Screen.mainScreen.widthPixels, Screen.mainScreen.heightPixels);
5859

0 commit comments

Comments
 (0)