215 lines
9.2 KiB
HTML
215 lines
9.2 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>Espresso timer</title>
|
|
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
|
|
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@4.x/css/materialdesignicons.min.css" rel="stylesheet">
|
|
<link href="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css" rel="stylesheet">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
|
|
</head>
|
|
<body>
|
|
<div id="app">
|
|
<v-app>
|
|
<v-app-bar app>
|
|
<v-toolbar-title>Espresso timer</v-toolbar-title>
|
|
</v-app-bar>
|
|
|
|
<v-main>
|
|
<v-container>
|
|
<h2 class="text-h6 text-center">Timer</h2>
|
|
<v-row class="mt-8">
|
|
<v-col cols="2" offset="2">
|
|
<v-label>Grind level</p>
|
|
</v-col>
|
|
<v-col cols="6">
|
|
<v-slider
|
|
v-model="grindLevel"
|
|
thumb-color="primary"
|
|
thumb-label="always"
|
|
@change="storeValue('grindLevel')"
|
|
min="1"
|
|
max="20"
|
|
></v-slider>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<v-row>
|
|
<v-col cols="2" offset="2">
|
|
<v-label>Pre-infusion (in s)</p>
|
|
</v-col>
|
|
<v-col cols="6">
|
|
<v-slider
|
|
v-model="preinfusionTimer"
|
|
thumb-color="primary"
|
|
thumb-label="always"
|
|
:readonly="hasTimed || interval"
|
|
@change="storeValue('preinfusionTimer')"
|
|
min="0"
|
|
max="10"
|
|
></v-slider>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<v-row>
|
|
<v-col cols="2" offset="2">
|
|
<v-label>Total time (in s)</p>
|
|
</v-col>
|
|
<v-col cols="6">
|
|
<v-slider
|
|
v-model="totalTimer"
|
|
thumb-color="primary"
|
|
thumb-label="always"
|
|
:readonly="hasTimed || interval"
|
|
@change="storeValue('totalTimer')"
|
|
:min="preinfusionTimer"
|
|
max="40"
|
|
></v-slider>
|
|
</v-col>
|
|
<v-col cols="2" v-if="extraTotalTime > 0">
|
|
+ {{ extraTotalTime }}s
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<v-row>
|
|
<v-col cols="12" class="text-center">
|
|
<v-btn
|
|
class="mx-4"
|
|
fab
|
|
dark
|
|
large
|
|
color="primary"
|
|
@click="buttonFunction"
|
|
v-if="interval || voiceDetector || hasTimed"
|
|
>
|
|
<v-icon dark v-if="interval || voiceDetector">
|
|
mdi-stop
|
|
</v-icon>
|
|
<v-icon dark v-else-if="hasTimed">
|
|
mdi-replay
|
|
</v-icon>
|
|
</v-btn>
|
|
<v-dialog
|
|
v-else
|
|
v-model="dialogAudio"
|
|
persistent
|
|
max-width="290"
|
|
>
|
|
<template v-slot:activator="{ on, attrs }">
|
|
<v-btn
|
|
class="mx-4"
|
|
fab
|
|
dark
|
|
large
|
|
color="primary"
|
|
v-bind="attrs"
|
|
v-on="on"
|
|
>
|
|
<v-icon dark>
|
|
mdi-play
|
|
</v-icon>
|
|
</v-btn>
|
|
</template>
|
|
|
|
<v-card>
|
|
<v-card-title class="headline">
|
|
Use audio detection?
|
|
</v-card-title>
|
|
<v-card-text>Trigger start/stop timer through voice level detection.</v-card-text>
|
|
<v-card-actions>
|
|
<v-spacer></v-spacer>
|
|
<v-btn
|
|
color="green darken-1"
|
|
text
|
|
@click="noAudio"
|
|
>
|
|
No
|
|
</v-btn>
|
|
<v-btn
|
|
color="green darken-1"
|
|
text
|
|
@click="useAudio"
|
|
>
|
|
Yes
|
|
</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
</v-col>
|
|
<v-col cols="12" class="text-center" v-if="!interval && hasTimed">
|
|
<v-simple-table class="text-center">
|
|
<template v-slot:default>
|
|
<thead>
|
|
<tr>
|
|
<th>
|
|
Grind level
|
|
</th>
|
|
<th>
|
|
Pre-infusion
|
|
</th>
|
|
<th>
|
|
Total time
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>{{ grindLevel }}</td>
|
|
<td>{{ initialPreinfusionTimer - preinfusionTimer }}</td>
|
|
<td>{{ initialTotalTimer - totalTimer + extraTotalTime }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</template>
|
|
</v-simple-table>
|
|
</v-col>
|
|
<v-col cols="12" class="text-center" v-if="!interval && hasTimed">
|
|
<v-btn
|
|
v-if="hasTimed"
|
|
class="mx-4"
|
|
fab
|
|
dark
|
|
large
|
|
color="primary"
|
|
@click="saveFunction"
|
|
>
|
|
<v-icon dark>
|
|
mdi-content-save
|
|
</v-icon>
|
|
</v-btn>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<v-divider class="my-8"></v-divider>
|
|
|
|
<h2 class="text-h6 text-center">History</h2>
|
|
<v-dialog v-model="dialogDelete" max-width="290">
|
|
<v-card>
|
|
<v-card-title class="headline">Are you sure you want to delete this item?</v-card-title>
|
|
<v-card-actions>
|
|
<v-spacer></v-spacer>
|
|
<v-btn color="blue darken-1" text @click="closeDelete">Cancel</v-btn>
|
|
<v-btn color="blue darken-1" text @click="deleteItemConfirm">OK</v-btn>
|
|
<v-spacer></v-spacer>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
<v-data-table :headers=historyHeaders :items="history">
|
|
<template v-slot:item.actions="{ item }">
|
|
<v-icon
|
|
small
|
|
@click="deleteItem(item)"
|
|
>
|
|
mdi-delete
|
|
</v-icon>
|
|
</template>
|
|
</v-data-table>
|
|
</v-container>
|
|
</v-main>
|
|
</v-app>
|
|
</div>
|
|
<script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script>
|
|
<script src="./bundle.js"></script>
|
|
</body>
|
|
</html>
|