Β© OMARINO IT ServicesA new Flutter project.
A mobile application built with Flutter that captures electricity meter readings using OCR technology and synchronizes data directly to Microsoft Excel Online via the Microsoft Graph API.## Getting Started
---This project is a starting point for a Flutter application.
ποΈ System ArchitectureA few resources to get you started if this is your first Flutter project:
Technology Stack- Lab: Write your first Flutter app
-
Framework: Flutter (Dart)- Cookbook: Useful Flutter samples
-
OCR Engine: Google ML Kit Text Recognition
-
Authentication: Azure AD OAuth 2.0 (via
aad_oauth)For help getting started with Flutter development, view the -
Cloud Storage: Microsoft OneDrive + Excel Onlineonline documentation, which offers tutorials,
-
API: Microsoft Graph APIsamples, guidance on mobile development, and a full API reference.
-
Local Storage: SQLite (offline mode)
-
State Management: Provider pattern
βββββββββββββββ ββββββββββββββββ βββββββββββββββ
β Camera βββββββΆβ OCR Engine βββββββΆβ Preview β
β Capture β β (ML Kit) β β Screen β
βββββββββββββββ ββββββββββββββββ βββββββββββββββ
β
βΌ
βββββββββββββββ ββββββββββββββββ βββββββββββββββ
β Excel ββββββββ Graph API ββββββββ Auth Serviceβ
β Online β β Service β β (Azure AD) β
βββββββββββββββ ββββββββββββββββ βββββββββββββββ
β
βΌ
ββββββββββββββββ
β Local SQLite β
β (Offline) β
ββββββββββββββββ
meter_reader_app/
βββ lib/
β βββ main.dart # App entry point
β βββ models/ # Data models
β β βββ meter_reading.dart # MeterReading model
β β βββ upload_status.dart # Upload status tracking
β βββ screens/ # UI screens
β β βββ splash_screen.dart # Splash with OMARINO branding
β β βββ home_screen.dart # Main screen with scan button
β β βββ preview_screen.dart # OCR results preview
β β βββ history_screen.dart # Past readings
β βββ services/ # Business logic services
β β βββ auth_service.dart # Azure AD authentication
β β βββ graph_service.dart # Microsoft Graph API operations
β β βββ ocr_service.dart # OCR processing
β β βββ camera_service.dart # Camera capture
β β βββ database_service.dart # Local SQLite operations
β βββ utils/ # Helper utilities
β βββ constants.dart # App constants
β βββ config.dart # Azure config loader
β βββ theme.dart # Material Design 3 theme
βββ assets/
β βββ images/ # Logo and branding assets
βββ android/ # Android configuration
βββ ios/ # iOS configuration
βββ config/
β βββ azure_config.json # Azure app registration details
βββ pubspec.yaml # Dependencies
- Flutter SDK (3.0+)
- Android Studio / Xcode (for mobile development)
- Microsoft Azure account
- OneDrive account
git clone <repository-url>
cd MeterReaderApp
flutter pub get-
Go to Azure Portal: https://portal.azure.com
-
Navigate to: Azure Active Directory β App registrations β New registration
-
Configure Application:
- Name: MeterReaderApp
- Supported account types: Accounts in any organizational directory and personal Microsoft accounts
- Redirect URI:
- Platform: Public client/native (mobile & desktop)
- URI:
msauth://com.omarinoitservices.meter_reader_app/auth
-
API Permissions (Microsoft Graph):
Files.ReadWrite(Delegated)User.Read(Delegated)offline_access(Delegated)
Click "Grant admin consent" if required.
-
Copy Configuration:
- Application (client) ID:
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - Directory (tenant) ID:
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
- Application (client) ID:
Create a file: config/azure_config.json
{
"client_id": "YOUR_CLIENT_ID_HERE",
"tenant_id": "YOUR_TENANT_ID_HERE",
"redirect_uri": "msauth://com.omarinoitservices.meter_reader_app/auth",
"scopes": [
"User.Read",
"Files.ReadWrite",
"offline_access"
]
}IMPORTANT: Add config/azure_config.json to .gitignore to keep credentials secure.
Add permissions inside <manifest>:
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>Add inside <application> β <activity>:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="msauth"
android:host="com.omarinoitservices.meter_reader_app"
android:path="/auth" />
</intent-filter>Add before </dict>:
<key>NSCameraUsageDescription</key>
<string>This app needs camera access to capture meter readings</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs photo library access to select meter images</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>msauth</string>
</array>
</dict>
</array># Run on connected device
flutter run
# Run in debug mode
flutter run --debug
# Run in release mode (production)
flutter run --release# Android APK
flutter build apk --release
# iOS Archive (requires Mac)
flutter build ios --release- User clicks "Login" β
AuthService.login() - Azure AD OAuth redirect β User authenticates
- Access token stored securely β Token auto-refresh enabled
- Token passed to
GraphServicefor API calls
- User captures image β
CameraService.captureImage() - Image preprocessing β
OcrService.processImage() - Text extraction β Parse meter number & reading
- Return structured JSON:
{meterNumber, reading, timestamp}
- User confirms data β
GraphService.uploadToExcel() - Check if file exists:
GET /me/drive/root:/MeterReader/data.xlsx - If not exists: Create Excel file with headers
- Append row:
POST /me/drive/root:/MeterReader/data.xlsx:/workbook/tables/Table1/rows/add
- Failed uploads saved to local SQLite database
- Background sync job retries when network available
- User notified of pending uploads in UI
{
"id": "uuid",
"meterNumber": "123456789",
"reading": "54321",
"timestamp": "2025-10-20T14:30:00Z",
"imagePath": "/local/path/image.jpg",
"uploadStatus": "pending|uploaded|failed",
"uploadedAt": "2025-10-20T14:31:00Z"
}- Theme: Material Design 3
- Colors: Custom OMARINO IT Services branding
- Dark Mode: Fully supported
- Typography: Roboto (default Material)
flutter testflutter drive --target=test_driver/app.dart- Camera capture works on Android & iOS
- OCR correctly extracts meter number and reading
- Authentication flow completes successfully
- Excel file is created in OneDrive if missing
- Data appends correctly to Excel Online
- Offline mode saves data locally
- Background sync works when network restored
- Dark mode renders correctly
- App handles errors gracefully
- Tokens: Stored securely using
flutter_secure_storage - API Keys: Never hardcoded, loaded from config file
- Permissions: Request only when needed
- Data: Images deleted after successful upload (optional)
Β© 2025 OMARINO IT Services. All rights reserved.
For issues or questions, contact: OMARINO IT Services
- Project setup and architecture
- Camera capture implementation
- OCR integration
- Azure AD authentication
- Microsoft Graph API integration
- Offline mode
- UI/UX polish
- Beta testing
- Production release
Built with β€οΈ by OMARINO IT Services