changed graph appearance + QOL improvements

This commit is contained in:
2024-11-08 21:27:05 +01:00
parent 6271cdd99d
commit 38543bae7f
7 changed files with 131 additions and 126 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "WorkTime", "name": "WorkTime",
"version": "0.3.1", "version": "0.3.2",
"author": "Ionic Framework", "author": "Ionic Framework",
"homepage": "https://ionicframework.com/", "homepage": "https://ionicframework.com/",
"scripts": { "scripts": {

View File

@@ -27,7 +27,10 @@
<ion-card> <ion-card>
<ion-card-header> <ion-card-header>
<ion-card-title>Noch zu arbeiten</ion-card-title> <ion-card-title>Noch zu arbeiten</ion-card-title>
<ion-card-subtitle *ngIf="combinedWorkTime > (settings.maxWorkTime + settings.desiredOverTime)">Tagessoll erreicht!</ion-card-subtitle> <ion-card-subtitle *ngIf="combinedWorkTime < settings.maxWorkTime">Noch {{formatTime(settings.maxWorkTime - combinedWorkTime)}} Stunden</ion-card-subtitle>
<ion-card-subtitle *ngIf="combinedWorkTime >= settings.maxWorkTime && combinedWorkTime < (settings.maxWorkTime + settings.desiredOverTime)">Arbeitszeit erreicht!</ion-card-subtitle>
<ion-card-subtitle *ngIf="combinedWorkTime >= (settings.maxWorkTime + settings.desiredOverTime) && combinedWorkTime <= (settings.maxWorkTime + settings.maxOverTime)">Tagessoll erreicht!</ion-card-subtitle>
<ion-card-subtitle *ngIf="combinedWorkTime > settings.maxWorkTime + settings.maxOverTime">Tageslimit erreicht!</ion-card-subtitle>
</ion-card-header> </ion-card-header>
<ion-card-content> <ion-card-content>
@@ -63,7 +66,7 @@
{{formatTime(Math.max(combinedWorkTime - settings.maxWorkTime, 0))}} von {{formatTime(settings.desiredOverTime)}} ({{formatTime(settings.maxOverTime)}} maximal) {{formatTime(Math.max(combinedWorkTime - settings.maxWorkTime, 0))}} von {{formatTime(settings.desiredOverTime)}} ({{formatTime(settings.maxOverTime)}} maximal)
<ion-progress-bar <ion-progress-bar
*ngIf="combinedWorkTime - settings.maxWorkTime <= settings.maxOverTime" *ngIf="combinedWorkTime - settings.maxWorkTime <= settings.maxOverTime"
class="work-progress" id="overtime" class="work-progress" id="overtime" [ngClass]="{'progress-warn': combinedWorkTime > settings.maxWorkTime + settings.desiredOverTime}"
[value]="(combinedWorkTime - settings.maxWorkTime) / settings.maxOverTime" [value]="(combinedWorkTime - settings.maxWorkTime) / settings.maxOverTime"
[buffer]="settings.desiredOverTime / settings.maxOverTime" [buffer]="settings.desiredOverTime / settings.maxOverTime"
/> />

View File

@@ -5,7 +5,7 @@
background-image: radial-gradient(ellipse at center, var(--background) 0%, var(--background) 30%, var(--background) 30%); background-image: radial-gradient(ellipse at center, var(--background) 0%, var(--background) 30%, var(--background) 30%);
} }
&::part(track) { &::part(track), &.progress-warn::part(progress) {
background-color: var(--ion-color-warning); background-color: var(--ion-color-warning);
} }
} }

View File

@@ -21,7 +21,7 @@ import {TimeService} from "../../services/time.service";
import {Chart} from "chart.js/auto"; import {Chart} from "chart.js/auto";
import {addIcons} from "ionicons"; import {addIcons} from "ionicons";
import {briefcase, card, pizza} from "ionicons/icons"; import {briefcase, card, pizza} from "ionicons/icons";
import {NgIf} from "@angular/common"; import {NgClass, NgIf} from "@angular/common";
import {SettingsService} from "../../services/settings.service"; import {SettingsService} from "../../services/settings.service";
import {Settings} from "../../models/settings"; import {Settings} from "../../models/settings";
import {AppComponent} from "../app.component"; import {AppComponent} from "../app.component";
@@ -31,7 +31,7 @@ import {AppComponent} from "../app.component";
templateUrl: 'analysis.page.html', templateUrl: 'analysis.page.html',
styleUrls: ['analysis.page.scss'], styleUrls: ['analysis.page.scss'],
standalone: true, standalone: true,
imports: [IonHeader, IonToolbar, IonTitle, IonContent, IonItem, IonLabel, IonDatetimeButton, IonModal, IonDatetime, FormsModule, IonCard, IonCardHeader, IonCardTitle, IonCardContent, IonCardSubtitle, IonList, IonIcon, IonProgressBar, NgIf] imports: [IonHeader, IonToolbar, IonTitle, IonContent, IonItem, IonLabel, IonDatetimeButton, IonModal, IonDatetime, FormsModule, IonCard, IonCardHeader, IonCardTitle, IonCardContent, IonCardSubtitle, IonList, IonIcon, IonProgressBar, NgIf, NgClass]
}) })
export class AnalysisPage { export class AnalysisPage {
public currentDate: any; public currentDate: any;
@@ -51,7 +51,7 @@ export class AnalysisPage {
constructor(private time: TimeService, private settingsProvider: SettingsService) { constructor(private time: TimeService, private settingsProvider: SettingsService) {
this.settings = this.settingsProvider.loadSettings(); this.settings = this.settingsProvider.loadSettings();
addIcons({briefcase, pizza, card}) addIcons({briefcase, pizza, card});
} }
ionViewDidEnter() { ionViewDidEnter() {
@@ -72,11 +72,6 @@ export class AnalysisPage {
this.driveTime = 0; this.driveTime = 0;
this.combinedWorkTime = 0; this.combinedWorkTime = 0;
if (this.timeData.length == 0) {
this.showEmptyChart();
return;
}
if (this.timeData.length >= 1 && this.time.isToday(this.currentDate)) { if (this.timeData.length >= 1 && this.time.isToday(this.currentDate)) {
const lastEntry = this.timeData[this.timeData.length - 1]; const lastEntry = this.timeData[this.timeData.length - 1];
const diff = this.time.calculateTimespanInMinutes(lastEntry, { const diff = this.time.calculateTimespanInMinutes(lastEntry, {
@@ -98,7 +93,7 @@ export class AnalysisPage {
} }
} }
if (this.timeData.length > 2) { if (this.timeData.length >= 2) {
for (let i = 1; i < this.timeData.length; i++) { for (let i = 1; i < this.timeData.length; i++) {
const start = this.timeData[i - 1]; const start = this.timeData[i - 1];
const end = this.timeData[i]; const end = this.timeData[i];
@@ -135,22 +130,34 @@ export class AnalysisPage {
const style = getComputedStyle(document.body); const style = getComputedStyle(document.body);
const textColor = style.getPropertyValue('--ion-text-color'); const textColor = style.getPropertyValue('--ion-text-color');
const workColor = style.getPropertyValue('--ion-color-primary'); const workColor = style.getPropertyValue('--ion-color-primary');
const driveColor = style.getPropertyValue('--ion-color-secondary');
const remainColor = style.getPropertyValue('--ion-card-background'); const remainColor = style.getPropertyValue('--ion-card-background');
const overColor = style.getPropertyValue('--ion-color-tertiary'); const overColor = style.getPropertyValue('--ion-color-tertiary');
const overColorWarn = style.getPropertyValue('--ion-color-warning'); const overColorWarn = style.getPropertyValue('--ion-color-warning');
const overColorDanger = style.getPropertyValue('--ion-color-danger');
let overData: number[] = []; let chartData: number[] = [];
let overLabels: string[] = []; let chartLabels: string[] = [];
let overColors: string[] = []; let chartColors: string[] = [];
if (this.combinedWorkTime > this.settings.maxWorkTime) { if (this.combinedWorkTime > (this.settings.maxWorkTime + this.settings.maxOverTime)) {
chartData.push(1);
chartColors.push(overColorDanger);
}
else if (this.combinedWorkTime > this.settings.maxWorkTime) {
const overTime = this.combinedWorkTime - this.settings.maxWorkTime; const overTime = this.combinedWorkTime - this.settings.maxWorkTime;
const overPercentage = overTime / this.settings.desiredOverTime; const overPercentage = (overTime / this.settings.desiredOverTime) * 0.5;
overData.push(this.combinedWorkTime * overPercentage); chartData.push(overPercentage, 1 - overPercentage);
overLabels.push('Überstunden'); chartLabels.push('Überstunden', 'Arbeitszeit');
overColors.push(overPercentage > 1 ? overColorWarn : overColor); chartColors.push(overPercentage > 0.5 ? overColorWarn : overColor, workColor);
}
else if (this.combinedWorkTime == 0) {
chartData.push(1);
chartColors.push(remainColor);
}
else {
chartData.push(this.workTime, Math.max(this.settings.maxWorkTime - this.combinedWorkTime, 0));
chartColors.push(workColor, remainColor);
} }
this.chart?.destroy(); this.chart?.destroy();
@@ -158,55 +165,17 @@ export class AnalysisPage {
this.chart = new Chart(this.chartRef.nativeElement, { this.chart = new Chart(this.chartRef.nativeElement, {
type: 'doughnut', type: 'doughnut',
data: { data: {
labels: [ labels: chartLabels,
...overLabels,
'Arbeitszeit',
'Dienstreise'
],
datasets: [{ datasets: [{
label: 'Zeit', data: chartData,
data: [...overData, this.workTime, this.driveTime, Math.max(this.settings.maxWorkTime - this.combinedWorkTime, 0)], backgroundColor: chartColors
backgroundColor: [
...overColors,
workColor,
driveColor,
remainColor
],
}] }]
}, },
options: { options: {
events: [], events: [],
plugins: { plugins: {
legend: { legend: {
display: this.driveTime > 0 || this.combinedWorkTime > this.settings.maxWorkTime display: false
}
}
}
});
}
public showEmptyChart() {
const style = getComputedStyle(document.body);
const remainColor = style.getPropertyValue('--ion-card-background');
this.chart?.destroy();
this.chart = new Chart(this.chartRef.nativeElement, {
type: 'doughnut',
data: {
labels: [],
datasets: [{
label: 'Zeit',
data: [100],
backgroundColor: [
remainColor
],
}]
},
options: {
events: [],
plugins: {
legend: {
display: this.driveTime > 0 || this.combinedWorkTime > this.settings.maxWorkTime
} }
} }
} }

View File

@@ -13,62 +13,69 @@
</ion-toolbar> </ion-toolbar>
</ion-header> </ion-header>
<ion-list> <ion-card>
<!--<ion-item> <ion-card-content>
<ion-toggle [(ngModel)]="input.notifications">Benachrichtigungen</ion-toggle> <ion-list>
</ion-item> <!--<ion-item>
<ion-item-divider/>--> <ion-toggle [(ngModel)]="input.notifications">Benachrichtigungen</ion-toggle>
<ion-item> </ion-item>
<ion-label><h1>Zeiten</h1></ion-label> <ion-item-divider/>-->
</ion-item> <ion-item>
<ion-item> <ion-icon aria-hidden="true" name="briefcase"></ion-icon>
<ion-label slot="start">Arbeitszeit</ion-label> <ion-label><h1>Zeiten</h1></ion-label>
<ion-input type="number" fill="solid" [placeholder]="settings.maxWorkTime / 60" [(ngModel)]="input.maxWorkTime" /> </ion-item>
<ion-label slot="end">Stunden</ion-label> <ion-item>
</ion-item> <ion-label slot="start">Arbeitszeit</ion-label>
<ion-item-divider/> <ion-input type="number" fill="solid" [placeholder]="settings.maxWorkTime / 60" [(ngModel)]="input.maxWorkTime" />
<ion-item> <ion-label slot="end">Stunden</ion-label>
<ion-label><h1>Pause</h1></ion-label> </ion-item>
</ion-item> <ion-item-divider/>
<ion-item> <ion-item>
<ion-label slot="start">Nach 0 Stunden</ion-label> <ion-icon aria-hidden="true" name="pizza"></ion-icon>
<ion-input type="number" fill="solid" [placeholder]="settings.defaultPauseTime" [(ngModel)]="input.defaultPauseTime" /> <ion-label><h1>Pause</h1></ion-label>
<ion-label slot="end">Minuten</ion-label> </ion-item>
</ion-item> <ion-item>
<ion-item> <ion-label slot="start">Nach 0 Stunden</ion-label>
<ion-label slot="start">Nach 6 Stunden</ion-label> <ion-input type="number" fill="solid" [placeholder]="settings.defaultPauseTime" [(ngModel)]="input.defaultPauseTime" />
<ion-input type="number" fill="solid" [placeholder]="settings.pauseAfter6" [(ngModel)]="input.pauseAfter6" /> <ion-label slot="end">Minuten</ion-label>
<ion-label slot="end">Minuten</ion-label> </ion-item>
</ion-item> <ion-item>
<ion-item> <ion-label slot="start">Nach 6 Stunden</ion-label>
<ion-label slot="start">Nach 9 Stunden</ion-label> <ion-input type="number" fill="solid" [placeholder]="settings.pauseAfter6" [(ngModel)]="input.pauseAfter6" />
<ion-input type="number" fill="solid" [placeholder]="settings.pauseAfter9" [(ngModel)]="input.pauseAfter9" /> <ion-label slot="end">Minuten</ion-label>
<ion-label slot="end">Minuten</ion-label> </ion-item>
</ion-item> <ion-item>
<ion-item> <ion-label slot="start">Nach 9 Stunden</ion-label>
<ion-label slot="start">Nicht tracken nach</ion-label> <ion-input type="number" fill="solid" [placeholder]="settings.pauseAfter9" [(ngModel)]="input.pauseAfter9" />
<ion-input type="number" fill="solid" [placeholder]="settings.dontTrackPauseAfter" [(ngModel)]="input.dontTrackPauseAfter" /> <ion-label slot="end">Minuten</ion-label>
<ion-label slot="end">Uhr</ion-label> </ion-item>
</ion-item> <ion-item>
<ion-item-divider/> <ion-label slot="start">Nicht tracken nach</ion-label>
<ion-item> <ion-input type="number" fill="solid" [placeholder]="settings.dontTrackPauseAfter" [(ngModel)]="input.dontTrackPauseAfter" />
<ion-label><h1>Überstunden</h1></ion-label> <ion-label slot="end">Uhr</ion-label>
</ion-item> </ion-item>
<ion-item> <ion-item-divider/>
<ion-label slot="start">Optimal</ion-label> <ion-item>
<ion-input type="number" fill="solid" [placeholder]="settings.desiredOverTime" [(ngModel)]="input.desiredOverTime" /> <ion-icon aria-hidden="true" name="card"></ion-icon>
<ion-label slot="end">Minuten</ion-label> <ion-label><h1>Überstunden</h1></ion-label>
</ion-item> </ion-item>
<ion-item> <ion-item>
<ion-label slot="start">Maximal</ion-label> <ion-label slot="start">Optimal</ion-label>
<ion-input type="number" fill="solid" [placeholder]="settings.maxOverTime" [(ngModel)]="input.maxOverTime" /> <ion-input type="number" fill="solid" [placeholder]="settings.desiredOverTime" [(ngModel)]="input.desiredOverTime" />
<ion-label slot="end">Minuten</ion-label> <ion-label slot="end">Minuten</ion-label>
</ion-item> </ion-item>
<ion-item-divider/> <ion-item>
<ion-item> <ion-label slot="start">Maximal</ion-label>
<ion-col size="12" class="ion-text-center"> <ion-input type="number" fill="solid" [placeholder]="settings.maxOverTime" [(ngModel)]="input.maxOverTime" />
<ion-button size="normal" (click)="save()">Speichern</ion-button> <ion-label slot="end">Minuten</ion-label>
</ion-col> </ion-item>
</ion-item> <ion-item-divider/>
</ion-list> <ion-item>
<ion-col size="12" class="ion-text-center">
<ion-button size="normal" (click)="save()">Speichern</ion-button>
</ion-col>
</ion-item>
</ion-list>
</ion-card-content>
</ion-card>
</ion-content> </ion-content>

View File

@@ -1,3 +1,9 @@
ion-card-content {
ion-item, ion-item-divider {
--background: unset;
}
}
ion-item-divider { ion-item-divider {
--background: transparent; --background: transparent;
border-bottom: none; border-bottom: none;
@@ -10,3 +16,13 @@ ion-item {
ion-label { ion-label {
min-width: 60px; min-width: 60px;
} }
ion-icon {
height: 100%;
font-size: 1.7rem;
transform: translateY(-0.15rem);
margin-right: 1rem;
display: flex;
justify-content: center;
align-items: center;
}

View File

@@ -7,20 +7,30 @@ import {
IonList, IonList,
IonItem, IonItem,
IonInput, IonInput,
IonToggle, IonButton, IonLabel, IonItemDivider, IonCol, ToastController IonToggle,
IonButton,
IonLabel,
IonItemDivider,
IonCol,
ToastController,
IonIcon,
IonCard,
IonCardHeader,
IonCardTitle,
IonCardContent
} from '@ionic/angular/standalone'; } from '@ionic/angular/standalone';
import {Settings} from "../../models/settings"; import {Settings} from "../../models/settings";
import {SettingsService} from "../../services/settings.service"; import {SettingsService} from "../../services/settings.service";
import {FormsModule} from "@angular/forms"; import {FormsModule} from "@angular/forms";
import {addIcons} from "ionicons"; import {addIcons} from "ionicons";
import { save } from 'ionicons/icons'; import {briefcase, card, pizza, save} from 'ionicons/icons';
@Component({ @Component({
selector: 'app-tab3', selector: 'app-tab3',
templateUrl: 'settings.page.html', templateUrl: 'settings.page.html',
styleUrls: ['settings.page.scss'], styleUrls: ['settings.page.scss'],
standalone: true, standalone: true,
imports: [IonHeader, IonToolbar, IonTitle, IonContent, IonList, IonItem, IonInput, FormsModule, IonToggle, IonButton, IonLabel, IonItemDivider, IonCol], imports: [IonHeader, IonToolbar, IonTitle, IonContent, IonList, IonItem, IonInput, FormsModule, IonToggle, IonButton, IonLabel, IonItemDivider, IonCol, IonIcon, IonCard, IonCardHeader, IonCardTitle, IonCardContent],
}) })
export class SettingsPage { export class SettingsPage {
public settings: Settings; public settings: Settings;
@@ -30,7 +40,7 @@ export class SettingsPage {
this.settings = settingsProvider.loadSettings(); this.settings = settingsProvider.loadSettings();
this.input.notifications = this.settings.notifications; this.input.notifications = this.settings.notifications;
addIcons({save}); addIcons({save, briefcase, pizza, card});
} }
public async save() { public async save() {