remove android application, will try later
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Juan José Gutiérrez de Quevedo Pérez 2025-11-25 17:47:59 +01:00
parent b907866c85
commit d1f8d1dc35
25 changed files with 0 additions and 3158 deletions

View file

@ -11,27 +11,3 @@ steps:
tags: tags:
- latest - latest
- ${DRONE_COMMIT_SHA:0:7} - ${DRONE_COMMIT_SHA:0:7}
- name: build-debug
image: cirrusci/android-sdk:33
commands:
- cd MathHomeworkHelper
- echo "Building Debug APK..."
- gradle clean assembleDebug
- echo "Debug APK built successfully!"
- name: build-release
image: cirrusci/android-sdk:33
commands:
- cd MathHomeworkHelper
- echo "Building Release APK..."
- gradle clean assembleRelease
- echo "Release APK built successfully!"
- name: run-tests
image: cirrusci/android-sdk:33
commands:
- cd MathHomeworkHelper
- echo "Running unit tests..."
- gradle test
- echo "Tests completed!"

View file

@ -1,37 +0,0 @@
# Gradle files
.gradle/
build/
*.apk
*.ap_
*.aab
# Local configuration file (sdk path, etc)
local.properties
# Log/OS Files
*.log
.DS_Store
# Android Studio generated files and folders
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Android Studio/IntelliJ
out/
.idea_modules/
*.iml
*.iws
*.ipr
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# gradle wrapper
gradle/wrapper/gradle-wrapper.jar

View file

@ -1,360 +0,0 @@
# Math Homework Helper - Android Project Index
## 📋 Project Overview
A complete Android WebView wrapper application for the Math Homework Helper web app. This project wraps your existing HTML/CSS/JavaScript application into a native Android app that can be installed on any Android device.
**Project Status**: ✅ **READY TO BUILD AND DEPLOY**
---
## 📚 Documentation Files
Start here based on your needs:
### 1. **QUICKSTART.md** ⭐ START HERE
- **Purpose**: Get up and running in 5 minutes
- **Best for**: First-time users
- **Contains**: Step-by-step setup instructions
- **Time**: 5-10 minutes to complete
### 2. **INSTALLATION.md** 🔧 DETAILED SETUP
- **Purpose**: Complete installation guide with troubleshooting
- **Best for**: Detailed setup and configuration
- **Contains**: Prerequisites, step-by-step installation, advanced config
- **Time**: 30-60 minutes to complete
### 3. **README.md** 📖 FULL DOCUMENTATION
- **Purpose**: Comprehensive project documentation
- **Best for**: Understanding the project structure and features
- **Contains**: Architecture, features, permissions, troubleshooting
- **Time**: Reference document
### 4. **PROJECT_SUMMARY.md** 📊 PROJECT STATUS
- **Purpose**: Overview of what was created
- **Best for**: Understanding project components
- **Contains**: File structure, features, configuration details
- **Time**: 10-15 minutes to read
### 5. **INDEX.md** (This File) 🗂️ NAVIGATION
- **Purpose**: Navigate all project files and documentation
- **Best for**: Finding what you need
- **Contains**: File listing and descriptions
---
## 📁 Project Structure
```
MathHomeworkHelper/
├── 📄 Documentation Files
│ ├── INDEX.md ← You are here
│ ├── QUICKSTART.md ← Start here!
│ ├── INSTALLATION.md ← Detailed setup
│ ├── README.md ← Full documentation
│ └── PROJECT_SUMMARY.md ← Project overview
├── 🔧 Build Configuration
│ ├── build.gradle ← Project-level build config
│ ├── settings.gradle ← Gradle settings
│ ├── gradle.properties ← Gradle properties
│ └── .gitignore ← Git ignore rules
└── 📦 app/ (Main Application Module)
├── 🔨 build.gradle ← App-level build config
├── proguard-rules.pro ← ProGuard obfuscation rules
└── src/main/
├── 📱 java/
│ └── com/example/mathhomeworkhelper/
│ └── MainActivity.java ← Main activity with WebView
├── 🎨 res/ (Resources)
│ ├── layout/
│ │ └── activity_main.xml ← Main layout
│ ├── values/
│ │ ├── strings.xml ← App strings
│ │ └── styles.xml ← Theme & colors
│ └── mipmap/ ← App icons (add here)
├── 🌐 assets/ (Web App Files)
│ ├── index.html ← Main HTML file
│ ├── styles.css ← Stylesheets
│ ├── script.js ← JavaScript logic
│ ├── translations.js ← Translation system
│ └── translations/
│ ├── en.json ← English
│ ├── es.json ← Spanish
│ ├── sv.json ← Swedish
│ └── el.json ← Greek
└── AndroidManifest.xml ← App manifest
```
---
## 🚀 Quick Start Paths
### Path 1: I Just Want to Build and Run (5 minutes)
1. Read: **QUICKSTART.md**
2. Open project in Android Studio
3. Click Run button
4. Done! ✅
### Path 2: I Want to Understand Everything (30 minutes)
1. Read: **PROJECT_SUMMARY.md**
2. Read: **README.md**
3. Explore the file structure
4. Read: **INSTALLATION.md** for detailed setup
### Path 3: I'm Having Issues (Troubleshooting)
1. Check: **README.md** → Troubleshooting section
2. Check: **INSTALLATION.md** → Troubleshooting section
3. Check: Android Studio Logcat for error messages
4. Search: Android Developer Documentation
### Path 4: I Want to Customize the App (15 minutes)
1. Read: **PROJECT_SUMMARY.md** → Customization Options
2. Modify files as needed:
- App name: `app/src/main/res/values/strings.xml`
- App icon: `app/src/main/res/mipmap/`
- Theme colors: `app/src/main/res/values/styles.xml`
- WebView behavior: `app/src/main/java/.../MainActivity.java`
### Path 5: I Want to Build for Release (20 minutes)
1. Read: **INSTALLATION.md** → Building for Distribution
2. Follow steps to create signed APK
3. Upload to Google Play Store (optional)
---
## 📋 File Descriptions
### Documentation
| File | Purpose | Read Time |
|------|---------|-----------|
| QUICKSTART.md | Get started in 5 minutes | 5 min |
| INSTALLATION.md | Complete setup guide | 30 min |
| README.md | Full documentation | 20 min |
| PROJECT_SUMMARY.md | Project overview | 10 min |
| INDEX.md | This file - navigation | 5 min |
### Build Configuration
| File | Purpose |
|------|---------|
| build.gradle (root) | Project-level Gradle configuration |
| app/build.gradle | App-level Gradle configuration |
| settings.gradle | Gradle project settings |
| gradle.properties | Gradle properties and JVM settings |
| .gitignore | Git ignore rules |
### Source Code
| File | Purpose |
|------|---------|
| MainActivity.java | Main activity with WebView setup |
| activity_main.xml | Main layout with WebView |
| AndroidManifest.xml | App manifest and permissions |
### Resources
| File | Purpose |
|------|---------|
| strings.xml | App strings and labels |
| styles.xml | App theme and colors |
| mipmap/ | App icons (add your icons here) |
### Web Assets
| File | Purpose |
|------|---------|
| index.html | Main HTML file |
| styles.css | Stylesheets |
| script.js | JavaScript logic |
| translations.js | Translation system |
| translations/*.json | Language files |
---
## 🎯 Common Tasks
### Task: Build the App
```bash
cd MathHomeworkHelper
./gradlew build
```
See: **INSTALLATION.md** → Step 6
### Task: Run on Emulator
1. Start Android emulator
2. Click Run button in Android Studio
3. Select emulator
See: **QUICKSTART.md** → Step 3
### Task: Run on Physical Device
1. Enable USB Debugging on device
2. Connect via USB
3. Click Run button in Android Studio
See: **INSTALLATION.md** → Step 7
### Task: Change App Name
Edit: `app/src/main/res/values/strings.xml`
```xml
<string name="app_name">New App Name</string>
```
See: **PROJECT_SUMMARY.md** → Customization
### Task: Change App Icon
Replace files in: `app/src/main/res/mipmap/`
See: **PROJECT_SUMMARY.md** → Customization
### Task: Change Theme Colors
Edit: `app/src/main/res/values/styles.xml`
See: **PROJECT_SUMMARY.md** → Customization
### Task: Build Release APK
```bash
./gradlew assembleRelease
```
See: **INSTALLATION.md** → Building for Distribution
### Task: Debug Issues
1. Check Logcat in Android Studio
2. Read troubleshooting sections
3. Consult Android documentation
See: **README.md** → Troubleshooting
---
## 🔍 Key Information
### Project Details
- **Type**: Native Android WebView Wrapper
- **Min SDK**: 21 (Android 5.0)
- **Target SDK**: 34 (Android 14)
- **Language**: Java
- **Build System**: Gradle
- **Package**: com.example.mathhomeworkhelper
### Features
✅ WebView with HTML content
✅ JavaScript enabled
✅ Local storage support
✅ Multi-language support
✅ Zoom controls
✅ Back button navigation
✅ Responsive layout
### Permissions
- INTERNET (required for WebView)
- ACCESS_NETWORK_STATE (network status)
### Dependencies
- androidx.appcompat:appcompat:1.6.1
- com.google.android.material:material:1.10.0
- androidx.constraintlayout:constraintlayout:2.1.4
---
## 📞 Getting Help
### Documentation
1. **QUICKSTART.md** - For quick setup
2. **INSTALLATION.md** - For detailed setup
3. **README.md** - For comprehensive info
4. **PROJECT_SUMMARY.md** - For project overview
### Troubleshooting
1. Check Logcat in Android Studio
2. Review troubleshooting sections in docs
3. Check Android Developer Documentation
4. Search Stack Overflow
### Resources
- [Android Developer Docs](https://developer.android.com/docs)
- [WebView Guide](https://developer.android.com/guide/webapps/webview)
- [Gradle Documentation](https://gradle.org/)
- [Android Studio Help](https://developer.android.com/studio/intro)
---
## ✅ Verification Checklist
Before you start, verify:
- [ ] Android Studio installed
- [ ] Android SDK 21+ installed
- [ ] Java 11+ installed
- [ ] 5GB+ free disk space
- [ ] Project folder accessible
- [ ] All files present (23 files total)
---
## 📊 Project Statistics
- **Total Files**: 23
- **Project Size**: 144 KB
- **Documentation Files**: 5
- **Source Files**: 1 (MainActivity.java)
- **Layout Files**: 1 (activity_main.xml)
- **Resource Files**: 2 (strings.xml, styles.xml)
- **Configuration Files**: 4 (build.gradle, settings.gradle, etc.)
- **Web Assets**: 9 (HTML, CSS, JS, translations)
- **Build System**: Gradle
---
## 🎓 Learning Path
### Beginner
1. Read QUICKSTART.md
2. Build and run the app
3. Test features
4. Celebrate! 🎉
### Intermediate
1. Read PROJECT_SUMMARY.md
2. Read README.md
3. Customize app (name, icon, colors)
4. Build release APK
### Advanced
1. Read INSTALLATION.md
2. Modify MainActivity.java
3. Add native Android features
4. Publish to Google Play Store
---
## 🚀 Next Steps
1. **Start Here**: Read **QUICKSTART.md**
2. **Open Project**: Launch Android Studio
3. **Build App**: Click Build button
4. **Run App**: Click Run button
5. **Test Features**: Verify everything works
6. **Customize**: Modify as needed
7. **Deploy**: Build release APK
---
## 📝 Notes
- All HTML files are in `app/src/main/assets/`
- All translations are included (EN, ES, SV, EL)
- JavaScript is enabled in WebView
- Back button navigation is supported
- App is ready to build immediately
---
**Last Updated**: November 25, 2025
**Project Status**: ✅ Ready to Build and Deploy
**Total Setup Time**: 5-30 minutes (depending on path)
---
**Happy Coding! 🚀**
For questions or issues, refer to the appropriate documentation file above.

View file

@ -1,389 +0,0 @@
# Installation & Setup Guide
## Complete Setup Instructions for Math Homework Helper Android App
### Prerequisites Checklist
Before you begin, ensure you have:
- [ ] **Android Studio** (latest version) - [Download here](https://developer.android.com/studio)
- [ ] **Java Development Kit (JDK) 11+** - Usually included with Android Studio
- [ ] **Android SDK** - Installed via Android Studio SDK Manager
- [ ] **Minimum 5GB free disk space** - For SDK and emulator
- [ ] **Git** (optional) - For version control
---
## Step 1: Install Android Studio
### Windows/Mac/Linux
1. Download Android Studio from https://developer.android.com/studio
2. Run the installer and follow the setup wizard
3. Choose "Standard" installation (recommended)
4. Accept the default settings
5. Complete the installation
### Verify Installation
```bash
# Check if Android Studio is installed
which android-studio # macOS/Linux
# or look for Android Studio in Applications/Programs
```
---
## Step 2: Set Up Android SDK
### Using Android Studio
1. Open Android Studio
2. Go to **Tools** → **SDK Manager**
3. Under "SDK Platforms" tab:
- ✅ Check "Android 14 (API 34)" - **Required**
- ✅ Check "Android 5.0 (API 21)" - **Minimum**
- ✅ Check "Android 12 (API 31)" - **Recommended**
4. Under "SDK Tools" tab:
- ✅ Check "Android SDK Build-Tools 34.x.x"
- ✅ Check "Android Emulator"
- ✅ Check "Android SDK Platform-Tools"
5. Click "Apply" and wait for downloads to complete
---
## Step 3: Create Android Virtual Device (Emulator)
### Option A: Using Android Studio GUI
1. Open Android Studio
2. Go to **Tools** → **Device Manager**
3. Click **"Create Device"**
4. Select a device (e.g., "Pixel 4" or "Pixel 5")
5. Click **"Next"**
6. Select API level (API 30 or higher recommended)
7. Click **"Next"**
8. Review settings and click **"Finish"**
9. Click the play button to start the emulator
### Option B: Using Command Line
```bash
# List available devices
emulator -list-avds
# Create a new AVD
avdmanager create avd -n "Pixel4" -k "system-images;android;30;google_apis"
# Start the emulator
emulator -avd Pixel4
```
---
## Step 4: Open the Project
### Method 1: Using Android Studio (Recommended)
1. Launch **Android Studio**
2. Click **"Open an existing Android Studio project"**
3. Navigate to the **MathHomeworkHelper** folder
4. Click **"Open"**
5. Wait for Gradle to sync (first time takes 2-5 minutes)
6. If prompted, click **"Trust Project"**
### Method 2: Using Command Line
```bash
# Navigate to project directory
cd /path/to/MathHomeworkHelper
# Open in Android Studio
open -a "Android Studio" . # macOS
# or
studio . # Linux
# or
start . # Windows (if Android Studio is in PATH)
```
---
## Step 5: Configure Project
### Gradle Sync
After opening the project:
1. Android Studio will automatically start Gradle sync
2. Wait for the sync to complete (check bottom status bar)
3. If sync fails:
- Click **File** → **Sync Now**
- Or **File****Invalidate Caches** → **Invalidate and Restart**
### Verify Configuration
```bash
# From project root directory
./gradlew --version # Should show Gradle version
./gradlew tasks # List available tasks
```
---
## Step 6: Build the Project
### Using Android Studio
1. Click **Build****Build Bundle(s) / APK(s)** → **Build APK(s)**
2. Wait for build to complete
3. You'll see a notification when build succeeds
### Using Command Line
```bash
cd MathHomeworkHelper
# Build debug APK
./gradlew assembleDebug
# Build release APK
./gradlew assembleRelease
# Clean and rebuild
./gradlew clean build
```
---
## Step 7: Run the App
### On Emulator
1. Start the Android emulator (if not already running)
2. In Android Studio, click the green **Run** button (or press **Shift+F10**)
3. Select your emulator from the device list
4. Click **OK**
5. Wait for app to install and launch
### On Physical Device
1. **Enable Developer Mode:**
- Go to **Settings** → **About Phone**
- Tap **Build Number** 7 times
- Go back to **Settings** → **Developer Options**
- Enable **USB Debugging**
2. **Connect Device:**
- Connect Android device via USB cable
- Allow USB debugging when prompted on device
- Android Studio will detect the device
3. **Run App:**
- Click green **Run** button in Android Studio
- Select your device from the list
- Click **OK**
---
## Step 8: Verify Installation
### Check App is Running
1. You should see the Math Homework Helper interface
2. Test the following features:
- ✅ Difficulty slider works
- ✅ Math problems display
- ✅ Answer input works
- ✅ Check Answer button functions
- ✅ Language selector works
- ✅ Back button navigates correctly
### Common Issues
| Issue | Solution |
|-------|----------|
| Gradle sync fails | File → Invalidate Caches → Invalidate and Restart |
| Emulator won't start | Check virtualization enabled in BIOS; try different API level |
| App crashes on launch | Check Logcat (View → Tool Windows → Logcat) for errors |
| WebView shows blank | Verify assets in app/src/main/assets/ |
| JavaScript not working | Check MainActivity.java has setJavaScriptEnabled(true) |
---
## Advanced Configuration
### Change Minimum SDK Version
Edit `app/build.gradle`:
```gradle
defaultConfig {
minSdk 21 // Change this value
}
```
### Change Target SDK Version
Edit `app/build.gradle`:
```gradle
android {
targetSdk 34 // Change this value
}
```
### Enable ProGuard/R8 for Release
Edit `app/build.gradle`:
```gradle
buildTypes {
release {
minifyEnabled true // Enable code shrinking
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
```
---
## Building for Distribution
### Create Signed Release APK
1. In Android Studio: **Build** → **Generate Signed Bundle / APK**
2. Select **APK**
3. Click **Next**
4. **Create new keystore** (or select existing):
- Key store path: Choose location
- Password: Create strong password
- Key alias: e.g., "release"
- Key password: Same as keystore or different
- Validity: 25+ years recommended
5. Click **Next**
6. Select **release** build type
7. Click **Finish**
8. APK will be generated in `app/build/outputs/apk/release/`
### Upload to Google Play Store
1. Create Google Play Developer account ($25 one-time fee)
2. Create new app in Play Console
3. Fill in app details (description, screenshots, etc.)
4. Upload signed APK
5. Set pricing and distribution
6. Submit for review
---
## Troubleshooting
### Gradle Issues
```bash
# Clear Gradle cache
./gradlew clean
# Rebuild with verbose output
./gradlew build --info
# Update Gradle wrapper
./gradlew wrapper --gradle-version=latest
```
### Emulator Issues
```bash
# List running emulators
emulator -list-avds
# Kill all emulator processes
pkill -f emulator
# Start emulator with more RAM
emulator -avd Pixel4 -memory 2048
```
### Build Issues
```bash
# Check Java version
java -version
# Check Android SDK
$ANDROID_HOME/tools/bin/sdkmanager --list
# Invalidate Android Studio cache
rm -rf ~/.android/
```
---
## Environment Variables (Optional)
### Set ANDROID_HOME
**macOS/Linux:**
```bash
export ANDROID_HOME=$HOME/Library/Android/sdk # macOS
export ANDROID_HOME=$HOME/Android/Sdk # Linux
export PATH=$PATH:$ANDROID_HOME/tools
export PATH=$PATH:$ANDROID_HOME/platform-tools
```
**Windows:**
```cmd
setx ANDROID_HOME "C:\Users\YourUsername\AppData\Local\Android\Sdk"
setx PATH "%PATH%;%ANDROID_HOME%\tools;%ANDROID_HOME%\platform-tools"
```
---
## Next Steps
1. ✅ Complete installation
2. ✅ Build and run the app
3. ✅ Test all features
4. ✅ Customize app (name, icon, colors)
5. ✅ Build release APK
6. ✅ Publish to Google Play Store (optional)
---
## Support & Resources
- **Android Studio Help**: https://developer.android.com/studio/intro
- **Android Developer Docs**: https://developer.android.com/docs
- **WebView Guide**: https://developer.android.com/guide/webapps/webview
- **Gradle Documentation**: https://gradle.org/
- **Stack Overflow**: Tag with `android` and `android-studio`
---
## Quick Reference Commands
```bash
# Navigate to project
cd MathHomeworkHelper
# Build debug APK
./gradlew assembleDebug
# Build release APK
./gradlew assembleRelease
# Run tests
./gradlew test
# Clean build
./gradlew clean
# Check dependencies
./gradlew dependencies
# Update Gradle
./gradlew wrapper --gradle-version=latest
```
---
**Installation Complete!** 🎉
Your Android project is now ready to build and deploy. Start with the Quick Start Guide (QUICKSTART.md) for next steps.

View file

@ -1,267 +0,0 @@
# Android Project Summary - Math Homework Helper
## ✅ Project Successfully Created!
Your Android project has been successfully created and is ready to build and deploy. This is a native Android WebView wrapper that displays your Math Homework Helper HTML application.
## 📁 Complete Project Structure
```
MathHomeworkHelper/
├── app/
│ ├── src/main/
│ │ ├── java/com/example/mathhomeworkhelper/
│ │ │ └── MainActivity.java ✅ Main activity with WebView
│ │ ├── res/
│ │ │ ├── layout/
│ │ │ │ └── activity_main.xml ✅ WebView layout
│ │ │ ├── values/
│ │ │ │ ├── strings.xml ✅ App strings
│ │ │ │ └── styles.xml ✅ App theme & colors
│ │ │ └── mipmap/ 📁 (for app icons)
│ │ ├── assets/
│ │ │ ├── index.html ✅ Main HTML file
│ │ │ ├── styles.css ✅ Stylesheets
│ │ │ ├── script.js ✅ JavaScript logic
│ │ │ ├── translations.js ✅ Translation logic
│ │ │ └── translations/
│ │ │ ├── en.json ✅ English translations
│ │ │ ├── es.json ✅ Spanish translations
│ │ │ ├── sv.json ✅ Swedish translations
│ │ │ └── el.json ✅ Greek translations
│ │ └── AndroidManifest.xml ✅ App manifest
│ ├── build.gradle ✅ App build config
│ └── proguard-rules.pro ✅ ProGuard rules
├── build.gradle ✅ Project build config
├── settings.gradle ✅ Gradle settings
├── gradle.properties ✅ Gradle properties
├── .gitignore ✅ Git ignore rules
├── README.md ✅ Full documentation
├── QUICKSTART.md ✅ Quick start guide
└── PROJECT_SUMMARY.md ✅ This file
```
## 🎯 What Was Created
### Core Components
1. **MainActivity.java**
- Initializes WebView with proper settings
- Enables JavaScript for interactive features
- Configures DOM storage and local storage
- Handles back button navigation
- Loads HTML from assets folder
2. **Activity Layout (activity_main.xml)**
- Simple LinearLayout with WebView
- WebView fills entire screen
3. **Android Manifest**
- Declares MainActivity as launcher activity
- Requests INTERNET permission
- Configures app theme and properties
4. **Build Configuration**
- Gradle build files for project and app
- Targets Android SDK 21-34
- Includes necessary dependencies
5. **Resources**
- App strings and theme colors
- ProGuard rules for code obfuscation
6. **Web Assets**
- All HTML, CSS, and JavaScript files copied
- All translation files included
- Ready to display in WebView
## 🚀 Quick Start
### Option 1: Using Android Studio (Recommended)
```bash
1. Open Android Studio
2. File → Open → Select MathHomeworkHelper folder
3. Wait for Gradle sync
4. Click Run (green play button)
5. Select emulator or device
```
### Option 2: Using Command Line
```bash
cd MathHomeworkHelper
./gradlew build # Build the project
./gradlew assembleDebug # Create debug APK
./gradlew assembleRelease # Create release APK
```
## 📋 Key Features Implemented
✅ **WebView Integration**
- Loads local HTML files from assets
- JavaScript enabled for interactivity
- DOM storage for data persistence
- Zoom controls available
✅ **File Access**
- All HTML/CSS/JS files in assets folder
- Translation files included
- Proper file permissions configured
✅ **User Experience**
- Back button navigation support
- Responsive layout
- Theme colors configured
- Multi-language support preserved
✅ **Build Configuration**
- Modern Gradle setup
- AndroidX support enabled
- Proper SDK versions configured
- ProGuard rules for release builds
## 🔧 Configuration Details
### Android Versions
- **Minimum SDK**: 21 (Android 5.0)
- **Target SDK**: 34 (Android 14)
- **Compile SDK**: 34
### Permissions
- `INTERNET` - Required for WebView
- `ACCESS_NETWORK_STATE` - Network status checking
### WebView Settings
- JavaScript: ✅ Enabled
- DOM Storage: ✅ Enabled
- Database: ✅ Enabled
- File Access: ✅ Enabled
- Zoom Controls: ✅ Enabled
- Mixed Content: ✅ Allowed (Android 5.0+)
## 📦 Dependencies
The project uses minimal dependencies:
- `androidx.appcompat:appcompat:1.6.1`
- `com.google.android.material:material:1.10.0`
- `androidx.constraintlayout:constraintlayout:2.1.4`
## 🎨 Customization Options
### Change App Name
Edit: `app/src/main/res/values/strings.xml`
```xml
<string name="app_name">Your App Name</string>
```
### Change App Icon
Replace files in: `app/src/main/res/mipmap/`
- `ic_launcher.png` (108x108 dp)
- `ic_launcher_round.png` (108x108 dp)
### Change Theme Colors
Edit: `app/src/main/res/values/styles.xml`
```xml
<color name="purple_500">#FF6200EE</color>
<!-- Change these color values -->
```
### Modify WebView Behavior
Edit: `app/src/main/java/com/example/mathhomeworkhelper/MainActivity.java`
## 📱 Building for Distribution
### Debug APK (Testing)
```bash
./gradlew assembleDebug
# Output: app/build/outputs/apk/debug/app-debug.apk
```
### Release APK (Distribution)
```bash
./gradlew assembleRelease
# Output: app/build/outputs/apk/release/app-release.apk
```
### Signed Release APK
1. In Android Studio: Build → Generate Signed Bundle/APK
2. Select APK
3. Create or select keystore
4. Fill signing information
5. Select release build type
## 🐛 Troubleshooting
### Issue: Gradle Sync Fails
**Solution**:
- File → Sync Now
- File → Invalidate Caches → Invalidate and Restart
### Issue: WebView Shows Blank Screen
**Solution**:
- Verify files in `app/src/main/assets/`
- Check MainActivity.java loadUrl path
- Enable JavaScript in WebView settings
### Issue: App Crashes on Launch
**Solution**:
- Check Logcat for error messages
- Verify AndroidManifest.xml syntax
- Ensure all dependencies are installed
### Issue: JavaScript Not Working
**Solution**:
- Confirm `setJavaScriptEnabled(true)` in MainActivity
- Check browser console for JS errors
- Verify file paths in HTML
## 📚 Documentation Files
- **README.md** - Complete project documentation
- **QUICKSTART.md** - Step-by-step getting started guide
- **PROJECT_SUMMARY.md** - This file
## 🔗 Useful Resources
- [Android Developer Documentation](https://developer.android.com/docs)
- [WebView Guide](https://developer.android.com/guide/webapps/webview)
- [Gradle Documentation](https://gradle.org/)
- [Android Studio Help](https://developer.android.com/studio/intro)
## ✨ Next Steps
1. **Open in Android Studio**
- File → Open → Select MathHomeworkHelper folder
2. **Set Up Emulator or Device**
- Create Android Virtual Device (AVD)
- Or connect physical device with USB debugging
3. **Build and Run**
- Click Run button or press Shift+F10
- Select target device
4. **Test the App**
- Verify HTML content displays
- Test all interactive features
- Check language switching
5. **Customize (Optional)**
- Change app name and icon
- Modify theme colors
- Add additional features
## 📞 Support
For issues or questions:
1. Check the troubleshooting section above
2. Review the README.md and QUICKSTART.md files
3. Check Android Studio Logcat for error messages
4. Consult Android Developer Documentation
---
**Project Status**: ✅ Ready to Build and Deploy
Your Android project is complete and ready to be opened in Android Studio. All necessary files have been created and configured. Simply open the project in Android Studio and click Run to get started!
Happy coding! 🚀

View file

@ -1,114 +0,0 @@
# Quick Start Guide
## Getting Started with Math Homework Helper Android App
### Prerequisites
- Android Studio installed (download from https://developer.android.com/studio)
- Android SDK 21+ installed
- Java 11+ installed
### Step 1: Open the Project
1. Launch Android Studio
2. Select "Open an existing Android Studio project"
3. Navigate to and select the `MathHomeworkHelper` folder
4. Wait for Gradle to sync (this may take a few minutes on first load)
### Step 2: Set Up an Emulator (or use a physical device)
**Option A: Using Android Emulator**
1. In Android Studio, go to Tools → Device Manager
2. Click "Create Device"
3. Select a device (e.g., Pixel 4)
4. Select an API level (API 30 or higher recommended)
5. Click "Finish"
6. Click the play button to start the emulator
**Option B: Using Physical Device**
1. Enable Developer Mode on your Android device:
- Go to Settings → About Phone
- Tap "Build Number" 7 times
- Go back to Settings → Developer Options
- Enable "USB Debugging"
2. Connect your device via USB cable
3. Android Studio will detect it automatically
### Step 3: Build and Run
1. Click the green "Run" button (or press Shift+F10)
2. Select your emulator or device
3. Click "OK"
4. Wait for the app to build and install (first build takes longer)
### Step 4: Test the App
Once the app launches:
- You should see the Math Homework Helper interface
- Try selecting a difficulty level
- Solve a multiplication problem
- Click "Check Answer" to verify
- Use the language selector to change languages
## Troubleshooting
### Gradle Sync Issues
- Click "File" → "Sync Now"
- If that doesn't work, try "File" → "Invalidate Caches" → "Invalidate and Restart"
### Emulator Won't Start
- Make sure you have enough disk space (at least 5GB)
- Try creating a new AVD with a different API level
- Check that virtualization is enabled in BIOS (for Windows/Linux)
### App Crashes on Launch
- Check the Logcat (View → Tool Windows → Logcat)
- Look for red error messages
- Common issues:
- Missing assets (check app/src/main/assets/)
- JavaScript errors (check browser console in WebView)
### WebView Not Displaying Content
- Ensure all HTML files are in `app/src/main/assets/`
- Check that the file path in MainActivity matches: `file:///android_asset/index.html`
- Verify JavaScript is enabled in WebView settings
## Project Structure Overview
```
MathHomeworkHelper/
├── app/ # Main app module
│ ├── src/main/
│ │ ├── java/ # Java source code
│ │ ├── res/ # Android resources (layouts, strings, styles)
│ │ ├── assets/ # Web app files (HTML, CSS, JS)
│ │ └── AndroidManifest.xml # App configuration
│ └── build.gradle # App build configuration
├── build.gradle # Project build configuration
└── settings.gradle # Gradle settings
```
## Building for Distribution
### Debug APK (for testing)
```bash
./gradlew assembleDebug
# Output: app/build/outputs/apk/debug/app-debug.apk
```
### Release APK (for distribution)
```bash
./gradlew assembleRelease
# Output: app/build/outputs/apk/release/app-release.apk
```
## Next Steps
- Customize the app icon (replace files in `app/src/main/res/mipmap/`)
- Modify the app name in `app/src/main/res/values/strings.xml`
- Update the theme colors in `app/src/main/res/values/styles.xml`
- Add more features by modifying `MainActivity.java`
## Need Help?
- Android Documentation: https://developer.android.com/docs
- WebView Guide: https://developer.android.com/guide/webapps/webview
- Gradle Documentation: https://gradle.org/
Happy coding! 🚀

View file

@ -1,143 +0,0 @@
# Math Homework Helper - Android App
This is an Android wrapper application that displays the Math Homework Helper web application using a WebView component.
## Project Structure
```
MathHomeworkHelper/
├── app/
│ ├── src/main/
│ │ ├── java/com/example/mathhomeworkhelper/
│ │ │ └── MainActivity.java # Main activity with WebView
│ │ ├── res/
│ │ │ ├── layout/
│ │ │ │ └── activity_main.xml # Main layout with WebView
│ │ │ ├── values/
│ │ │ │ ├── strings.xml # String resources
│ │ │ │ └── styles.xml # App theme and colors
│ │ │ └── mipmap/ # App icons
│ │ ├── assets/
│ │ │ ├── index.html # Main HTML file
│ │ │ ├── styles.css # Stylesheets
│ │ │ ├── script.js # JavaScript logic
│ │ │ ├── translations.js # Translation logic
│ │ │ └── translations/ # Translation JSON files
│ │ └── AndroidManifest.xml # App manifest
│ ├── build.gradle # App-level build configuration
│ └── proguard-rules.pro # ProGuard rules
├── build.gradle # Project-level build configuration
├── settings.gradle # Gradle settings
└── README.md # This file
```
## Requirements
- Android Studio (latest version recommended)
- Android SDK 21 or higher (minSdk)
- Target SDK 34
- Java 11 or higher
## Building the Project
### Using Android Studio
1. Open Android Studio
2. Click "Open an existing Android Studio project"
3. Navigate to the `MathHomeworkHelper` directory and select it
4. Wait for Gradle to sync
5. Click "Build" → "Build Bundle(s) / APK(s)" → "Build APK(s)"
### Using Command Line
```bash
cd MathHomeworkHelper
./gradlew build
```
To build a debug APK:
```bash
./gradlew assembleDebug
```
To build a release APK:
```bash
./gradlew assembleRelease
```
## Running the App
### On Android Studio Emulator
1. Create or select an Android Virtual Device (AVD)
2. Click the "Run" button (green play icon)
3. Select your emulator and click OK
### On Physical Device
1. Enable Developer Mode on your Android device
2. Connect your device via USB
3. Click the "Run" button in Android Studio
4. Select your device from the list
## Features
- ✅ Displays HTML content in a WebView
- ✅ JavaScript enabled for interactive features
- ✅ Local storage and DOM storage support
- ✅ Zoom controls enabled
- ✅ Back button navigation support
- ✅ Multi-language support (English, Spanish, Swedish, Greek)
## WebView Configuration
The MainActivity.java configures the WebView with the following settings:
- **JavaScript**: Enabled for interactive functionality
- **DOM Storage**: Enabled for local data persistence
- **Database**: Enabled for local storage
- **Zoom Controls**: Built-in zoom controls available
- **File Access**: Enabled to access local assets
- **Mixed Content**: Allowed for Android 5.0+
## Permissions
The app requires the following permissions (defined in AndroidManifest.xml):
- `INTERNET`: For WebView functionality
- `ACCESS_NETWORK_STATE`: To check network connectivity
## Troubleshooting
### WebView not loading content
- Ensure all HTML files are in the `app/src/main/assets/` directory
- Check that JavaScript is enabled in WebView settings
- Verify the file path in `webView.loadUrl()`
### JavaScript not working
- Confirm `setJavaScriptEnabled(true)` is set in MainActivity
- Check browser console for JavaScript errors
### App crashes on startup
- Check the Logcat for error messages
- Ensure all required dependencies are in build.gradle
- Verify AndroidManifest.xml is properly configured
## Building for Release
To create a signed release APK:
1. Go to "Build" → "Generate Signed Bundle / APK"
2. Select "APK"
3. Create or select a keystore
4. Fill in the signing information
5. Select "release" build type
6. Click "Finish"
## License
This project wraps the Math Homework Helper web application for Android.
## Support
For issues or questions, please refer to the original web application documentation.

View file

@ -1,39 +0,0 @@
plugins {
id 'com.android.application'
}
android {
namespace 'com.example.mathhomeworkhelper'
compileSdk 34
defaultConfig {
applicationId "com.example.mathhomeworkhelper"
minSdk 21
targetSdk 34
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.10.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
testImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}

View file

@ -1,18 +0,0 @@
# This is a configuration file for ProGuard.
# http://proguard.sourceforge.net/index.html#manual/usage.html
-dontusemixedcaseclassnames
# For using GSON @Expose annotation
-keepattributes *Annotation*
# Gson specific classes
-dontwarn sun.misc.**
-dontwarn com.google.gson.**
-keep class com.google.gson.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.example.mathhomeworkhelper.** { *; }
# Preserve line numbers for debugging stack traces
-keepattributes SourceFile,LineNumberTable
-renamesourcefileattribute SourceFile

View file

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mathhomeworkhelper">
<!-- Internet permission for WebView -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MathHomeworkHelper">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View file

@ -1,86 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Math Homework Helper - Multiplication Practice</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<!-- Language Selector -->
<div class="language-selector">
<div class="language-flags" id="language-flags"></div>
</div>
<div class="container">
<header class="header">
<h1 id="title">🎓 Math Homework Helper</h1>
<p class="subtitle" id="subtitle">Multiplication Practice</p>
</header>
<main class="main-content">
<!-- Difficulty Slider Section -->
<section class="difficulty-section">
<label for="difficulty-slider" class="difficulty-label">
Difficulty Level: <span id="difficulty-display">1</span>
</label>
<div class="slider-container">
<span class="difficulty-text">Easy</span>
<input
type="range"
id="difficulty-slider"
min="1"
max="5"
value="1"
class="slider"
>
<span class="difficulty-text">Hard</span>
</div>
<div class="difficulty-info">
<p id="difficulty-description">1 digit × 1 digit (e.g., 5 × 7)</p>
</div>
</section>
<!-- Problem Display Section -->
<section class="problem-section">
<div class="problem-display" id="problem-display">
<!-- Problem will be rendered here -->
</div>
</section>
<!-- Check Answer Button -->
<section class="answer-section">
<button id="submit-btn" class="submit-btn" style="width: 100%;">Check Answer</button>
</section>
<!-- Feedback Section -->
<section class="feedback-section">
<div id="feedback" class="feedback"></div>
</section>
<!-- Score Section -->
<section class="score-section">
<div class="score-box">
<p class="score-label">Points:</p>
<p class="score-value" id="points-score">0/20</p>
</div>
</section>
<!-- New Problem Button -->
<button id="new-problem-btn" class="new-problem-btn">New Problem</button>
</main>
</div>
<!-- Victory Modal -->
<div id="victory-modal" class="modal">
<div class="modal-content">
<h2>🎉 Congratulations! 🎉</h2>
<p>You've reached 20 points!</p>
<button id="play-again-btn" class="modal-btn">Play Again</button>
</div>
</div>
<script src="translations.js"></script>
<script src="script.js"></script>
</body>
</html>

View file

@ -1,651 +0,0 @@
// Game State
let gameState = {
difficulty: 1,
currentProblem: null,
points: 0,
totalAnswers: 0
};
// Difficulty configurations (will be updated with translations)
let difficultyConfig = {
1: {
num1Min: 1, num1Max: 9,
num2Min: 1, num2Max: 9,
descriptionKey: 'difficulty1'
},
2: {
num1Min: 10, num1Max: 99,
num2Min: 1, num2Max: 9,
descriptionKey: 'difficulty2'
},
3: {
num1Min: 10, num1Max: 99,
num2Min: 10, num2Max: 99,
descriptionKey: 'difficulty3'
},
4: {
num1Min: 100, num1Max: 999,
num2Min: 10, num2Max: 99,
descriptionKey: 'difficulty4'
},
5: {
num1Min: 10000, num1Max: 99999,
num2Min: 100, num2Max: 999,
descriptionKey: 'difficulty5'
}
};
// DOM Elements
const difficultySlider = document.getElementById('difficulty-slider');
const difficultyDisplay = document.getElementById('difficulty-display');
const difficultyDescription = document.getElementById('difficulty-description');
const problemDisplay = document.getElementById('problem-display');
const submitBtn = document.getElementById('submit-btn');
const feedbackDiv = document.getElementById('feedback');
const pointsScoreDisplay = document.getElementById('points-score');
const newProblemBtn = document.getElementById('new-problem-btn');
const victoryModal = document.getElementById('victory-modal');
const playAgainBtn = document.getElementById('play-again-btn');
// Event Listeners
difficultySlider.addEventListener('change', handleDifficultyChange);
submitBtn.addEventListener('click', handleSubmitAnswer);
newProblemBtn.addEventListener('click', generateNewProblem);
playAgainBtn.addEventListener('click', resetGame);
// Initialize
window.addEventListener('load', async () => {
await i18n.initialize();
initializeLanguageSelector();
updateUIText();
generateNewProblem();
});
/**
* Handle difficulty slider change
*/
function handleDifficultyChange() {
gameState.difficulty = parseInt(difficultySlider.value);
difficultyDisplay.textContent = gameState.difficulty;
difficultyDescription.textContent = difficultyConfig[gameState.difficulty].description;
generateNewProblem();
}
/**
* Generate a random number between min and max (inclusive)
*/
function getRandomNumber(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
/**
* Generate a new multiplication problem
*/
function generateNewProblem() {
const config = difficultyConfig[gameState.difficulty];
const num1 = getRandomNumber(config.num1Min, config.num1Max);
const num2 = getRandomNumber(config.num2Min, config.num2Max);
const answer = num1 * num2;
gameState.currentProblem = {
num1,
num2,
answer
};
displayProblem();
clearFeedback();
}
/**
* Calculate intermediate steps for vertical multiplication
*/
function calculateIntermediateSteps(num1, num2) {
const num2Str = num2.toString();
const steps = [];
// Calculate partial products for each digit of num2
for (let i = num2Str.length - 1; i >= 0; i--) {
const digit = parseInt(num2Str[i]);
const partialProduct = num1 * digit;
const shiftAmount = num2Str.length - 1 - i;
steps.push({
digit,
product: partialProduct,
shift: shiftAmount
});
}
return steps;
}
/**
* Display the multiplication problem
*/
function displayProblem() {
const { num1, num2 } = gameState.currentProblem;
const difficulty = gameState.difficulty;
if (difficulty === 1) {
// Horizontal layout for 1x1 with result
const answer = gameState.currentProblem.answer.toString();
let resultHTML = '<div class="line" style="justify-content: flex-end; gap: 2px;">';
for (let i = 0; i < answer.length; i++) {
resultHTML += `<input type="text" class="digit-input result-input" maxlength="1" data-pos="${i}" />`;
}
resultHTML += '</div>';
problemDisplay.innerHTML = `
<div class="multiplication-horizontal">
<span class="number">${num1}</span>
<span class="operator">×</span>
<span class="number">${num2}</span>
<span class="operator">=</span>
${resultHTML}
</div>
`;
// Add event listeners to result digit inputs
setTimeout(() => {
addResultDigitInputListeners();
}, 0);
} else {
// Vertical layout for 2+ digits
const num1Str = num1.toString();
const num2Str = num2.toString();
// Calculate intermediate steps for reference
const steps = calculateIntermediateSteps(num1, num2);
gameState.currentProblem.steps = steps;
// Create input fields for intermediate steps only if num2 has more than 1 digit
let intermediateHTML = '';
if (num2 > 9) {
// Calculate the maximum width needed for intermediate steps
const maxResultWidth = gameState.currentProblem.answer.toString().length;
for (let i = 0; i < steps.length; i++) {
const stepProduct = steps[i].product.toString();
const totalWidth = stepProduct.length + steps[i].shift;
intermediateHTML += '<div class="line" style="justify-content: flex-start; gap: 5px;">';
// Each row is offset one position to the left
// Add offset spaces at the beginning (left side)
for (let offset = 0; offset < i; offset++) {
intermediateHTML += '<span style="width: 90px;"></span>';
}
// Add empty spaces for shift
for (let s = 0; s < steps[i].shift; s++) {
intermediateHTML += '<span style="width: 90px;"></span>';
}
// Add input fields for each digit
for (let j = 0; j < stepProduct.length; j++) {
intermediateHTML += `<input type="text" class="digit-input intermediate-input" maxlength="1" data-step="${i}" data-pos="${j}" />`;
}
// Add trailing empty spaces on the right
const trailingSpaces = maxResultWidth - totalWidth - i;
for (let e = 0; e < trailingSpaces; e++) {
intermediateHTML += '<span style="width: 90px;"></span>';
}
intermediateHTML += '</div>';
}
}
// Create input fields for final result
const answer = gameState.currentProblem.answer.toString();
let resultHTML = '<div class="line" style="justify-content: flex-end; gap: 2px;">';
for (let i = 0; i < answer.length; i++) {
resultHTML += `<input type="text" class="digit-input result-input" maxlength="1" data-pos="${i}" />`;
}
resultHTML += '</div>';
let html = `
<div class="multiplication-vertical">
<div class="line">
<span>${num1Str}</span>
</div>
<div class="line">
<span class="operator">×</span>
<span>${num2Str}</span>
</div>
<div class="separator"></div>
`;
if (num2 > 9) {
html += `
<div id="intermediate-steps">
${intermediateHTML}
</div>
<div class="separator"></div>
`;
}
html += `
<div id="result-steps">
${resultHTML}
</div>
</div>
`;
problemDisplay.innerHTML = html;
// Add event listeners to digit inputs
setTimeout(() => {
addDigitInputListeners();
addResultDigitInputListeners();
}, 0);
}
}
/**
* Add event listeners to digit input fields
*/
function addDigitInputListeners() {
const digitInputs = document.querySelectorAll('.digit-input:not(.result-input)');
digitInputs.forEach((input, index) => {
input.addEventListener('input', (e) => {
// Only allow digits
if (!/^\d?$/.test(e.target.value)) {
e.target.value = '';
return;
}
// Move to next input if digit entered
if (e.target.value && index < digitInputs.length - 1) {
digitInputs[index + 1].focus();
}
});
input.addEventListener('keydown', (e) => {
if (e.key === 'Backspace' && !e.target.value && index > 0) {
digitInputs[index - 1].focus();
}
});
});
}
/**
* Add event listeners to result digit input fields
* Navigation: left after filling, wrap to rightmost of next line
*/
function addResultDigitInputListeners() {
const resultInputs = document.querySelectorAll('.result-input');
resultInputs.forEach((input, index) => {
input.addEventListener('input', (e) => {
// Only allow digits
if (!/^\d?$/.test(e.target.value)) {
e.target.value = '';
return;
}
// Move to LEFT if digit entered
if (e.target.value) {
if (index > 0) {
// Move to previous input (left)
resultInputs[index - 1].focus();
} else if (index === 0) {
// At the leftmost position, wrap to rightmost of previous line
const allLines = document.querySelectorAll('#result-steps .line, #intermediate-steps .line');
if (allLines.length > 1) {
const prevLineInputs = allLines[allLines.length - 2].querySelectorAll('input');
if (prevLineInputs.length > 0) {
prevLineInputs[prevLineInputs.length - 1].focus();
}
}
}
}
});
input.addEventListener('keydown', (e) => {
if (e.key === 'Backspace' && !e.target.value && index < resultInputs.length - 1) {
resultInputs[index + 1].focus();
}
});
});
}
/**
* Find which digits are incorrect in the answer
*/
function findIncorrectDigits(userAnswer, correctAnswer) {
const userStr = userAnswer.toString();
const correctStr = correctAnswer.toString();
const incorrectPositions = [];
// Pad the shorter string with leading zeros for comparison
const maxLen = Math.max(userStr.length, correctStr.length);
const userPadded = userStr.padStart(maxLen, '0');
const correctPadded = correctStr.padStart(maxLen, '0');
for (let i = 0; i < maxLen; i++) {
if (userPadded[i] !== correctPadded[i]) {
incorrectPositions.push(i);
}
}
return incorrectPositions;
}
/**
* Display answer with highlighted incorrect digits
*/
function displayAnswerWithErrors(userAnswer, correctAnswer) {
const incorrectPositions = findIncorrectDigits(userAnswer, correctAnswer);
const userStr = userAnswer.toString();
const correctStr = correctAnswer.toString();
const maxLen = Math.max(userStr.length, correctStr.length);
const userPadded = userStr.padStart(maxLen, '0');
let html = '<div style="font-size: 1.5em; margin-top: 15px;"><strong>Your answer:</strong> ';
for (let i = 0; i < maxLen; i++) {
const digit = userPadded[i];
if (incorrectPositions.includes(i)) {
html += `<span style="border: 3px solid #dc2626; padding: 5px 8px; margin: 0 2px; display: inline-block; background-color: #fee2e2;">${digit}</span>`;
} else {
html += digit;
}
}
html += `<br><strong>Correct answer:</strong> ${correctStr}</div>`;
return html;
}
/**
* Get user answer from input boxes
*/
function getUserAnswer() {
const resultInputs = document.querySelectorAll('.result-input');
let answer = '';
resultInputs.forEach(input => {
answer += input.value;
});
return answer === '' ? null : parseInt(answer);
}
/**
* Get user intermediate steps from input boxes
*/
function getUserIntermediateSteps() {
const steps = [];
const intermediateLines = document.querySelectorAll('#intermediate-steps .line');
intermediateLines.forEach((line, lineIndex) => {
const inputs = line.querySelectorAll('input');
let stepValue = '';
inputs.forEach(input => {
stepValue += input.value;
});
if (stepValue) {
steps.push(parseInt(stepValue));
}
});
return steps;
}
/**
* Handle answer submission
*/
function handleSubmitAnswer() {
const userAnswer = getUserAnswer();
const correctAnswer = gameState.currentProblem.answer;
if (userAnswer === null) {
showFeedback('Please enter an answer!', 'incorrect');
return;
}
gameState.totalAnswers++;
// Check intermediate steps if they exist
const intermediateStepsDiv = document.getElementById('intermediate-steps');
let intermediateStepsCorrect = true;
let intermediateErrorMessage = '';
if (intermediateStepsDiv) {
const steps = gameState.currentProblem.steps;
const intermediateLines = document.querySelectorAll('#intermediate-steps .line');
intermediateLines.forEach((line, lineIndex) => {
const inputs = line.querySelectorAll('input');
let userStepValue = '';
inputs.forEach(input => {
userStepValue += input.value;
});
if (userStepValue) {
const userStepNum = parseInt(userStepValue);
const correctStepNum = steps[lineIndex].product;
if (userStepNum !== correctStepNum) {
intermediateStepsCorrect = false;
intermediateErrorMessage += `<br>Step ${lineIndex + 1}: You wrote ${userStepNum}, correct is ${correctStepNum}`;
// Highlight incorrect digits in this step
const correctStr = correctStepNum.toString();
const userStr = userStepValue;
inputs.forEach((input, digitIndex) => {
if (digitIndex < userStr.length && userStr[digitIndex] !== correctStr[correctStr.length - userStr.length + digitIndex]) {
input.classList.add('error');
} else if (digitIndex < userStr.length) {
input.classList.add('correct');
}
});
}
}
});
}
if (userAnswer === correctAnswer && intermediateStepsCorrect) {
gameState.points += 1;
showFeedback('🎉 Correct! +1 point', 'correct');
updateScore();
// Check if reached 10 points
if (gameState.points >= 10) {
showVictoryModal();
return;
}
setTimeout(() => {
generateNewProblem();
}, 1500);
} else {
gameState.points = Math.max(0, gameState.points - 2);
// Mark incorrect result boxes with red color
if (userAnswer !== correctAnswer) {
const resultInputs = document.querySelectorAll('.result-input');
const userStr = userAnswer.toString();
const correctStr = correctAnswer.toString();
const maxLen = Math.max(userStr.length, correctStr.length);
const userPadded = userStr.padStart(maxLen, '0');
const correctPadded = correctStr.padStart(maxLen, '0');
resultInputs.forEach((input, index) => {
if (userPadded[index] !== correctPadded[index]) {
input.classList.add('error');
}
});
}
feedbackDiv.textContent = '❌ Your answer is wrong, check the red boxes';
feedbackDiv.className = 'feedback incorrect';
updateScore();
}
}
/**
* Show feedback message
*/
function showFeedback(message, type) {
feedbackDiv.textContent = message;
feedbackDiv.className = `feedback ${type}`;
}
/**
* Clear feedback message
*/
function clearFeedback() {
feedbackDiv.textContent = '';
feedbackDiv.className = 'feedback empty';
}
/**
* Update score display
*/
function updateScore() {
pointsScoreDisplay.textContent = `${gameState.points}/10`;
}
/**
* Show victory modal and create confetti
*/
function showVictoryModal() {
victoryModal.classList.add('show');
createConfetti();
}
/**
* Create confetti animation
*/
function createConfetti() {
const colors = ['#2563eb', '#7c3aed', '#dc2626', '#16a34a', '#ea580c', '#f59e0b'];
const confettiCount = 50;
for (let i = 0; i < confettiCount; i++) {
const confetti = document.createElement('div');
confetti.className = 'confetti';
confetti.style.left = Math.random() * 100 + '%';
confetti.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
confetti.style.delay = Math.random() * 0.5 + 's';
confetti.style.animationDuration = (Math.random() * 2 + 2.5) + 's';
document.body.appendChild(confetti);
// Remove confetti element after animation
setTimeout(() => {
confetti.remove();
}, 3500);
}
}
/**
* Reset game for new round
*/
function resetGame() {
gameState.points = 0;
gameState.totalAnswers = 0;
victoryModal.classList.remove('show');
updateScore();
generateNewProblem();
}
/**
* Initialize language selector
*/
function initializeLanguageSelector() {
const languageFlagsContainer = document.getElementById('language-flags');
const languages = i18n.getSupportedLanguages();
languageFlagsContainer.innerHTML = '';
Object.entries(languages).forEach(([langCode, langInfo]) => {
const flagButton = document.createElement('button');
flagButton.className = 'language-flag';
flagButton.textContent = langInfo.flag;
flagButton.title = langInfo.name;
flagButton.setAttribute('data-tooltip', langInfo.name);
if (langCode === i18n.getCurrentLanguage()) {
flagButton.classList.add('active');
}
flagButton.addEventListener('click', () => {
changeLanguage(langCode);
});
languageFlagsContainer.appendChild(flagButton);
});
}
/**
* Change language and update UI
*/
function changeLanguage(langCode) {
i18n.setLanguage(langCode);
// Update active flag
document.querySelectorAll('.language-flag').forEach(flag => {
flag.classList.remove('active');
});
const languages = i18n.getSupportedLanguages();
const flagButtons = document.querySelectorAll('.language-flag');
const langCodes = Object.keys(languages);
flagButtons.forEach((btn, index) => {
if (langCodes[index] === langCode) {
btn.classList.add('active');
}
});
updateUIText();
}
/**
* Update all UI text based on current language
*/
function updateUIText() {
// Update header
document.getElementById('title').textContent = '🎓 ' + i18n.t('title');
document.getElementById('subtitle').textContent = i18n.t('subtitle');
// Update difficulty label
const difficultyLabel = document.querySelector('.difficulty-label');
if (difficultyLabel) {
difficultyLabel.innerHTML = i18n.t('difficultyLevel') + ' <span id="difficulty-display">' + gameState.difficulty + '</span>';
}
// Update difficulty text labels
const difficultyTexts = document.querySelectorAll('.difficulty-text');
if (difficultyTexts.length >= 2) {
difficultyTexts[0].textContent = i18n.t('easy');
difficultyTexts[1].textContent = i18n.t('hard');
}
// Update difficulty description
const config = difficultyConfig[gameState.difficulty];
if (config && config.descriptionKey) {
document.getElementById('difficulty-description').textContent = i18n.t(config.descriptionKey);
}
// Update buttons
document.getElementById('submit-btn').textContent = i18n.t('checkAnswer');
document.getElementById('new-problem-btn').textContent = i18n.t('newProblem');
// Update score label
const scoreLabel = document.querySelector('.score-label');
if (scoreLabel) {
scoreLabel.textContent = i18n.t('points');
}
// Update modal
const modalTitle = document.querySelector('.modal-content h2');
const modalText = document.querySelector('.modal-content p');
const playAgainButton = document.getElementById('play-again-btn');
if (modalTitle) {
modalTitle.textContent = i18n.t('congratulations');
}
if (modalText) {
modalText.textContent = i18n.t('youReached10Points');
}
if (playAgainButton) {
playAgainButton.textContent = i18n.t('playAgain');
}
}

View file

@ -1,591 +0,0 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', 'Roboto', 'Arial', sans-serif;
background: #87CEEB;
min-height: 100vh;
padding: 20px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
/* Language Selector */
.language-selector {
position: fixed;
top: 20px;
right: 20px;
z-index: 100;
}
.language-flags {
display: flex;
gap: 10px;
background: white;
padding: 10px 15px;
border-radius: 15px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
}
.language-flag {
font-size: 1.5em;
cursor: pointer;
padding: 5px 10px;
border-radius: 8px;
transition: all 0.3s;
border: 2px solid transparent;
}
.language-flag:hover {
background: #f0f0f0;
transform: scale(1.1);
}
.language-flag.active {
background: #87CEEB;
border-color: #2563eb;
transform: scale(1.15);
}
.language-flag-tooltip {
position: relative;
}
.language-flag-tooltip:hover::after {
content: attr(data-tooltip);
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background: #333;
color: white;
padding: 5px 10px;
border-radius: 5px;
font-size: 0.8em;
white-space: nowrap;
margin-bottom: 5px;
z-index: 101;
}
.container {
background: white;
border-radius: 30px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
max-width: 1000px;
width: 100%;
padding: 40px;
animation: slideIn 0.5s ease-out;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Header */
.header {
text-align: center;
margin-bottom: 40px;
}
.header h1 {
font-size: 3em;
color: #2563eb;
margin-bottom: 10px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
}
.subtitle {
font-size: 1.3em;
color: #7c3aed;
font-weight: bold;
}
/* Difficulty Section */
.difficulty-section {
background: linear-gradient(135deg, #dc2626 0%, #ea580c 100%);
border-radius: 20px;
padding: 25px;
margin-bottom: 30px;
box-shadow: 0 10px 25px rgba(220, 38, 38, 0.3);
}
.difficulty-label {
display: block;
font-size: 1.3em;
color: white;
font-weight: bold;
margin-bottom: 15px;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
}
#difficulty-display {
background: white;
color: #dc2626;
padding: 5px 15px;
border-radius: 10px;
font-weight: bold;
font-size: 1.2em;
}
.slider-container {
display: flex;
align-items: center;
gap: 15px;
margin-bottom: 15px;
}
.difficulty-text {
color: white;
font-weight: bold;
font-size: 0.95em;
min-width: 50px;
}
.slider {
flex: 1;
height: 12px;
border-radius: 10px;
background: rgba(255, 255, 255, 0.3);
outline: none;
-webkit-appearance: none;
appearance: none;
cursor: pointer;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 35px;
height: 35px;
border-radius: 50%;
background: white;
cursor: pointer;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
transition: transform 0.2s;
}
.slider::-webkit-slider-thumb:hover {
transform: scale(1.1);
}
.slider::-moz-range-thumb {
width: 35px;
height: 35px;
border-radius: 50%;
background: white;
cursor: pointer;
border: none;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
transition: transform 0.2s;
}
.slider::-moz-range-thumb:hover {
transform: scale(1.1);
}
.difficulty-info {
background: rgba(255, 255, 255, 0.2);
padding: 10px 15px;
border-radius: 10px;
text-align: center;
}
#difficulty-description {
color: white;
font-size: 0.95em;
font-weight: bold;
}
/* Problem Section */
.problem-section {
background: linear-gradient(135deg, #dbeafe 0%, #e0e7ff 100%);
border-radius: 20px;
padding: 40px;
margin-bottom: 30px;
min-height: 150px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 10px 25px rgba(37, 99, 235, 0.2);
}
.problem-display {
font-size: 2.5em;
font-weight: bold;
color: #333;
text-align: center;
font-family: 'Courier New', monospace;
line-height: 1.6;
}
/* Horizontal multiplication (1x1) */
.multiplication-horizontal {
display: flex;
align-items: center;
justify-content: center;
gap: 20px;
}
.multiplication-horizontal .number {
font-size: 2.5em;
}
.multiplication-horizontal .operator {
font-size: 2.5em;
color: #f5576c;
font-weight: bold;
}
/* Vertical multiplication (2+ digits) */
.multiplication-vertical {
display: inline-block;
text-align: right;
font-family: 'Courier New', monospace;
}
.multiplication-vertical .line {
display: flex;
justify-content: flex-end;
gap: 5px;
margin: 5px 0;
font-size: 2em;
}
.multiplication-vertical .operator {
color: #f5576c;
font-weight: bold;
margin-right: 10px;
}
.multiplication-vertical .separator {
width: 100%;
height: 3px;
background: #333;
margin: 10px 0;
}
.digit-input {
width: 90px;
height: 90px;
font-size: 1.4em;
text-align: center;
border: 2px solid #2563eb;
border-radius: 8px;
padding: 10px;
font-weight: bold;
font-family: 'Courier New', monospace;
transition: all 0.2s;
}
.digit-input:focus {
outline: none;
border-color: #7c3aed;
box-shadow: 0 0 8px rgba(124, 58, 237, 0.4);
background-color: #f0f4ff;
}
.digit-input.error {
border-color: #dc2626;
background-color: #fee2e2;
}
.digit-input.correct {
border-color: #16a34a;
background-color: #dcfce7;
}
/* Answer Section */
.answer-section {
display: flex;
gap: 15px;
margin-bottom: 30px;
}
.answer-input {
flex: 1;
padding: 18px;
font-size: 1.3em;
border: 3px solid #2563eb;
border-radius: 15px;
outline: none;
transition: all 0.3s;
font-family: 'Segoe UI', 'Roboto', 'Arial', sans-serif;
font-weight: bold;
}
.answer-input:focus {
border-color: #7c3aed;
box-shadow: 0 0 15px rgba(124, 58, 237, 0.3);
transform: scale(1.02);
}
.answer-input::placeholder {
color: #ccc;
}
.submit-btn {
padding: 18px 30px;
font-size: 1.2em;
background: linear-gradient(135deg, #2563eb 0%, #7c3aed 100%);
color: white;
border: none;
border-radius: 15px;
cursor: pointer;
font-weight: bold;
transition: all 0.3s;
box-shadow: 0 5px 15px rgba(37, 99, 235, 0.4);
font-family: 'Segoe UI', 'Roboto', 'Arial', sans-serif;
}
.submit-btn:hover {
transform: translateY(-3px);
box-shadow: 0 8px 20px rgba(37, 99, 235, 0.6);
}
.submit-btn:active {
transform: translateY(-1px);
}
/* Feedback Section */
.feedback-section {
min-height: 80px;
margin-bottom: 30px;
display: flex;
align-items: center;
justify-content: center;
}
.feedback {
font-size: 1.1em;
font-weight: bold;
text-align: center;
padding: 15px;
border-radius: 15px;
min-width: 100%;
animation: fadeIn 0.5s ease-out;
word-wrap: break-word;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: scale(0.9);
}
to {
opacity: 1;
transform: scale(1);
}
}
.feedback.correct {
background: linear-gradient(135deg, #84fab0 0%, #8fd3f4 100%);
color: #2d5016;
box-shadow: 0 5px 15px rgba(132, 250, 176, 0.4);
}
.feedback.incorrect {
background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
color: #8b0000;
box-shadow: 0 5px 15px rgba(250, 112, 154, 0.4);
}
.feedback.empty {
background: transparent;
color: transparent;
}
/* Score Section */
.score-section {
display: flex;
gap: 20px;
margin-bottom: 30px;
justify-content: center;
}
.score-box {
background: linear-gradient(135deg, #16a34a 0%, #059669 100%);
padding: 20px 30px;
border-radius: 15px;
text-align: center;
box-shadow: 0 5px 15px rgba(22, 163, 74, 0.3);
min-width: 120px;
color: white;
}
.score-label {
font-size: 0.95em;
color: white;
font-weight: bold;
margin-bottom: 8px;
}
.score-value {
font-size: 2.5em;
color: white;
font-weight: bold;
}
/* New Problem Button */
.new-problem-btn {
width: 100%;
padding: 18px;
font-size: 1.3em;
background: linear-gradient(135deg, #dc2626 0%, #ea580c 100%);
color: white;
border: none;
border-radius: 15px;
cursor: pointer;
font-weight: bold;
transition: all 0.3s;
box-shadow: 0 5px 15px rgba(220, 38, 38, 0.4);
font-family: 'Segoe UI', 'Roboto', 'Arial', sans-serif;
}
.new-problem-btn:hover {
transform: translateY(-3px);
box-shadow: 0 8px 20px rgba(220, 38, 38, 0.6);
}
.new-problem-btn:active {
transform: translateY(-1px);
}
/* Confetti Animation */
@keyframes confetti-fall {
to {
transform: translateY(100vh) rotateZ(360deg);
opacity: 0;
}
}
.confetti {
position: fixed;
width: 10px;
height: 10px;
pointer-events: none;
animation: confetti-fall 3s ease-in forwards;
}
/* Modal Popup */
.modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
align-items: center;
justify-content: center;
}
.modal.show {
display: flex;
}
.modal-content {
background-color: white;
padding: 40px;
border-radius: 20px;
text-align: center;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
animation: modalBounce 0.5s ease-out;
max-width: 500px;
}
@keyframes modalBounce {
0% {
transform: scale(0.5);
opacity: 0;
}
50% {
transform: scale(1.05);
}
100% {
transform: scale(1);
opacity: 1;
}
}
.modal-content h2 {
font-size: 2.5em;
color: #16a34a;
margin-bottom: 20px;
}
.modal-content p {
font-size: 1.3em;
color: #333;
margin-bottom: 30px;
}
.modal-btn {
padding: 15px 40px;
font-size: 1.2em;
background: linear-gradient(135deg, #16a34a 0%, #059669 100%);
color: white;
border: none;
border-radius: 15px;
cursor: pointer;
font-weight: bold;
transition: all 0.3s;
box-shadow: 0 5px 15px rgba(22, 163, 74, 0.4);
font-family: 'Segoe UI', 'Roboto', 'Arial', sans-serif;
}
.modal-btn:hover {
transform: translateY(-3px);
box-shadow: 0 8px 20px rgba(22, 163, 74, 0.6);
}
.modal-btn:active {
transform: translateY(-1px);
}
/* Responsive Design */
@media (max-width: 600px) {
.container {
padding: 25px;
}
.header h1 {
font-size: 2.2em;
}
.problem-section {
padding: 25px;
min-height: 120px;
}
.problem-display {
font-size: 1.8em;
}
.answer-input,
.submit-btn {
font-size: 1.1em;
padding: 15px;
}
.score-box {
min-width: 100px;
padding: 15px 20px;
}
.score-value {
font-size: 2em;
}
}

View file

@ -1,184 +0,0 @@
// Translation Manager
class TranslationManager {
constructor() {
this.currentLanguage = 'en'; // Will be set during initialization
this.translations = {};
this.supportedLanguages = {
'en': { name: 'English', flag: '🇬🇧' },
'es': { name: 'Español', flag: '🇪🇸' },
'sv': { name: 'Svenska', flag: '🇸🇪' },
'el': { name: 'Ελληνικά', flag: '🇬🇷' }
};
// Country to language mapping
this.countryToLanguage = {
// Spanish-speaking countries
'ES': 'es', 'MX': 'es', 'AR': 'es', 'CO': 'es', 'PE': 'es', 'VE': 'es',
'CL': 'es', 'EC': 'es', 'BO': 'es', 'PY': 'es', 'UY': 'es', 'CU': 'es',
'DO': 'es', 'GT': 'es', 'HN': 'es', 'SV': 'es', 'NI': 'es', 'CR': 'es',
'PA': 'es', 'BZ': 'es', 'EQ': 'es',
// Swedish-speaking countries
'SE': 'sv', 'FI': 'sv', 'AX': 'sv',
// Greek-speaking countries
'GR': 'el', 'CY': 'el',
// Default to English for all others
};
}
// Detect language with geolocation fallback
async detectLanguageWithGeolocation() {
// Step 1: Check localStorage for saved preference
const savedLanguage = localStorage.getItem('preferredLanguage');
if (savedLanguage && this.supportedLanguages[savedLanguage]) {
console.log('Using saved language preference:', savedLanguage);
return savedLanguage;
}
// Step 2: Try browser language detection
const browserLang = this.detectBrowserLanguage();
if (browserLang !== 'en') {
console.log('Using browser language:', browserLang);
return browserLang;
}
// Step 3: Try geolocation API to get country and map to language
try {
const countryCode = await this.getCountryFromGeolocation();
if (countryCode) {
const language = this.countryToLanguage[countryCode] || 'en';
console.log('Using geolocation-based language:', language, 'from country:', countryCode);
return language;
}
} catch (error) {
console.warn('Geolocation failed, continuing with fallback:', error.message);
}
// Step 4: Fallback to English
console.log('Falling back to English');
return 'en';
}
// Detect browser language
detectBrowserLanguage() {
const browserLang = navigator.language || navigator.userLanguage;
const langCode = browserLang.split('-')[0];
// Check if the detected language is supported
if (this.supportedLanguages[langCode]) {
return langCode;
}
// Return 'en' if not supported (will trigger geolocation)
return 'en';
}
// Get country code from geolocation API
async getCountryFromGeolocation() {
const timeout = 5000; // 5 second timeout
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
// Try ip-api.com (free, no auth required)
const response = await fetch('https://ipapi.co/json/', {
signal: controller.signal,
headers: { 'Accept': 'application/json' }
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`API returned status ${response.status}`);
}
const data = await response.json();
const countryCode = data.country_code;
if (countryCode && typeof countryCode === 'string') {
console.log('Geolocation API returned country:', countryCode);
return countryCode;
}
throw new Error('No country code in response');
} catch (error) {
if (error.name === 'AbortError') {
console.warn('Geolocation API request timed out');
} else {
console.warn('Geolocation API error:', error.message);
}
return null;
}
}
// Load translation file
async loadTranslation(language) {
try {
const response = await fetch(`translations/${language}.json`);
if (!response.ok) {
throw new Error(`Failed to load ${language} translation`);
}
this.translations[language] = await response.json();
this.currentLanguage = language;
localStorage.setItem('preferredLanguage', language);
return true;
} catch (error) {
console.error('Error loading translation:', error);
return false;
}
}
// Get translated string
t(key) {
if (this.translations[this.currentLanguage] && this.translations[this.currentLanguage][key]) {
return this.translations[this.currentLanguage][key];
}
// Fallback to English if key not found
if (this.translations['en'] && this.translations['en'][key]) {
return this.translations['en'][key];
}
// Return key if no translation found
return key;
}
// Get current language
getCurrentLanguage() {
return this.currentLanguage;
}
// Get all supported languages
getSupportedLanguages() {
return this.supportedLanguages;
}
// Set language
setLanguage(language) {
if (this.supportedLanguages[language]) {
this.currentLanguage = language;
localStorage.setItem('preferredLanguage', language);
return true;
}
return false;
}
// Initialize translations
async initialize() {
// Detect language using geolocation fallback chain
this.currentLanguage = await this.detectLanguageWithGeolocation();
// Load all supported language files
const loadPromises = Object.keys(this.supportedLanguages).map(lang =>
this.loadTranslation(lang)
);
await Promise.all(loadPromises);
// Ensure current language is set correctly
if (!this.translations[this.currentLanguage]) {
this.currentLanguage = 'en';
}
}
}
// Create global instance
const i18n = new TranslationManager();

View file

@ -1,20 +0,0 @@
{
"title": "Βοηθός Μαθηματικών Εργασιών",
"subtitle": "Εξάσκηση Πολλαπλασιασμού",
"difficultyLevel": "Επίπεδο Δυσκολίας:",
"easy": "Εύκολο",
"hard": "Δύσκολο",
"difficulty1": "1 ψηφίο × 1 ψηφίο (π.χ. 5 × 7)",
"difficulty2": "1 ψηφίο × 2 ψηφία (π.χ. 5 × 23)",
"difficulty3": "2 ψηφία × 2 ψηφία (π.χ. 23 × 45)",
"difficulty4": "2 ψηφία × 3 ψηφία (π.χ. 23 × 456)",
"difficulty5": "3 ψηφία × 3 ψηφία (π.χ. 234 × 567)",
"checkAnswer": "Έλεγχος Απάντησης",
"points": "Πόντοι:",
"newProblem": "Νέο Πρόβλημα",
"congratulations": "🎉 Συγχαρητήρια! 🎉",
"youReached20Points": "Έφτασες τους 20 πόντους!",
"playAgain": "Παίξε Ξανά",
"correct": "Σωστό! Εξαιρετική δουλειά! 🎉",
"incorrect": "Λάθος. Προσπάθησε ξανά! 💪"
}

View file

@ -1,20 +0,0 @@
{
"title": "Math Homework Helper",
"subtitle": "Multiplication Practice",
"difficultyLevel": "Difficulty Level:",
"easy": "Easy",
"hard": "Hard",
"difficulty1": "1 digit × 1 digit (e.g., 5 × 7)",
"difficulty2": "1 digit × 2 digits (e.g., 5 × 23)",
"difficulty3": "2 digits × 2 digits (e.g., 23 × 45)",
"difficulty4": "2 digits × 3 digits (e.g., 23 × 456)",
"difficulty5": "3 digits × 3 digits (e.g., 234 × 567)",
"checkAnswer": "Check Answer",
"points": "Points:",
"newProblem": "New Problem",
"congratulations": "🎉 Congratulations! 🎉",
"youReached20Points": "You've reached 20 points!",
"playAgain": "Play Again",
"correct": "Correct! Great job! 🎉",
"incorrect": "Incorrect. Try again! 💪"
}

View file

@ -1,20 +0,0 @@
{
"title": "Ayudante de Tareas de Matemáticas",
"subtitle": "Práctica de Multiplicación",
"difficultyLevel": "Nivel de Dificultad:",
"easy": "Fácil",
"hard": "Difícil",
"difficulty1": "1 dígito × 1 dígito (p. ej., 5 × 7)",
"difficulty2": "1 dígito × 2 dígitos (p. ej., 5 × 23)",
"difficulty3": "2 dígitos × 2 dígitos (p. ej., 23 × 45)",
"difficulty4": "2 dígitos × 3 dígitos (p. ej., 23 × 456)",
"difficulty5": "3 dígitos × 3 dígitos (p. ej., 234 × 567)",
"checkAnswer": "Verificar Respuesta",
"points": "Puntos:",
"newProblem": "Nuevo Problema",
"congratulations": "🎉 ¡Felicitaciones! 🎉",
"youReached20Points": "¡Has alcanzado 20 puntos!",
"playAgain": "Jugar de Nuevo",
"correct": "¡Correcto! ¡Excelente trabajo! 🎉",
"incorrect": "Incorrecto. ¡Intenta de nuevo! 💪"
}

View file

@ -1,20 +0,0 @@
{
"title": "Matematikläxhjälp",
"subtitle": "Multiplikationspraktik",
"difficultyLevel": "Svårighetsnivå:",
"easy": "Lätt",
"hard": "Svårt",
"difficulty1": "1 siffra × 1 siffra (t.ex. 5 × 7)",
"difficulty2": "1 siffra × 2 siffror (t.ex. 5 × 23)",
"difficulty3": "2 siffror × 2 siffror (t.ex. 23 × 45)",
"difficulty4": "2 siffror × 3 siffror (t.ex. 23 × 456)",
"difficulty5": "3 siffror × 3 siffror (t.ex. 234 × 567)",
"checkAnswer": "Kontrollera Svar",
"points": "Poäng:",
"newProblem": "Nytt Problem",
"congratulations": "🎉 Grattis! 🎉",
"youReached20Points": "Du har nått 20 poäng!",
"playAgain": "Spela Igen",
"correct": "Rätt! Bra jobbat! 🎉",
"incorrect": "Fel. Försök igen! 💪"
}

View file

@ -1,64 +0,0 @@
package com.example.mathhomeworkhelper;
import android.os.Build;
import android.os.Bundle;
import android.webkit.WebSettings;
import android.webkit.WebView;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = findViewById(R.id.webview);
// Configure WebView settings
WebSettings webSettings = webView.getSettings();
// Enable JavaScript (required for your app)
webSettings.setJavaScriptEnabled(true);
// Enable DOM storage
webSettings.setDomStorageEnabled(true);
// Enable local storage
webSettings.setDatabaseEnabled(true);
// Set user agent
webSettings.setUserAgentString(webSettings.getUserAgentString());
// Enable zoom controls
webSettings.setBuiltInZoomControls(true);
webSettings.setDisplayZoomControls(false);
// Set default zoom level
webSettings.setDefaultZoom(WebSettings.ZoomDensity.MEDIUM);
// Allow file access
webSettings.setAllowFileAccess(true);
webSettings.setAllowContentAccess(true);
// For Android 5.0 and above, allow mixed content
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
// Load the local HTML file from assets
webView.loadUrl("file:///android_asset/index.html");
}
@Override
public void onBackPressed() {
// Allow back navigation within the WebView
if (webView.canGoBack()) {
webView.goBack();
} else {
super.onBackPressed();
}
}
}

View file

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

View file

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Math Homework Helper</string>
<string name="app_title">Math Homework Helper</string>
</resources>

View file

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.MathHomeworkHelper" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorError">@color/red_500</item>
<item name="colorOnPrimary">@color/white</item>
<item name="colorOnSecondary">@color/black</item>
<item name="colorOnError">@color/white</item>
<item name="colorOnBackground">@color/black</item>
<item name="colorOnSurface">@color/black</item>
</style>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="red_500">#FFFF0000</color>
</resources>

View file

@ -1,5 +0,0 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '8.1.0' apply false
id 'com.android.library' version '8.1.0' apply false
}

View file

@ -1,21 +0,0 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE are ignored when building from the
# command line. Check Gradle settings in the IDE if you notice discrepancies
# between the IDE and command line builds.
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it easier to discover and migrate existing, old-style packages
android.useAndroidX=true
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and does not include resources from the
# dependencies, thereby reducing the size of the R class in the final APK.
android.nonTransitiveRClass=true
# Gradle memory settings
org.gradle.jvmargs=-Xmx2048m

View file

@ -1,16 +0,0 @@
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "Math Homework Helper"
include ':app'