Skip to content

Commit

Permalink
added typeahead, fixed scss, code tidied up
Browse files Browse the repository at this point in the history
  • Loading branch information
kaisentlaia committed Feb 25, 2021
1 parent 4d22f9e commit f3ee419
Show file tree
Hide file tree
Showing 7 changed files with 319 additions and 186 deletions.
270 changes: 188 additions & 82 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "gerbil",
"version": "0.1.0",
"version": "0.2.0",
"main": "main.ts",
"description": "A simple time tracker",
"author": "Kaisentlaia <kaisentlaia@gmail.com>",
Expand Down Expand Up @@ -63,12 +63,14 @@
"@angular/compiler": "~9.1.0",
"@angular/core": "~9.1.0",
"@angular/forms": "~9.1.0",
"@angular/localize": "~9.1.0",
"@angular/platform-browser": "~9.1.0",
"@angular/platform-browser-dynamic": "~9.1.0",
"@angular/router": "~9.1.0",
"@fortawesome/angular-fontawesome": "^0.6.1",
"@fortawesome/fontawesome-svg-core": "^1.2.34",
"@fortawesome/free-solid-svg-icons": "^5.15.2",
"@ng-bootstrap/ng-bootstrap": "^6.2.0",
"bootstrap": "^4.6.0",
"electron-reload": "^1.5.0",
"electron-store": "^7.0.2",
Expand Down
14 changes: 7 additions & 7 deletions src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<button type="button" class="btn btn-dark btn-sm mr-sm-1" (click)="dayBefore()" tabindex="1" title="Previous day"><fa-icon [icon]="faCaretLeft"></fa-icon></button>
<button type="button" class="btn btn-dark btn-sm mr-sm-1" (click)="setDate(null)" tabindex="2" title="Today"><fa-icon [icon]="faCalendarDay"></fa-icon></button>
<button type="button" class="btn btn-dark btn-sm mr-sm-1" (click)="dayAfter()" tabindex="3" title="Next day"><fa-icon [icon]="faCaretRight"></fa-icon></button>
<input type="date" name="selectedDate" class="form-control form-control-sm w-auto mr-sm-1" [ngModel] ="selectedDate | date:'yyyy-MM-dd'" (change)="datePicker($event);" tabindex="4">
<input type="date" name="selectedDate" class="form-control form-control-gerbil form-control-sm w-auto mr-sm-1" [ngModel] ="selectedDate | date:'yyyy-MM-dd'" (change)="datePicker($event);" tabindex="4">
<button type="button" class="btn btn-dark btn-sm mr-sm-1" [ngClass]="filterDays==FILTER_ALL?'active':''" (click)="filterDays=FILTER_ALL" title="Cycle through all days"><fa-icon [icon]="faCalendarAlt"></fa-icon></button>
<button type="button" class="btn btn-dark btn-sm mr-sm-1" [ngClass]="filterDays==FILTER_FULL?'active':''" (click)="filterDays=FILTER_FULL" title="Cycle through non empty days only"><fa-icon [icon]="faCalendarCheck"></fa-icon></button>
<button type="button" class="btn btn-dark btn-sm mr-sm-1" [ngClass]="filterDays==FILTER_EMPTY?'active':''" (click)="filterDays=FILTER_EMPTY" title="Cycle through empty days only"><fa-icon [icon]="faCalendar"></fa-icon></button>
Expand All @@ -30,7 +30,7 @@ <h4 class="text-truncate">{{activeTask?.name}}</h4>

<div class="form-row pt-2 pb-3 pl-1 pr-1">
<div class="flex-grow-1">
<input name="taskName" type="text" class="form-control" placeholder="Task name" [(ngModel)]="newTask" (keyup.enter)="switchTask(newTask)" (click)="clearSelection()" (keyup.esc)="newTask=null" tabindex="7" #taskNameNew autofocus>
<input name="taskName" type="text" class="form-control form-control-gerbil" placeholder="Task name" [(ngModel)]="newTask" (keyup.enter)="switchTask(newTask)" (click)="clearSelection()" (keyup.esc)="newTask=null" tabindex="7" [ngbTypeahead]="search" #taskNameNew autofocus>
</div>
<div>
<button *ngIf="!activeTask" type="button" class="ml-2 btn btn-success" (click)="beginTask(newTask)" [disabled]="!newTask" tabindex="8"><fa-icon [icon]="faPlay"></fa-icon></button>
Expand All @@ -47,7 +47,7 @@ <h4 class="text-truncate">{{activeTask?.name}}</h4>
<div class="card scrollable mh-100 h-100">

<ul *ngIf="!openTask" class="list-group list-group-flush">
<li class="list-group-item list-group-item-action list-group-item-light d-flex justify-content-between align-items-center" *ngFor="let task of todayTasks; let i = index" (click)="selectTask(task)" (focus)="selectTask(task)" (keyup.enter)="editTask()" (keyup.delete)="deleteTask()" (keyup.esc)="clearSelection()" [ngClass]="(selectedTask==task)?'active':''" [tabindex]="i+10" (dblclick)="editTask()">
<li class="list-group-item list-group-item-gerbil list-group-item-action list-group-item-dark d-flex justify-content-between align-items-center" *ngFor="let task of todayTasks; let i = index" (click)="selectTask(task)" (focus)="selectTask(task)" (keyup.enter)="editTask()" (keyup.delete)="deleteTask()" (keyup.esc)="clearSelection()" [ngClass]="(selectedTask==task)?'active':''" [tabindex]="i+10" (dblclick)="editTask()">
<span class="hours">{{task.start | date: 'HH:mm'}} - {{task.end | date: 'HH:mm'}}</span>
<span class="text-truncate flex-grow-1">{{task.name}}</span>
<span class="badge badge-dark badge-pill">{{getDurationPill(task)}}</span>
Expand All @@ -59,17 +59,17 @@ <h4 class="text-truncate">{{activeTask?.name}}</h4>
<div class="form-group row">
<label class="col-2 col-form-label col-form-label-sm text-right">Task</label>
<div class="col-10">
<input type="text" class="form-control form-control-sm" [(ngModel)]="openTask.name" [value]="openTask.name" name="name" (keyup.enter)="saveTask()" (keyup.esc)="clearSelection()" tabindex="10" #taskNameEdit>
<input type="text" class="form-control form-control-gerbil form-control-sm" [(ngModel)]="openTask.name" [value]="openTask.name" name="name" (keyup.enter)="saveTask()" (keyup.esc)="clearSelection()" tabindex="10" #taskNameEdit autofocus>
</div>
</div>
<div class="form-group row">
<label class="col-2 col-form-label col-form-label-sm text-right">Start at</label>
<div class="col-4">
<input type="time" class="form-control form-control-sm" [(ngModel)]="openTask.startTime" [value]="openTask.startTime" name="startTime" (keyup.enter)="saveTask()" (keyup.esc)="clearSelection()" tabindex="11">
<input type="time" class="form-control form-control-gerbil form-control-sm" [(ngModel)]="openTask.startTime" [value]="openTask.startTime" name="startTime" (keyup.enter)="saveTask()" (keyup.esc)="clearSelection()" tabindex="11">
</div>
<label class="col-2 col-form-label col-form-label-sm text-right">End at</label>
<div class="col-4">
<input type="time" class="form-control form-control-sm" [(ngModel)]="openTask.endTime" [value]="openTask.endTime" name="endTime" (keyup.enter)="saveTask()" (keyup.esc)="clearSelection()" tabindex="12">
<input type="time" class="form-control form-control-gerbil form-control-sm" [(ngModel)]="openTask.endTime" [value]="openTask.endTime" name="endTime" (keyup.enter)="saveTask()" (keyup.esc)="clearSelection()" tabindex="12">
</div>
</div>
<div class="form-group row">
Expand Down Expand Up @@ -104,7 +104,7 @@ <h4>Totals</h4>
</div>
<div class="col">
<div class="progress bg-dark mb-1">
<div [ngClass]="(taskTotal[0].active)?'progress-bar-striped progress-bar-animated':''" class="progress-bar text-right bg-secondary p-1" role="progressbar" [style]="'width:' + taskTotal[0].percent +'%'" [attr.aria-valuenow]="taskTotal[0].percent" aria-valuemin="0" aria-valuemax="100">{{millisToDecH(taskTotal[0].total)}}h</div>
<div [ngClass]="(taskTotal[0].active)?'progress-bar-striped progress-bar-animated':''" class="progress-bar progress-bar-gerbil text-right bg-secondary p-1" role="progressbar" [style]="'width:' + taskTotal[0].percent +'%'" [attr.aria-valuenow]="taskTotal[0].percent" aria-valuemin="0" aria-valuemax="100">{{millisToDecH(taskTotal[0].total)}}h</div>
</div>
</div>
</div>
Expand Down
73 changes: 47 additions & 26 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,41 @@
import { Component, AfterViewChecked, NgZone, ViewChild, ElementRef, OnInit } from '@angular/core';
import { Component, AfterViewChecked, NgZone, ViewChild, ElementRef, OnInit, ViewEncapsulation } from '@angular/core';
import { Task } from './task.model';
import { Observable, interval, Subscription } from 'rxjs';
import {debounceTime, distinctUntilChanged, map} from 'rxjs/operators';


import { ElectronService } from 'ngx-electron';
import { faMagic, faCaretRight, faCaretLeft, faCalendar, faCalendarAlt, faCalendarCheck, faCalendarDay, faPlay, faStop, faRandom } from '@fortawesome/free-solid-svg-icons';

let taskNames = [] as string[];

const FILTER_ALL = 0;
const FILTER_EMPTY = 1;
const FILTER_FULL = 2;
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
styleUrls: ['./app.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class AppComponent implements AfterViewChecked, OnInit {
title = 'gerbil';
private updateSubscription: Subscription;
@ViewChild('taskNameNew') taskNameNew: ElementRef;
@ViewChild('taskNameEdit') taskNameEdit: ElementRef;
faMagic = faMagic;
faCaretRight = faCaretRight;
faCaretLeft = faCaretLeft;
faCalendar = faCalendar;
faCalendarAlt = faCalendarAlt;
faCalendarCheck = faCalendarCheck;
faCalendarDay = faCalendarDay;
faPlay = faPlay;
faStop = faStop;
faRandom = faRandom;
readonly FILTER_ALL = FILTER_ALL;
readonly FILTER_EMPTY = FILTER_EMPTY;
readonly FILTER_FULL = FILTER_FULL;
readonly faMagic = faMagic;
readonly faCaretRight = faCaretRight;
readonly faCaretLeft = faCaretLeft;
readonly faCalendar = faCalendar;
readonly faCalendarAlt = faCalendarAlt;
readonly faCalendarCheck = faCalendarCheck;
readonly faCalendarDay = faCalendarDay;
readonly faPlay = faPlay;
readonly faStop = faStop;
readonly faRandom = faRandom;

debugLevel = 1;

Expand All @@ -39,10 +51,6 @@ export class AppComponent implements AfterViewChecked, OnInit {
useMagic: boolean;
filterDays: number;

FILTER_ALL = 0;
FILTER_EMPTY = 1;
FILTER_FULL = 2;

constructor(
public electronService: ElectronService,
readonly ngZone: NgZone
Expand All @@ -59,7 +67,7 @@ export class AppComponent implements AfterViewChecked, OnInit {
}
);
this.useMagic = true;
this.filterDays = this.FILTER_ALL;
this.filterDays = FILTER_ALL;
// this.debug('this.electronService.isElectronApp', this.electronService.isElectronApp);
if (this.electronService.isElectronApp) {
// this.debug('electron app');
Expand Down Expand Up @@ -125,9 +133,12 @@ export class AppComponent implements AfterViewChecked, OnInit {
}

ngAfterViewChecked() {
if (this.openTask) {
this.taskNameEdit.nativeElement.focus();
}
// if (this.openTask) {
// this.taskNameEdit.nativeElement.focus();
// }
taskNames = this.tasks.map( (item) => {
return item.name;
}).filter((value, index, self) => self.indexOf(value) === index);
}

loadData(tasks: Task[]) {
Expand Down Expand Up @@ -282,17 +293,17 @@ export class AppComponent implements AfterViewChecked, OnInit {
const dayBefore = new Date(this.selectedDate.getTime());
dayBefore.setDate(dayBefore.getDate() - 1);
this.setDate(dayBefore);
if (this.filterDays !== this.FILTER_ALL) {
if (this.filterDays !== FILTER_ALL) {
const yearStart = new Date(this.selectedDate.getTime());
yearStart.setMonth(0, 1);
let dayTasks = this.getDayTasks(dayBefore);
let found = this.filterDays === this.FILTER_FULL ? dayTasks.length > 0 : dayTasks.length === 0;
let found = this.filterDays === FILTER_FULL ? dayTasks.length > 0 : dayTasks.length === 0;
while (!found && dayBefore > yearStart) {
dayBefore.setDate(dayBefore.getDate() - 1);
this.debug(['checking', dayBefore], 1);
this.setDate(dayBefore);
dayTasks = this.getDayTasks(dayBefore);
found = this.filterDays === this.FILTER_FULL ? dayTasks.length > 0 : dayTasks.length === 0;
found = this.filterDays === FILTER_FULL ? dayTasks.length > 0 : dayTasks.length === 0;
}
}
}
Expand All @@ -301,17 +312,17 @@ export class AppComponent implements AfterViewChecked, OnInit {
const dayAfter = new Date(this.selectedDate.getTime());
dayAfter.setDate(dayAfter.getDate() + 1);
this.setDate(dayAfter);
if (this.filterDays !== this.FILTER_ALL) {
if (this.filterDays !== FILTER_ALL) {
const yearEnd = new Date(this.selectedDate.getTime());
yearEnd.setMonth(11, 31);
let dayTasks = this.getDayTasks(dayAfter);
let found = this.filterDays === this.FILTER_FULL ? dayTasks.length > 0 : dayTasks.length === 0;
let found = this.filterDays === FILTER_FULL ? dayTasks.length > 0 : dayTasks.length === 0;
while (!found && dayAfter < yearEnd) {
dayAfter.setDate(dayAfter.getDate() + 1);
this.debug(['checking', dayAfter], 1);
this.setDate(dayAfter);
dayTasks = this.getDayTasks(dayAfter);
found = this.filterDays === this.FILTER_FULL ? dayTasks.length > 0 : dayTasks.length === 0;
found = this.filterDays === FILTER_FULL ? dayTasks.length > 0 : dayTasks.length === 0;
}
}
}
Expand Down Expand Up @@ -492,6 +503,16 @@ export class AppComponent implements AfterViewChecked, OnInit {
this.saveData();
}

search(text$: Observable<string>) {

return text$.pipe(
debounceTime(200),
distinctUntilChanged(),
map(term => term.length < 2 ? []
: taskNames.filter( name => name?.toLowerCase().indexOf(term.toLowerCase()) > -1).slice(0, 10) )
);
}

private debug(messages, level) {
if (this.debugLevel > 0 && level <= this.debugLevel) {
messages.map((message) => {
Expand Down
4 changes: 3 additions & 1 deletion src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { AppComponent } from './app.component';
import { FormsModule } from '@angular/forms';
import { ElectronService } from 'ngx-electron';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';

@NgModule({
declarations: [
Expand All @@ -16,7 +17,8 @@ import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
BrowserModule,
AppRoutingModule,
FormsModule,
FontAwesomeModule
FontAwesomeModule,
NgbModule
],
providers: [ElectronService],
bootstrap: [AppComponent]
Expand Down
4 changes: 4 additions & 0 deletions src/polyfills.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/***************************************************************************************************
* Load `$localize` onto the global scope - used if i18n tags appear in Angular templates.
*/
import '@angular/localize/init';
/**
* This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file.
Expand Down
Loading

0 comments on commit f3ee419

Please sign in to comment.