Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 64 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# Countdown App для Zepp OS
# Countdown Timer для Zepp OS

Современное и настраиваемое приложение обратного отсчета для умных часов на базе Zepp OS. Позволяет отслеживать время до любого важного события.
Универсальное приложение обратного отсчёта для умных часов на базе Zepp OS 3.0. Отслеживайте время до любого важного события — дня рождения, Нового года, дедлайна, поездки и многого другого.

![MIT License](https://img.shields.io/badge/License-MIT-blue.svg)
![Zepp OS](https://img.shields.io/badge/Zepp_OS-3.0-green.svg)
![Version](https://img.shields.io/badge/Version-2.0.0-blue.svg)

## 🖼️ Скриншоты

Expand All @@ -12,25 +14,43 @@

## ✨ Возможности

- **Точный обратный отсчет**: Отсчитывает дни, часы, минуты и секунды до указанной даты.
- **Современный дизайн**: Чистый и минималистичный интерфейс с белыми цифрами на черном фоне.
- **Настраиваемая дата**: Легко установите любую целевую дату и время через интуитивное меню настроек.
- **Сохранение состояния**: Приложение запоминает установленную дату даже после закрытия.
- **Цветовая индикация**: Цифры меняют цвет на красный, когда до события остается менее 5 минут.
- **Open Source**: Проект полностью открыт для доработок и улучшений.
- **Точный обратный отсчёт**: Дни, часы, минуты и секунды до указанной даты в реальном времени.
- **Название события**: Выбирайте тип события — День рождения, Новый год, Дедлайн, Экзамен, Свадьба и другие.
- **Быстрые пресеты**: Установка цели в одно касание — через 1 час, 1 день, 1 неделю или на Новый год.
- **Адаптивный дизайн**: Автоматическая адаптация под размер экрана любого устройства.
- **Цветовая индикация**: Зелёный → оранжевый → красный по мере приближения события.
- **Уведомление о завершении**: Toast-уведомление при истечении времени.
- **Многоязычность**: Поддержка русского и английского языков.
- **Сохранение состояния**: Приложение запоминает настройки после закрытия.

## ⌚ Поддерживаемые устройства

### Круглые экраны
| Размер экрана | Устройства |
| :---: | :--- |
| 480×480 | Amazfit GTR 4, GTR 3 Pro, T-Rex Ultra, Falcon |
| 466×466 | Amazfit GTR 3 |
| 454×454 | Amazfit GTR 4 Mini, GTR Mini |
| 416×416 | Amazfit T-Rex 2, T-Rex Pro |

### Квадратные экраны
| Размер экрана | Устройства |
| :---: | :--- |
| 390×450 | Amazfit GTS 4, Active |
| 336×384 | Amazfit GTS 4 Mini, Bip 5 |

## 🛠️ Установка и настройка

### Требования

- [Zeus CLI](https://developer.zepp.com/docs/zeus/cli/) - инструмент для разработки под Zepp OS.
- [Zeus CLI](https://developer.zepp.com/docs/zeus/cli/) инструмент для разработки под Zepp OS.
- Node.js (версия 14 или выше).

### Установка

1. **Клонируйте репозиторий:**
```bash
git clone https://github.com/your-username/countdown-app.git
git clone https://github.com/DmitryKolyadin/countdown-app.git
cd countdown-app
```

Expand All @@ -43,8 +63,6 @@

### Запуск в эмуляторе

Для запуска приложения в эмуляторе с автоматической перезагрузкой при изменениях в коде выполните:

```bash
zeus dev
```
Expand All @@ -61,42 +79,59 @@ zeus dev
zeus preview
```

3. **Отсканируйте QR-код** в приложении Zepp на вашем смартфоне, чтобы установить приложение на часы.
3. **Отсканируйте QR-код** в приложении Zepp на смартфоне.

### Сборка проекта

Для сборки установочного пакета `.zab` выполните:

```bash
zeus build
```

Готовый файл будет находиться в папке `dist/`.
Готовый файл `.zab` будет в папке `dist/`.

## 📂 Структура проекта

```
countdown-app/
├── LICENSE # Файл лицензии MIT
├── app.js # Главный файл приложения
├── app.json # Конфигурация приложения
├── app.json # Конфигурация (устройства, разрешения, i18n)
├── package.json # Зависимости и скрипты
├── README.md # Документация
├── page/
│ └── index.js # Код главного экрана (таймер)
└── setting/
└── index.js # Код экрана настроек
│ ├── index.js # Главный экран (таймер обратного отсчёта)
│ └── i18n/
│ ├── en-US.po # Английская локализация
│ └── ru-RU.po # Русская локализация
├── setting/
│ ├── index.js # Экран настроек (событие, дата, пресеты)
│ └── i18n/
│ ├── en-US.po # Английская локализация
│ └── ru-RU.po # Русская локализация
├── app-side/
│ ├── index.js # Фоновый сервис
│ └── i18n/
│ ├── en-US.po
│ └── ru-RU.po
├── utils/ # Утилиты (дата/время)
├── constants/ # Константы приложения
├── assets/ # Иконки приложения
└── docs/ # Скриншоты
```

## 🤝 Участие в разработке
## 🆕 Что нового в версии 2.0

Мы приветствуем любой вклад в развитие проекта! Если у вас есть идеи по улучшению или вы нашли ошибку, пожалуйста, следуйте этим шагам:
- **Поддержка 6 типов экранов** — круглые (480, 466, 454, 416) и квадратные (390, 336)
- **Название события** — выбор из 10 предустановленных категорий
- **Быстрые пресеты** — +1 час, +1 день, +1 неделя, Новый год
- **Русский язык** — полная локализация интерфейса
- **Адаптивная вёрстка** — UI масштабируется под любой экран
- **Трёхуровневая индикация** — зелёный/оранжевый/красный статус
- **Уведомление о завершении** — Toast-уведомление при достижении цели
- **Загрузка сохранённых настроек** — настройки загружаются при открытии

## 🤝 Участие в разработке

1. Сделайте форк репозитория.
2. Создайте новую ветку (`git checkout -b feature/your-feature`).
3. Внесите свои изменения.
4. Создайте Pull Request.
Мы приветствуем любой вклад! Создайте форк, внесите изменения и отправьте Pull Request.

## 📄 Лицензия

Этот проект распространяется под лицензией MIT. Подробности смотрите в файле [LICENSE](LICENSE).
Проект распространяется под лицензией MIT. Подробности в файле [LICENSE](LICENSE).
5 changes: 1 addition & 4 deletions app-side/i18n/en-US.po
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,4 @@ msgid "app_started"
msgstr "CountdownApp Started"

msgid "app_destroyed"
msgstr "CountdownApp Destroyed"

msgid "example"
msgstr "This is an example in app-side"
msgstr "CountdownApp Destroyed"
5 changes: 5 additions & 0 deletions app-side/i18n/ru-RU.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
msgid "app_started"
msgstr "CountdownApp запущен"

msgid "app_destroyed"
msgstr "CountdownApp завершён"
184 changes: 3 additions & 181 deletions app-side/index.js
Original file line number Diff line number Diff line change
@@ -1,191 +1,13 @@
import { gettext } from 'i18n'

AppSideService({
globalData: {
targetTimestamp: null,
missionCode: 'OPERATION COUNTDOWN',
agentId: null,
lastSync: null
},

onInit() {
console.log('[SPY-SYSTEM] CountdownApp initialized')
this.initializeMission()
this.loadSettings()
console.log('CountdownApp service initialized')
},

onRun() {
console.log('[SPY-SYSTEM] Mission commenced')
this.syncMissionData()
console.log('CountdownApp service running')
},

onDestroy() {
console.log('[SPY-SYSTEM] Mission terminated')
this.saveSettings()
},

initializeMission() {
// Генерируем ID агента если его нет
if (!this.globalData.agentId) {
this.globalData.agentId = this.generateAgentId()
}

// Генерируем код миссии
this.globalData.missionCode = this.generateMissionCode()

console.log(`[SPY-SYSTEM] Agent ${this.globalData.agentId} assigned to ${this.globalData.missionCode}`)
},

generateAgentId() {
const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
const numbers = '0123456789'

let agentId = 'AGENT-'

// Добавляем 2 буквы
for (let i = 0; i < 2; i++) {
agentId += letters[Math.floor(Math.random() * letters.length)]
}

agentId += '-'

// Добавляем 3 цифры
for (let i = 0; i < 3; i++) {
agentId += numbers[Math.floor(Math.random() * numbers.length)]
}

return agentId
},

generateMissionCode() {
const operations = [
'OPERATION COUNTDOWN',
'MISSION CRITICAL',
'PROJECT OMEGA',
'ALPHA ZERO',
'CODE CRIMSON',
'OPERATION PHOENIX'
]

return operations[Math.floor(Math.random() * operations.length)]
},

syncMissionData() {
this.globalData.lastSync = Date.now()
console.log('[SPY-SYSTEM] Mission data synchronized')
},

loadSettings() {
// Загружаем сохраненные настройки из локального хранилища
try {
const savedTimestamp = this.getStorageSync('targetTimestamp')
const savedAgentId = this.getStorageSync('agentId')
const savedMissionCode = this.getStorageSync('missionCode')

if (savedTimestamp) {
this.globalData.targetTimestamp = parseInt(savedTimestamp)
console.log('[SPY-SYSTEM] Target timestamp loaded')
}

if (savedAgentId) {
this.globalData.agentId = savedAgentId
}

if (savedMissionCode) {
this.globalData.missionCode = savedMissionCode
}

} catch (error) {
console.log('[SPY-SYSTEM] Error loading mission data:', error)
}
},

saveSettings() {
// Сохраняем настройки в локальное хранилище
try {
if (this.globalData.targetTimestamp) {
this.setStorageSync('targetTimestamp', this.globalData.targetTimestamp.toString())
}

if (this.globalData.agentId) {
this.setStorageSync('agentId', this.globalData.agentId)
}

if (this.globalData.missionCode) {
this.setStorageSync('missionCode', this.globalData.missionCode)
}

console.log('[SPY-SYSTEM] Mission data saved')

} catch (error) {
console.log('[SPY-SYSTEM] Error saving mission data:', error)
}
},

getGlobalData(key) {
return this.globalData[key]
},

setGlobalData(key, value) {
this.globalData[key] = value

// Автоматически сохраняем критичные данные
if (key === 'targetTimestamp') {
try {
this.setStorageSync('targetTimestamp', value.toString())
console.log('[SPY-SYSTEM] Target updated and saved')
} catch (error) {
console.log('[SPY-SYSTEM] Error auto-saving target:', error)
}
}
},

// Проверка статуса миссии
getMissionStatus() {
if (!this.globalData.targetTimestamp) {
return 'STANDBY'
}

const now = Date.now()
const diff = this.globalData.targetTimestamp - now
const minutes = Math.floor(diff / (1000 * 60))

if (diff <= 0) {
return 'COMPLETE'
} else if (minutes <= 5) {
return 'CRITICAL'
} else if (minutes <= 60) {
return 'WARNING'
} else {
return 'ACTIVE'
}
},

// Генерация отчета о миссии
generateMissionReport() {
const status = this.getMissionStatus()
const timeRemaining = this.globalData.targetTimestamp ?
this.globalData.targetTimestamp - Date.now() : 0

return {
agentId: this.globalData.agentId,
missionCode: this.globalData.missionCode,
status: status,
timeRemaining: timeRemaining,
lastSync: this.globalData.lastSync,
timestamp: Date.now()
}
},

// Заглушки для методов хранилища (в реальном приложении используйте API Zepp OS)
getStorageSync(key) {
// В реальном приложении здесь будет вызов API хранилища
// Например: hmFS.SysProGetString(key)
return null
},

setStorageSync(key, value) {
// В реальном приложении здесь будет вызов API хранилища
// Например: hmFS.SysProSetString(key, value)
console.log('CountdownApp service destroyed')
}
})
Loading