diff --git a/.claude/settings.local.json b/.claude/settings.local.json index ad4896a..b7b994c 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -10,7 +10,14 @@ "Bash(git config:*)", "Bash(git push:*)", "Bash(docker-compose:*)", - "Bash(curl:*)" + "Bash(curl:*)", + "Bash(docker logs:*)", + "Bash(docker exec:*)", + "Bash(python3:*)", + "Bash(npm install)", + "Bash(node:*)", + "Bash(npm install:*)", + "Bash(keytool:*)" ] } } \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b6794d6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +node_modules/ +.env +.claude/ +push-subscriptions.json +*.backup.* +.DS_Store \ No newline at end of file diff --git a/.well-known/assetlinks.json b/.well-known/assetlinks.json new file mode 100644 index 0000000..eb91c74 --- /dev/null +++ b/.well-known/assetlinks.json @@ -0,0 +1,10 @@ +[{ + "relation": ["delegate_permission/common.handle_all_urls"], + "target": { + "namespace": "android_app", + "package_name": "org.duckdns.bibbit.hikemap", + "sha256_cert_fingerprints": [ + "4B:99:EB:12:8C:5C:7B:9B:3C:2F:E5:5C:7A:5D:22:16:7C:A4:8B:28:95:DF:B8:A3:F5:7C:06:92:F0:73:79:36" + ] + } +}] \ No newline at end of file diff --git a/BUILD_APK_INSTRUCTIONS.md b/BUILD_APK_INSTRUCTIONS.md new file mode 100644 index 0000000..6b08d8e --- /dev/null +++ b/BUILD_APK_INSTRUCTIONS.md @@ -0,0 +1,121 @@ +# HikeMap APK Build Instructions + +Your HikeMap PWA is ready to be converted to an APK! Here are three methods to create an installable Android app: + +## Method 1: Online Converter (Easiest - No coding required) + +### Using PWA2APK.com: +1. Visit https://pwa2apk.com +2. Enter your app URL: `https://maps.bibbit.duckdns.org` +3. Click "Start" +4. Fill in the form: + - App Name: HikeMap Trail Navigator + - Short Name: HikeMap + - Package ID: org.duckdns.bibbit.hikemap +5. Click "Generate APK" +6. Download the APK file +7. Share with users - they can install directly! + +### Using PWABuilder.com (Microsoft's Tool): +1. Visit https://www.pwabuilder.com +2. Enter URL: `https://maps.bibbit.duckdns.org` +3. Click "Start" +4. Review the PWA score (should be high!) +5. Click "Package for stores" +6. Select "Android" +7. Download the APK package + +## Method 2: Using Bubblewrap (Advanced - Full control) + +If you want to build locally with full customization: + +```bash +# Install required tools +sudo apt-get install openjdk-11-jdk android-sdk + +# Install Bubblewrap globally +npm install -g @bubblewrap/cli + +# Initialize your TWA project +bubblewrap init --manifest="https://maps.bibbit.duckdns.org/manifest.json" + +# Build the APK +bubblewrap build + +# The APK will be in: app-release-signed.apk +``` + +## Method 3: Android Studio (Most Control) + +1. Download Android Studio +2. Create new project → "Empty Activity" +3. Add TWA (Trusted Web Activity) support +4. Configure `AndroidManifest.xml` with your URL +5. Build → Generate Signed Bundle/APK + +## APK Features + +Your generated APK will have: +- ✅ Full offline support (Service Worker caching) +- ✅ Push notifications +- ✅ GPS location access +- ✅ Camera access (for future features) +- ✅ Install to home screen +- ✅ Runs in fullscreen (no browser UI) +- ✅ Auto-updates from your server + +## Sharing the APK + +Once you have the APK file: + +1. **Direct Install**: Users enable "Install from unknown sources" in Android settings +2. **Email/Message**: Send the APK file directly +3. **Download Link**: Host on your server at `https://maps.bibbit.duckdns.org/hikemap.apk` +4. **QR Code**: Generate QR code linking to the APK + +## Google Play Store (Optional) + +To publish on Play Store: +1. Create Google Play Developer account ($25 one-time fee) +2. Use the AAB (Android App Bundle) format instead of APK +3. Add the assetlinks.json file to your server +4. Submit for review + +## Testing the APK + +Before sharing: +1. Test on multiple Android versions (7.0+) +2. Verify GPS works properly +3. Test push notifications +4. Check offline functionality +5. Ensure all icons display correctly + +## Current Configuration + +Your app is configured with: +- Package ID: `org.duckdns.bibbit.hikemap` +- Version: 1.0.0 +- Min Android: 7.0 (API 24) +- Target Android: Latest +- Orientation: Portrait +- Theme Color: #4CAF50 + +## Troubleshooting + +**"App not installed" error**: +- Enable "Install unknown apps" for your browser +- Uninstall any previous version first + +**Notifications not working**: +- Ensure HTTPS is working +- Check notification permissions in Android settings + +**GPS not working**: +- Grant location permission when prompted +- Check location services are enabled + +--- + +## Quick Start (Recommended) + +For fastest results, use **PWA2APK.com** - it takes about 2 minutes and produces a ready-to-share APK file that your users can install immediately! \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index b74f838..5e31742 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,6 +11,18 @@ RUN npm install # Copy application files COPY server.js ./ COPY index.html ./ +COPY manifest.json ./ +COPY service-worker.js ./ + +# Copy .env file if it exists (for VAPID keys) +COPY .env* ./ + +# Copy PWA icons +COPY icon-*.png ./ + +# Copy .well-known directory for app verification +COPY .well-known ./.well-known + # Copy default.kml if it exists (optional) COPY default.kml* ./ diff --git a/generate-vapid-keys.js b/generate-vapid-keys.js new file mode 100644 index 0000000..7451f40 --- /dev/null +++ b/generate-vapid-keys.js @@ -0,0 +1,13 @@ +const webpush = require('web-push'); + +// Generate VAPID keys +const vapidKeys = webpush.generateVAPIDKeys(); + +console.log('Add these to your .env file:'); +console.log(''); +console.log(`VAPID_PUBLIC_KEY=${vapidKeys.publicKey}`); +console.log(`VAPID_PRIVATE_KEY=${vapidKeys.privateKey}`); +console.log(`VAPID_EMAIL=mailto:admin@maps.bibbit.duckdns.org`); +console.log(''); +console.log('Public key for client-side:'); +console.log(vapidKeys.publicKey); \ No newline at end of file diff --git a/generate_icons.py b/generate_icons.py new file mode 100644 index 0000000..32b8a46 --- /dev/null +++ b/generate_icons.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +""" +Generate PWA icons from SVG or create simple placeholder icons +""" + +from PIL import Image, ImageDraw, ImageFont +import os + +def create_icon(size): + """Create a simple app icon with the specified size.""" + # Create a new image with a green background + img = Image.new('RGBA', (size, size), color='#4CAF50') + draw = ImageDraw.Draw(img) + + # Draw a white mountain shape + mountain_color = 'white' + # Mountain 1 (left) + mountain1 = [ + (size * 0.1, size * 0.7), + (size * 0.35, size * 0.3), + (size * 0.6, size * 0.7) + ] + draw.polygon(mountain1, fill=mountain_color) + + # Mountain 2 (right, slightly overlapping) + mountain2 = [ + (size * 0.4, size * 0.7), + (size * 0.65, size * 0.4), + (size * 0.9, size * 0.7) + ] + draw.polygon(mountain2, fill='#E8F5E9') + + # Draw a location pin at the peak + pin_center = (int(size * 0.65), int(size * 0.4)) + pin_radius = int(size * 0.05) + + # Pin circle + draw.ellipse( + [pin_center[0] - pin_radius, pin_center[1] - pin_radius, + pin_center[0] + pin_radius, pin_center[1] + pin_radius], + fill='#FF5722' + ) + + # Pin point + draw.polygon([ + (pin_center[0] - pin_radius, pin_center[1]), + (pin_center[0] + pin_radius, pin_center[1]), + (pin_center[0], pin_center[1] + pin_radius * 2) + ], fill='#FF5722') + + # Add "HM" text at the bottom + try: + # Try to use a default font, fall back to PIL default if not available + font_size = int(size * 0.15) + font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", font_size) + except: + font = ImageFont.load_default() + + text = "HM" + bbox = draw.textbbox((0, 0), text, font=font) + text_width = bbox[2] - bbox[0] + text_height = bbox[3] - bbox[1] + text_x = (size - text_width) // 2 + text_y = int(size * 0.75) + + draw.text((text_x, text_y), text, fill='white', font=font) + + return img + +# Icon sizes needed for PWA +sizes = [72, 96, 128, 144, 152, 192, 384, 512] + +print("Generating HikeMap PWA icons...") + +for size in sizes: + icon = create_icon(size) + filename = f"icon-{size}x{size}.png" + icon.save(filename, "PNG") + print(f"Created {filename}") + +print("\nAll icons generated successfully!") +print("Icons feature a mountain landscape with location pin design.") \ No newline at end of file diff --git a/geocaches.json b/geocaches.json index cde33bc..b6366f5 100644 --- a/geocaches.json +++ b/geocaches.json @@ -17,5 +17,65 @@ ], "createdAt": 1767115055219, "alerted": true + }, + { + "id": "gc_1767127362829_hbnrs61u2", + "lat": 30.527765731982754, + "lng": -97.83747911453248, + "messages": [ + { + "author": "Dr. Poopinshitz", + "text": "Home is where you poop", + "timestamp": 1767127384562 + }, + { + "author": "Riker", + "text": "I poop here too", + "timestamp": 1767132954284 + }, + { + "author": "Sulu", + "text": "I poop outside weirdos.", + "timestamp": 1767132973928 + }, + { + "author": "Ibby Dibby", + "text": "CAN I EAT IT?", + "timestamp": 1767133040824 + }, + { + "author": "Riker", + "text": "Stupid little cousin ibby dibby...", + "timestamp": 1767133204544 + } + ], + "createdAt": 1767127362829, + "alerted": true + }, + { + "id": "gc_1767133043404_9zkbxphry", + "lat": 30.52230723615832, + "lng": -97.82822817564012, + "messages": [ + { + "author": "Georges Evil Twin.", + "text": "I'm going to lick all the raw chicken.", + "timestamp": 1767133083657 + } + ], + "createdAt": 1767133043404 + }, + { + "id": "gc_1767140463979_69hvt9x5v", + "lat": 30.489440035930812, + "lng": -97.80640304088594, + "messages": [ + { + "author": "Riker", + "text": "Why are their kids on my laser pointer field!?", + "timestamp": 1767140488863 + } + ], + "createdAt": 1767140463979 } ] \ No newline at end of file diff --git a/icon-128x128.png b/icon-128x128.png new file mode 100644 index 0000000..5ad25d3 Binary files /dev/null and b/icon-128x128.png differ diff --git a/icon-144x144.png b/icon-144x144.png new file mode 100644 index 0000000..9ff4202 Binary files /dev/null and b/icon-144x144.png differ diff --git a/icon-152x152.png b/icon-152x152.png new file mode 100644 index 0000000..01c2b0f Binary files /dev/null and b/icon-152x152.png differ diff --git a/icon-192x192.png b/icon-192x192.png new file mode 100644 index 0000000..72a48b1 Binary files /dev/null and b/icon-192x192.png differ diff --git a/icon-384x384.png b/icon-384x384.png new file mode 100644 index 0000000..87ba8b1 Binary files /dev/null and b/icon-384x384.png differ diff --git a/icon-512x512.png b/icon-512x512.png new file mode 100644 index 0000000..6be6afb Binary files /dev/null and b/icon-512x512.png differ diff --git a/icon-72x72.png b/icon-72x72.png new file mode 100644 index 0000000..e102e99 Binary files /dev/null and b/icon-72x72.png differ diff --git a/icon-96x96.png b/icon-96x96.png new file mode 100644 index 0000000..b624e88 Binary files /dev/null and b/icon-96x96.png differ diff --git a/index.html b/index.html index c160fec..29e9fad 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,30 @@ - KML Track Editor + HikeMap Trail Navigator + + + + + + + + + + + + + + + + + + + + + + +