Calculator v1.6: round-screen keypad with arithmetic
- 19-key layout fitted to round display, centered focus, scrollable list - full arithmetic: +-*/ %, decimals, +/- , AC, divide-by-zero, chained ops - scroll-to-center focus with top/bottom spacers, high-contrast keys - tests: arithmetic + geometry/contrast
This commit is contained in:
+10
@@ -0,0 +1,10 @@
|
||||
<script>
|
||||
export default {
|
||||
onCreate() {
|
||||
console.log('Hello Vela app created')
|
||||
},
|
||||
onDestroy() {
|
||||
console.log('Hello Vela app destroyed')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="192" height="192" viewBox="0 0 192 192">
|
||||
<rect width="192" height="192" rx="48" fill="#ff6900"/>
|
||||
<text x="96" y="116" text-anchor="middle" font-family="DejaVu Sans, sans-serif" font-size="72" font-weight="700" fill="#ffffff">Hi</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 293 B |
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"package": "com.example.hellovela",
|
||||
"name": "Calc",
|
||||
"icon": "/common/icon.png",
|
||||
"versionName": "1.6",
|
||||
"versionCode": 7,
|
||||
"minAPILevel": 1,
|
||||
"deviceTypeList": [
|
||||
"watch"
|
||||
],
|
||||
"config": {
|
||||
"logLevel": "debug",
|
||||
"designWidth": 480
|
||||
},
|
||||
"router": {
|
||||
"entry": "pages/index",
|
||||
"pages": {
|
||||
"pages/index": {
|
||||
"component": "index",
|
||||
"path": "/"
|
||||
}
|
||||
}
|
||||
},
|
||||
"display": {
|
||||
"backgroundColor": "#000000"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<text class="display" style="font-size: {{displaySize}}px">{{ display }}</text>
|
||||
<list class="keys" id="keys" onscroll="onScroll">
|
||||
<list-item type="pad" class="pad top"></list-item>
|
||||
<list-item type="key" class="item {{ $idx === focused ? 'focused' : '' }}" for="{{ keys }}" onclick="confirmKey">
|
||||
<text class="keylabel" style="color: {{ $idx === focused ? '#000000' : '#ffffff' }}">{{ $item.label }}</text>
|
||||
</list-item>
|
||||
<list-item type="pad" class="pad bottom"></list-item>
|
||||
</list>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
private: {
|
||||
display: '0',
|
||||
focused: 0,
|
||||
keys: []
|
||||
},
|
||||
computed: {
|
||||
displaySize() {
|
||||
return this.display.length > 9 ? 38 : this.display.length > 7 ? 46 : 52
|
||||
}
|
||||
},
|
||||
onInit() {
|
||||
const labels = ['AC','+/-','%','/','7','8','9','x','4','5','6','-','1','2','3','+','0','.','=']
|
||||
this.keys = labels.map(l => ({ label: l }))
|
||||
this.ITEM_H = 54
|
||||
this.KEYS_H = 300
|
||||
this.PAD = this.KEYS_H / 2 - this.ITEM_H / 2 // 123px spacers so first/last item can center
|
||||
},
|
||||
onScroll(e) {
|
||||
// focused item = the one centered in the list's viewport (spacers included in offset)
|
||||
const idx = Math.round((e.scrollY + this.KEYS_H / 2 - this.ITEM_H / 2 - this.PAD) / this.ITEM_H)
|
||||
this.focused = Math.max(0, Math.min(this.keys.length - 1, idx))
|
||||
},
|
||||
confirmKey() {
|
||||
if (!this.keys.length) return
|
||||
this.press(this.keys[this.focused].label)
|
||||
},
|
||||
press(key) {
|
||||
if (key === '+') { this.stored = Number(this.display); this.op = '+'; this.fresh = true }
|
||||
else if (key === '-') { this.stored = Number(this.display); this.op = '-'; this.fresh = true }
|
||||
else if (key === 'x') { this.stored = Number(this.display); this.op = 'x'; this.fresh = true }
|
||||
else if (key === '/') { this.stored = Number(this.display); this.op = '/'; this.fresh = true }
|
||||
else if (key === '=') {
|
||||
const b = Number(this.display)
|
||||
let r = 0
|
||||
if (this.op === '+') r = this.stored + b
|
||||
else if (this.op === '-') r = this.stored - b
|
||||
else if (this.op === 'x') r = this.stored * b
|
||||
else if (this.op === '/') r = b === 0 ? NaN : this.stored / b
|
||||
this.display = Number.isFinite(r) ? String(Math.round(r * 1e9) / 1e9) : 'Error'
|
||||
this.fresh = true
|
||||
}
|
||||
else if (key === 'AC') { this.display = '0'; this.stored = 0; this.op = ''; this.fresh = true }
|
||||
else if (key === '+/-') { this.display = this.display.startsWith('-') ? this.display.slice(1) : '-' + this.display }
|
||||
else if (key === '%') { this.display = String(Number(this.display) / 100) }
|
||||
else if (key === '.') { if (this.fresh) { this.display = '0.'; this.fresh = false } else if (!this.display.includes('.')) this.display += '.' }
|
||||
else {
|
||||
if (this.fresh) { this.display = key; this.fresh = false }
|
||||
else if (this.display.replace(/[-.]/g,'').length < 9) this.display += key
|
||||
}
|
||||
// keep the focused item visually centered after each press
|
||||
const el = this.$element('keys')
|
||||
el && el.scrollTo({
|
||||
top: this.PAD + this.focused * this.ITEM_H - this.KEYS_H / 2 + this.ITEM_H / 2,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
},
|
||||
onBackPress() {
|
||||
this.confirmKey()
|
||||
return true
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.page {
|
||||
width: 480px; height: 480px;
|
||||
background-color: #000000;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.display {
|
||||
width: 340px; height: 70px;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
}
|
||||
.keys {
|
||||
width: 320px; height: 300px;
|
||||
}
|
||||
.item {
|
||||
width: 300px; height: 54px;
|
||||
justify-content: center; align-items: center;
|
||||
border-radius: 27px;
|
||||
background-color: #3a3a3e;
|
||||
}
|
||||
.focused {
|
||||
background-color: #f3a633;
|
||||
}
|
||||
.pad {
|
||||
height: 123px;
|
||||
}
|
||||
.keylabel {
|
||||
font-size: 34px; text-align: center;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user