GPS point ordering + GPX export + chart zoom fixes

GPS background recording:
- Batched writes (10s flush) in native service
- Polling lock prevents parallel processing
- Track by timestamp instead of line count
- Recovery idempotent via max DB timestamp
- Seq numbers on live recorded points

GPX export:
- Button in session detail
- SAF file picker on Android (ACTION_CREATE_DOCUMENT)
- GPS config in metadata (accuracy, minSpeed, minDist)

Charts:
- Pinch zoom enabled at creation (Hammer.js registers handlers)
- touch-action: pan-y blocks pinch in normal view (page scrolls)
- Fullscreen: CSS-only expand (no canvas manipulation)
- Downsampled to 500 points for smooth rendering
- Back gesture collapses fullscreen before closing modal

Build: --real flag finds first non-emulator device
This commit is contained in:
4aiman 2026-05-16 21:21:13 +03:00
commit b26264538b
20 changed files with 4234 additions and 37 deletions

339
data.js Normal file
View file

@ -0,0 +1,339 @@
const DATA = {
profile: {
height_cm: 178,
birth_year: 1988,
sex: "m",
bmr_formula: 1800,
bmr_estimated: 1580
},
days: [
// ===== 03.04 =====
{
date: "2026-04-03",
weights: [{ time: null, kg: 88.7 }],
sleep: { bed: "23:00", asleep: "23:40", wake: "09:00" },
food: [],
activity: [],
water: 0,
notes: ""
},
// ===== 04.04 =====
{
date: "2026-04-04",
weights: [
{ time: "10:39", kg: 88.7 },
{ time: "12:49", kg: 88.7 },
{ time: "17:44", kg: 87.8 }
],
sleep: { bed: "23:10", asleep: "23:39", wake: "08:30" },
food: [
{ time: "10:50", desc: "чай с сахаром", kcal: 20 },
{ time: "12:34", desc: "чай, булочка 40г, хачапури с сыром 100г (неслоёное тесто)", kcal: 390 },
{ time: "18:00", desc: "салат (капуста, огурец, подсолнечное масло), редиска, чай с сахаром, хлеб", kcal: 295 },
{ time: "19:20", desc: "чай, охотничьи колбаски 50г", kcal: 180 }
],
activity: [
{ time: "11:00", desc: "поход за продуктами (нёс 10кг половину пути)", minutes: 68, kcal: 300 },
{ time: "14:19", desc: "раскройка/распил ДВП, пробивание к стенке", minutes: 100, kcal: 350 },
{ time: "16:00", desc: "починка рулетки", minutes: 20, kcal: 30 },
{ time: "16:30", desc: "распил брусков 4x4", minutes: 74, kcal: 250 },
{ time: "18:40", desc: "прогулка", minutes: 40, kcal: 175 }
],
water: 3,
notes: "головная боль вечером (тупая давящая в лобных долях), жажда"
},
// ===== 05.04 =====
{
date: "2026-04-05",
weights: [
{ time: "10:35", kg: 88.1 },
{ time: "21:00", kg: 88.9 }
],
sleep: { bed: null, asleep: "01:40", wake: "08:45", nap_minutes: 150 },
food: [
{ time: "10:40", desc: "салат (капуста, огурцы, редиска), 0.6л чая с сахаром", kcal: 120 },
{ time: "16:10", desc: "чай, карамельный попкорн 60г, творог со сметаной/сахаром/колбасой", kcal: 640 },
{ time: "21:00", desc: "чай, попкорн, редис", kcal: 150 }
],
activity: [
{ time: "12:00", desc: "сборка каркаса шкафа (саморезы, уголки, брусья), перенос 2300x860x518", minutes: 240, kcal: 600 },
{ time: "20:20", desc: "зарядка", minutes: 20, kcal: 100 }
],
water: 0,
notes: "тяжесть в голове с утра (проснулся с болью), после стройки и дневного сна прошло"
},
// ===== 06.04 =====
{
date: "2026-04-06",
weights: [
{ time: "14:30", kg: 87.1 },
{ time: null, kg: 88.9 }
],
sleep: { bed: null, asleep: null, wake: "09:20" },
food: [
{ time: "12:30", desc: "пирожок бездрожжевой с капустой, сметана, чай с 1 ч.л. сахара", kcal: 320 },
{ time: "14:30", desc: "чай", kcal: 20 },
{ time: "14:35", desc: "6 редисок, кусочек жареной курицы", kcal: 170 },
{ time: "14:40", desc: "ещё 100г курицы", kcal: 200 },
{ time: null, desc: "стакан молока 200мл", kcal: 106 },
{ time: "18:30", desc: "картошка 100г жареная в масле, 2 огурца свежих", kcal: 220 },
{ time: "18:30", desc: "чай с сахаром ~700мл", kcal: 80 }
],
activity: [
{ time: "12:55", desc: "велосипед (отвёз ребёнка + круг, ~10км, пробил колесо)", minutes: 50, kcal: 350 },
{ time: "13:55", desc: "пешком с 10кг воды и великом", minutes: 17, kcal: 100 },
{ time: "14:12", desc: "затащил воду и велик на 5 этаж", minutes: 3, kcal: 50 }
],
water: 0,
notes: ""
},
// ===== 07.04 =====
{
date: "2026-04-07",
weights: [{ time: "12:55", kg: 88.3 }],
sleep: { bed: null, asleep: "00:00", wake: "09:20" },
food: [
{ time: "10:00", desc: "гречка с молоком и сахаром (дес. ложка), ел час", kcal: 370 },
{ time: "12:30", desc: "творог со сметаной и сахаром", kcal: 280 },
{ time: "16:00", desc: "кружка чая с 2 ч.л. сахара", kcal: 40 },
{ time: "17:50", desc: "100г сметаны, пирожок с тушёной капустой", kcal: 460 },
{ time: "18:40", desc: "чай с сахаром, банан", kcal: 150 },
{ time: "20:00", desc: "35г колбасок", kcal: 115 },
{ time: "23:00", desc: "чай с сахаром", kcal: 40 }
],
activity: [
{ time: "13:20", desc: "прогулка", minutes: 30, kcal: 130 }
],
water: 2,
notes: "удалёнка IT, витамины"
},
// ===== 08.04 =====
{
date: "2026-04-08",
weights: [{ time: "19:30", kg: 88.3 }],
sleep: { bed: "22:30", asleep: "22:30", wake: "09:20" },
food: [
{ time: "10:30", desc: "творог 180г с сахаром, сметаной и колбасками 35г", kcal: 430 },
{ time: "14:00", desc: "пол литра молока", kcal: 275 },
{ time: "17:00", desc: "40г жареного арахиса", kcal: 235 },
{ time: "19:30", desc: "гречка с молоком и сахаром, 150г батона, 350мл чая", kcal: 785 }
],
activity: [
{ time: "12:40", desc: "прогулка", minutes: 50, kcal: 220 },
{ time: "18:30", desc: "прогулка", minutes: 60, kcal: 260 }
],
water: 0,
notes: "утром полудрёма 08:20-08:40. Ночью будили, поднялись ЧСС и давление, не мог спать до 03:23"
},
// ===== 09.04 =====
{
date: "2026-04-09",
weights: [],
sleep: { bed: null, asleep: null, wake: "09:20", nap_minutes: 25 },
food: [
{ time: "11:30", desc: "гречка с молоком и сахаром (дес. ложка)", kcal: 370 },
{ time: "12:40", desc: "100г варёной картошки, 4 шпротинки, 50г салата (капуста, зелень, масло)", kcal: 170 },
{ time: "14:20", desc: "40г жареного арахиса", kcal: 235 },
{ time: "20:00", desc: "сырный багет 200г, 2 яйца глазунья, чай 600мл", kcal: 850 },
{ time: "20:15", desc: "15г морковки", kcal: 5 }
],
activity: [
{ time: "18:50", desc: "прогулка + магазин", minutes: 50, kcal: 220 }
],
water: 2,
notes: ""
},
// ===== 10.04 =====
{
date: "2026-04-10",
weights: [{ time: "17:30", kg: 87.7 }],
sleep: { bed: "01:24", asleep: "01:24", wake: "09:30" },
food: [
{ time: "10:20", desc: "50г творога со сметаной и сахаром", kcal: 110 },
{ time: "12:10", desc: "150г пюре, 120г творога со сметаной/сахаром, 50г морковки со сметаной/чесноком", kcal: 420 },
{ time: "13:32", desc: "чай с сахаром 220мл", kcal: 25 },
{ time: "17:20", desc: "2 чашки чая, 30г плавленного сыра, 3 кусочка батона", kcal: 320 },
{ time: "18:00", desc: "60г колбасок (в прогулке)", kcal: 195 },
{ time: "20:30", desc: "картошка, макароны, яйцо глазунья, 4 кусочка батона (250г всего)", kcal: 420 },
{ time: "22:00", desc: "чай", kcal: 40 }
],
activity: [
{ time: "14:30", desc: "замена покрышки и камеры на велике", minutes: 20, kcal: 50 },
{ time: "16:05", desc: "прогулка", minutes: 60, kcal: 260 },
{ time: "18:00", desc: "прогулка, магазины", minutes: 120, kcal: 520 }
],
water: 0,
notes: "витамины, омега, железо"
},
// ===== 11.04 =====
{
date: "2026-04-11",
weights: [],
sleep: { bed: null, asleep: "01:07", wake: "09:00" },
food: [
{ time: "10:30", desc: "чай, 30г протеинового батончика, витамины, железо, омега", kcal: 120 },
{ time: "12:00", desc: "150г сырного багета, чай", kcal: 475 },
{ time: "15:00", desc: "30г протеинового батончика", kcal: 80 },
{ time: "20:00", desc: "картошка, горошек, 15г колбасок, 2 чая", kcal: 320 }
],
activity: [
{ time: "11:00", desc: "прогулка", minutes: 60, kcal: 260 },
{ time: "13:30", desc: "велосипед 10+ км", minutes: 70, kcal: 400 },
{ time: "14:50", desc: "подъём велика на 5 этаж", minutes: 3, kcal: 50 }
],
water: 0,
notes: "ванна 15:30-16:50"
},
// ===== 12.04 =====
{
date: "2026-04-12",
weights: [{ time: null, kg: 88.7 }],
sleep: { bed: null, asleep: null, wake: "09:00" },
food: [
{ time: "11:00", desc: "пюре 200г, сметана, 5 песочных печенек домашних", kcal: 560 },
{ time: "14:00", desc: "2 чая, 2 протеиновых батончика по 30г (80ккал)", kcal: 240 },
{ time: "18:00", desc: "100г кулича без изюма", kcal: 320 },
{ time: "20:00", desc: "пюре 150г, горошек 100г, 20г колбасок, 2 чая, 150г кулича", kcal: 845 }
],
activity: [
{ time: "10:00", desc: "зарядка", minutes: 20, kcal: 80 },
{ time: "16:50", desc: "прогулка", minutes: 40, kcal: 175 },
{ time: "18:00", desc: "зарядка", minutes: 15, kcal: 60 }
],
water: 0,
notes: ""
},
// ===== 13.04 =====
{
date: "2026-04-13",
weights: [{ time: null, kg: 88.7 }],
sleep: { bed: null, asleep: "22:14", wake: "09:20" },
food: [
{ time: "11:00", desc: "300г молока", kcal: 165 },
{ time: "12:30", desc: "150г молока, 200г кулича, протеиновый батончик 30г", kcal: 803 },
{ time: "19:20", desc: "творог+сметана, пирожное (бисквит+масло) 70г, 2 чая, 6 кусочков колбасы, 5 кусочков батона", kcal: 965 }
],
activity: [
{ time: "12:50", desc: "велосипед", minutes: 65, kcal: 400 },
{ time: "14:00", desc: "подъём велика на 5 этаж, душ", minutes: 5, kcal: 50 },
{ time: "18:00", desc: "прогулка + магазин", minutes: 60, kcal: 260 }
],
water: 0,
notes: ""
},
// ===== 14.04 =====
{
date: "2026-04-14",
weights: [{ time: null, kg: 87.8 }],
sleep: { bed: null, asleep: null, wake: "09:20" },
food: [
{ time: "10:20", desc: "яблоко 200г, молоко 350мл, протеиновый батончик", kcal: 367 },
{ time: null, desc: "творог 200г со сметаной, 4 кружки чая, колбаса 50г", kcal: 610 },
{ time: null, desc: "лапша б/п (без бульона), 3 кусочка хлеба с плавленным сыром", kcal: 590 }
],
activity: [],
water: 0,
notes: ""
},
// ===== 15.04 =====
{
date: "2026-04-15",
weights: [],
sleep: { bed: "02:30", asleep: "02:30", wake: "09:20" },
food: [
{ time: "10:30", desc: "протеиновый батончик, 350мл молока", kcal: 273 },
{ time: "13:20", desc: "гречка с молоком, чай, витамины, омега", kcal: 410 },
{ time: "19:00", desc: "чай, домашние вафли с цукатами", kcal: 390 }
],
activity: [
{ time: "17:40", desc: "велосипед 10км", minutes: 50, kcal: 350 }
],
water: 0,
notes: "кодинг до 02:30"
},
// ===== 16.04 =====
{
date: "2026-04-16",
weights: [],
sleep: { bed: "22:40", asleep: "22:40", wake: null },
food: [
{ time: "10:30", desc: "протеиновый батончик, 350мл молока", kcal: 273 },
{ time: "12:40", desc: "макароны с сыром, домашняя вафля", kcal: 500 },
{ time: "13:30", desc: "чай 350мл", kcal: 40 },
{ time: "20:00", desc: "гречка с молоком, чай, плавленый сыр 90г, 15шт арахиса", kcal: 750 }
],
activity: [
{ time: "19:00", desc: "прогулка", minutes: 40, kcal: 175 }
],
water: 0,
notes: ""
},
// ===== 17.04 =====
{
date: "2026-04-17",
weights: [{ time: null, kg: 87.6 }],
sleep: { bed: null, asleep: null, wake: null, nap_minutes: 30 },
food: [
{ time: "10:30", desc: "арахис 30г, молоко", kcal: 286 },
{ time: "12:30", desc: "картошка, маринованный перец (испорчен)", kcal: 145 },
{ time: "20:20", desc: "пломбир в шоколаде с орехами 65г, чай", kcal: 235 }
],
activity: [
{ time: "16:10", desc: "прогулка", minutes: 60, kcal: 260 },
{ time: "18:50", desc: "прогулка", minutes: 30, kcal: 130 }
],
water: 0,
notes: "отравление маринованным перцем, пронесло в 16:00 и 17:10"
},
// ===== 18.04 =====
{
date: "2026-04-18",
weights: [],
sleep: { bed: "22:00", asleep: "22:00", wake: "08:40" },
food: [
{ time: null, desc: "2 огурца, немного сушек, яблоко, 2 кружки чая (весь день)", kcal: 350 }
],
activity: [],
water: 1,
notes: "температура 36.8-37.0, много спал, собака воет за стенкой 9-21, стресс, болит голова от лежания и недостатка еды. Ночью проснулся в 02:30, комп до 04:30, затем сон"
},
// ===== 19.04 =====
{
date: "2026-04-19",
weights: [{ time: null, kg: 86.7 }],
sleep: { bed: null, asleep: "00:00", wake: "09:20" },
food: [
{ time: null, desc: "огурец, десяток редисок, творог со сметаной и сахаром, много чая, газировка 0.5л, жареная курица в специях", kcal: 845 }
],
activity: [
{ time: null, desc: "прогулка", minutes: 30, kcal: 130 },
{ time: null, desc: "распил ХДФ лобзиком, сборка рамы шкафа", minutes: 60, kcal: 200 },
{ time: null, desc: "зарядка", minutes: 20, kcal: 80 }
],
water: 0,
notes: "тело тяжёлое, много лежал"
},
// ===== 20.04 =====
{
date: "2026-04-20",
weights: [{ time: null, kg: 87.0 }],
sleep: { bed: null, asleep: null, wake: "09:20" },
food: [
{ time: "10:00", desc: "чай", kcal: 40 }
],
activity: [],
water: 0,
notes: "неполные данные"
},
// ===== 27.04 =====
{
date: "2026-04-27",
weights: [{ time: null, kg: 88.0 }],
sleep: { bed: null, asleep: null, wake: null },
food: [],
activity: [],
water: 0,
notes: "только вес (был 86.7, поел много)"
}
]
};