Skip to content

Commit

Permalink
Merge pull request #89 from oatear/main
Browse files Browse the repository at this point in the history
Update feature branch with latest
  • Loading branch information
hristoiankov committed Aug 3, 2023
2 parents d04c4fd + 44b81a2 commit 06baf91
Show file tree
Hide file tree
Showing 16 changed files with 397 additions and 93 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Card IDE (CIDEr) - Design game cards using `HTML/Handlebars`, `CSS`, and `tabula
[![][downloads]][releases-url]
[![][last-commit]][gh-url]
[![][website]][pages-url]
[![][discord]][discord-url]

Website: [Start using Cider][pages-url]

Expand Down Expand Up @@ -82,6 +83,7 @@ The repository itself is protected by [AGPL-3.0][license-url] to ensure the proj
[license]: https://badgen.net/github/license/oatear/cider?cache=600
[stars]: https://img.shields.io/github/stars/oatear/cider
[release]: https://img.shields.io/github/v/release/oatear/cider
[discord]: https://img.shields.io/discord/1129380421642240133?logo=discord&label=discord&color=%23515fe4&link=https%3A%2F%2Fdiscord.gg%2FHu9wMB5W
[downloads]: https://img.shields.io/github/downloads/oatear/cider/total
[website]: https://img.shields.io/website?down_color=red&down_message=offline&up_color=green&up_message=online&url=https%3A%2F%2Foatear.github.io%2Fcider
[logo-url]: docs/assets/cider-logo-80.png
Expand All @@ -98,3 +100,4 @@ The repository itself is protected by [AGPL-3.0][license-url] to ensure the proj
[ttsexport-url]: TTS_EXPORT.md
[license-url]: LICENSE.md
[pages-url]: https://oatear.github.io/cider
[discord-url]: https://discord.gg/Hu9wMB5W
29 changes: 26 additions & 3 deletions cider-app/electron-app/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import * as path from 'path';
import * as fs from 'fs';

let win: BrowserWindow = null;
const args = process.argv.slice(1),
serve = args.some(val => val === '--serve');
const args = process.argv.slice(1);
const serve = args.some(val => val === '--serve');
var shouldClose: Boolean = false;

function createWindow(): BrowserWindow {

Expand Down Expand Up @@ -52,12 +53,28 @@ function createWindow(): BrowserWindow {
}

// Emitted when the window is closed.
win.on('close', (event) => {
if (!shouldClose) {
win.webContents.send('app-closed');
event.preventDefault();
}
});
win.on('closed', () => {
// Dereference the window object, usually you would store window
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
win = null;
});
// win.on('close', function (e) {
// let response = dialog.showMessageBoxSync(this, {
// type: 'question',
// buttons: ['Yes', 'No'],
// title: 'Confirm',
// message: 'Are you sure you want to quit?'
// });

// if(response == 1) e.preventDefault();
// });

return win;
}
Expand Down Expand Up @@ -92,6 +109,11 @@ try {
}
});

// app.on('before-quit', (event) => {
// win.webContents.send('app-closed');
// event.preventDefault();
// });

/**
* Minimize/maximize the window on titlebar double click
*/
Expand All @@ -112,7 +134,7 @@ try {
*/
ipcMain.handle('open-select-directory-dialog', async (event, arg) => {
const result = await dialog.showOpenDialog(win, {
properties: ['openDirectory']
properties: ['openDirectory', 'createDirectory']
});
console.log('directory selected', result.filePaths);
return result;
Expand Down Expand Up @@ -221,6 +243,7 @@ try {
* Exit the application
*/
ipcMain.on('exit-application', async (event, arg) => {
shouldClose = true;
app.quit();
});

Expand Down
6 changes: 3 additions & 3 deletions cider-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
"author": {
"name": "Hristo Iankov"
},
"version": "0.4.3",
"version": "0.4.6",
"repository": "https://github.com/oatear/cider",
"main": "electron-app/dist/main.js",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"build:gh-pages": "ng build --baseHref=/cider/",
"build:gh-pages": "ng build --base-href=/cider/",
"watch": "ng build --watch --configuration development",
"test": "ng test",
"electron": "ng build --base-href ./ && tsc --p electron-app && electron .",
Expand Down Expand Up @@ -77,4 +77,4 @@
"karma-jasmine-html-reporter": "~2.1.0",
"typescript": "~4.9.5"
}
}
}
42 changes: 29 additions & 13 deletions cider-app/src/app/card-preview/card-preview.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AfterViewChecked, ChangeDetectorRef, Component, DoCheck, ElementRef, Input, OnInit, QueryList, SecurityContext, ViewChildren } from '@angular/core';
import { AfterViewChecked, ChangeDetectorRef, Component, DoCheck, ElementRef, Input, OnChanges, OnInit, QueryList, SecurityContext, SimpleChanges, ViewChildren } from '@angular/core';
import { AssetsService } from '../data-services/services/assets.service';
import { CardTemplate } from '../data-services/types/card-template.type';
import { Card } from '../data-services/types/card.type';
Expand All @@ -15,7 +15,7 @@ import GeneralUtils from '../shared/utils/general-utils';
templateUrl: './card-preview.component.html',
styleUrls: ['./card-preview.component.scss']
})
export class CardPreviewComponent implements OnInit, AfterViewChecked {
export class CardPreviewComponent implements OnInit, AfterViewChecked, OnChanges {
@ViewChildren('cardElement') cardElement: QueryList<any> = {} as QueryList<any>;
@Input() card: Card = {} as Card;
@Input() template: CardTemplate = {} as CardTemplate;
Expand All @@ -28,6 +28,7 @@ export class CardPreviewComponent implements OnInit, AfterViewChecked {
uuid: string = uuid();
cachedImageUrl?: string;
private isLoadedSubject: AsyncSubject<boolean>;
private isCacheLoadedSubject: AsyncSubject<boolean>;

constructor(
private assetsService: AssetsService,
Expand All @@ -37,7 +38,8 @@ export class CardPreviewComponent implements OnInit, AfterViewChecked {
private cardToHtmlPipe: CardToHtmlPipe,
private sanitizer: DomSanitizer) {
this.isLoadedSubject = new AsyncSubject();
}
this.isCacheLoadedSubject = new AsyncSubject();
}

/**
* Setup the initial width and height when the view fully renders once
Expand All @@ -57,28 +59,42 @@ export class CardPreviewComponent implements OnInit, AfterViewChecked {
ngOnInit(): void {
this.assetsService.getAssetUrls().subscribe(assetUrls => {
this.assetUrls = assetUrls;
if (this.cache) {
lastValueFrom(this.isLoadedSubject).then(() => {
this.renderCacheService.getOrSet(this.getHash(),
() => GeneralUtils.delay(5000).then(() => this.toImageUrl()))
.subscribe((cachedImageUrl) => {
this.cachedImageUrl = cachedImageUrl
});
});
}
});
}

ngOnChanges(changes: SimpleChanges): void {
if (this.cache && this.assetUrls) {
lastValueFrom(this.isLoadedSubject).then(() => {
this.renderCacheService.getOrSet(this.getHash(),
() => GeneralUtils.delay(2000).then(() => this.toImageUrl()))
.subscribe((cachedImageUrl) => {
this.cachedImageUrl = cachedImageUrl;
GeneralUtils.delay(1000).then(() => {
this.isCacheLoadedSubject.next(true);
this.isCacheLoadedSubject.complete();
});
});
});
}
}

public getHash(): number {
const html = this.cardToHtmlPipe.transform(this.template, this.card, this.assetUrls);
return this.renderCacheService.calculateHash((html as any).changingThisBreaksApplicationSecurity);
}

public toImageUrl(): Promise<string> {
return htmlToImage.toPng((<any>this.cardElement.get(0)).nativeElement, {pixelRatio: 1.0});
const filter = (node: HTMLElement) => {
return 'style' !== node.localName;
};
return htmlToImage.toPng((<any>this.cardElement.get(0)).nativeElement, {pixelRatio: 1.0, filter: filter});
}

public isLoaded() {
return this.isLoadedSubject.asObservable();
}

public isCacheLoaded() {
return this.isCacheLoadedSubject.asObservable();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
optionLabel="label" optionValue="value"></p-selectButton>
<p-selectButton [options]="sideOptions" [(ngModel)]="sideSelected" class="p-mr-3"
optionLabel="label" optionValue="value"></p-selectButton>
<p-selectButton [options]="copyOptions" [(ngModel)]="copySelected" class="p-mr-3"
optionLabel="label" optionValue="value" (onChange)="refreshCards()"></p-selectButton>
<input type="search" pInputText placeholder="Search Cards" (input)="filter($event)">
</div>
<div class="card-thumbnails">
Expand Down
22 changes: 18 additions & 4 deletions cider-app/src/app/card-thumbnails/card-thumbnails.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,38 @@ export class CardThumbnailsComponent implements OnInit {
{ label: 'Both', value: 'both' }
];
filterFields: string = "";
copyOptions: any[] = [
{ label: 'Singles', value: 'singles' },
{ label: 'Copies', value: 'copies' }
];
copySelected: string = 'copies';



constructor(public cardsService: CardsService,
public templatesService: CardTemplatesService) { }

ngOnInit(): void {
this.refreshCards();
this.cardsService.getFields().then(fields => {
this.filterFields = fields.map(field => field.field).join(',');
});
}

refreshCards() {
this.cardsService.getAll().then(cards => {
const expandedList: Card[] = [];
cards.forEach(card => {
for (let i = 0; i < (typeof card.count === 'undefined' ? 1 : card.count); i++) {
if (this.copySelected === 'singles') {
expandedList.push(card);
} else {
for (let i = 0; i < (typeof card.count === 'undefined' ? 1 : card.count); i++) {
expandedList.push(card);
}
}
});
this.thumbnailCards = expandedList;
});
this.cardsService.getFields().then(fields => {
this.filterFields = fields.map(field => field.field).join(',');
});
}

filter(input: any) {
Expand Down
2 changes: 1 addition & 1 deletion cider-app/src/app/cards/cards.component.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<app-page-header header="Cards" subheader="List of all the cards in the deck"></app-page-header>
<app-cards-tab-menu></app-cards-tab-menu>
<p-card styleClass="page-card tabbed-card">
<app-entity-table [service]="cardsService" [allowImportExport]="true"></app-entity-table>
<app-entity-table [service]="cardsService" [allowImportExport]="true" [showStats]="true"></app-entity-table>
</p-card>
15 changes: 14 additions & 1 deletion cider-app/src/app/data-services/electron/electron.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { CardsService } from '../services/cards.service';
import { DecksService } from '../services/decks.service';
import XlsxUtils from 'src/app/shared/utils/xlsx-utils';
import { EntityService } from '../types/entity-service.type';
import { Subject } from 'rxjs';

@Injectable({
providedIn: 'root'
Expand All @@ -20,10 +21,16 @@ export class ElectronService {
private static readonly DECKS_DIR = "decks";
private projectHomeUrl: BehaviorSubject<string | undefined>;
private projectUnsaved: BehaviorSubject<boolean>;
private appClosed: Subject<null>;

constructor() {
this.projectHomeUrl = new BehaviorSubject<string | undefined>(undefined);
this.projectUnsaved = new BehaviorSubject<boolean>(false);
this.appClosed = new Subject<null>();

this.getIpcRenderer().on('app-closed', () => {
this.appClosed.next(null);
});
}

public getProjectHomeUrl() {
Expand All @@ -34,6 +41,10 @@ export class ElectronService {
return this.projectUnsaved.asObservable();
}

public getIsAppClosed() {
return this.appClosed.asObservable();
}

public setProjectUnsaved(unsaved: boolean) {
this.projectUnsaved.next(unsaved);
}
Expand Down Expand Up @@ -159,6 +170,7 @@ export class ElectronService {
this.writeFile(deckUrl + '/' + StringUtils.toKebabCase(template.name) + '.html', template.html)
]);
}));
this.setProjectUnsaved(false);
return true;
}));
}
Expand All @@ -182,7 +194,7 @@ export class ElectronService {
await cardsService.emptyTable();
await decksService.emptyTable();
await this.listDirectory(assetsUrl).then(assetUrls => Promise.all(assetUrls
.filter(assetUrl => assetUrl.isFile).map(async assetUrl => {
.filter(assetUrl => assetUrl.isFile && !assetUrl.name.includes('.DS_Store')).map(async assetUrl => {
const assetNameSplit = StringUtils.splitNameAndExtension(assetUrl.name);
const assetName = assetNameSplit.name;
const assetExt = assetNameSplit.extension;
Expand Down Expand Up @@ -220,6 +232,7 @@ export class ElectronService {
const cardsUrl = deckFullUrl + '/cards.csv';
const attributes = await this.importCsv(attributesUrl, 'attributes.csv', cardAttributesService, deck.id);
const cards = await this.importCsv(cardsUrl, 'cards.csv', cardsService, deck.id);
this.setProjectUnsaved(false);
});
}

Expand Down
13 changes: 12 additions & 1 deletion cider-app/src/app/data-services/indexed-db/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { ExportProgress } from "dexie-export-import/dist/export";
import { ImportProgress } from "dexie-export-import/dist/import";
import { FieldType } from "../types/field-type.type";
import { HttpClient } from "@angular/common/http";
import { firstValueFrom } from "rxjs";
import { BehaviorSubject, Subject, firstValueFrom } from "rxjs";
import { Injectable } from "@angular/core";

@Injectable({
Expand All @@ -34,10 +34,12 @@ export class AppDB extends Dexie {
assets!: Table<Asset, number>;
cardTemplates!: Table<CardTemplate, number>;
private httpClient;
private changeSubject: Subject<null>;

constructor(httpClient: HttpClient) {
super(AppDB.DB_NAME);
this.httpClient = httpClient;
this.changeSubject = new Subject<null>();
this.version(1).stores({
games: '++id, name',
cards: '++id, gameId, count, frontCardTemplateId, backCardTemplateId',
Expand Down Expand Up @@ -88,6 +90,11 @@ export class AppDB extends Dexie {
console.log('populate from file');
return this.populateFromFile().then(() => true);
}));

// trigger changeSubject when change emitted to db
Dexie.on('storagemutated', (event) => {
this.changeSubject.next(null);
});
}

async populateFromFile() {
Expand Down Expand Up @@ -147,4 +154,8 @@ export class AppDB extends Dexie {
return true;
});
}

public onChange() {
return this.changeSubject.asObservable();
}
}
Loading

0 comments on commit 06baf91

Please sign in to comment.