where my git go?

This commit is contained in:
Mathias Beaulieu-Duncan 2025-11-15 10:03:27 -05:00
commit 695b6a07e3
150 changed files with 8838 additions and 0 deletions

45
.gitignore vendored Normal file
View File

@ -0,0 +1,45 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.build/
.buildlog/
.history
.svn/
.swiftpm/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# 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/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.pub-cache/
.pub/
/build/
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release

45
.metadata Normal file
View File

@ -0,0 +1,45 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "ea121f8859e4b13e47a8f845e4586164519588bc"
channel: "stable"
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: ea121f8859e4b13e47a8f845e4586164519588bc
base_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- platform: android
create_revision: ea121f8859e4b13e47a8f845e4586164519588bc
base_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- platform: ios
create_revision: ea121f8859e4b13e47a8f845e4586164519588bc
base_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- platform: linux
create_revision: ea121f8859e4b13e47a8f845e4586164519588bc
base_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- platform: macos
create_revision: ea121f8859e4b13e47a8f845e4586164519588bc
base_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- platform: web
create_revision: ea121f8859e4b13e47a8f845e4586164519588bc
base_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- platform: windows
create_revision: ea121f8859e4b13e47a8f845e4586164519588bc
base_revision: ea121f8859e4b13e47a8f845e4586164519588bc
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'

427
API_MOCK_DATA.md Normal file
View File

@ -0,0 +1,427 @@
# API Mock Data Guide
If you don't have a backend API ready yet, you can use mock data to test the app. This guide shows you how to create and use mock data.
## Creating Mock Data
### Option 1: Modify RouteApiService
Edit `lib/services/api/route_api_service.dart` and replace the API calls with mock data:
```dart
import 'package:uuid/uuid.dart';
Future<List<RouteModel>> getDriverRoutes(String driverId) async {
// Simulate network delay
await Future.delayed(const Duration(seconds: 1));
// Return mock data
return [
RouteModel(
id: 'RT001',
driverId: driverId,
driverName: 'John Doe',
date: DateTime.now(),
status: RouteStatus.notStarted,
totalDistance: 45.5,
estimatedDuration: 120,
vehicleId: 'VH123',
stops: [
StopModel(
id: 'ST001',
customerId: 'C001',
customerName: 'Acme Corporation',
customerPhone: '+1234567890',
location: LocationModel(
latitude: 37.7749,
longitude: -122.4194,
address: '123 Market St, San Francisco, CA 94103',
),
type: StopType.pickup,
status: StopStatus.pending,
scheduledTime: DateTime.now().add(const Duration(hours: 1)),
items: ['Package A', 'Package B', 'Package C'],
orderNumber: 1,
),
StopModel(
id: 'ST002',
customerId: 'C002',
customerName: 'Tech Solutions Inc',
customerPhone: '+1234567891',
location: LocationModel(
latitude: 37.7849,
longitude: -122.4094,
address: '456 Mission St, San Francisco, CA 94105',
),
type: StopType.dropoff,
status: StopStatus.pending,
scheduledTime: DateTime.now().add(const Duration(hours: 2)),
items: ['Package A', 'Package B'],
orderNumber: 2,
),
StopModel(
id: 'ST003',
customerId: 'C003',
customerName: 'Global Supplies Ltd',
customerPhone: '+1234567892',
location: LocationModel(
latitude: 37.7949,
longitude: -122.3994,
address: '789 Howard St, San Francisco, CA 94107',
),
type: StopType.dropoff,
status: StopStatus.pending,
scheduledTime: DateTime.now().add(const Duration(hours: 3)),
items: ['Package C'],
orderNumber: 3,
),
],
),
RouteModel(
id: 'RT002',
driverId: driverId,
driverName: 'John Doe',
date: DateTime.now().add(const Duration(days: 1)),
status: RouteStatus.notStarted,
totalDistance: 32.8,
estimatedDuration: 90,
vehicleId: 'VH123',
stops: [
StopModel(
id: 'ST004',
customerId: 'C004',
customerName: 'Downtown Retail',
customerPhone: '+1234567893',
location: LocationModel(
latitude: 37.7649,
longitude: -122.4294,
address: '321 Broadway, San Francisco, CA 94133',
),
type: StopType.pickup,
status: StopStatus.pending,
scheduledTime: DateTime.now().add(const Duration(days: 1, hours: 1)),
items: ['Box 1', 'Box 2'],
orderNumber: 1,
),
],
),
];
}
Future<RouteModel?> getRouteById(String routeId) async {
await Future.delayed(const Duration(seconds: 1));
final routes = await getDriverRoutes('driver_1');
return routes.firstWhere(
(route) => route.id == routeId,
orElse: () => routes.first,
);
}
Future<bool> updateRouteStatus(String routeId, RouteStatus status) async {
await Future.delayed(const Duration(milliseconds: 500));
// Simulate successful update
return true;
}
Future<bool> updateStopStatus(
String routeId,
String stopId,
StopStatus status, {
String? signature,
String? photo,
String? notes,
}) async {
await Future.delayed(const Duration(milliseconds: 500));
// Simulate successful update
return true;
}
Future<bool> reportIssue(String routeId, String stopId, String issue) async {
await Future.delayed(const Duration(milliseconds: 500));
// Simulate successful report
return true;
}
```
### Option 2: Create a Mock Provider
Create a separate mock service that you can easily swap:
1. Create `lib/services/api/mock_route_api_service.dart`:
```dart
import 'route_api_service.dart';
import '../../features/routes/data/models/route_model.dart';
import '../../features/routes/data/models/stop_model.dart';
import '../../features/routes/data/models/location_model.dart';
class MockRouteApiService extends RouteApiService {
final List<RouteModel> _mockRoutes = [
// Add your mock routes here
];
@override
Future<List<RouteModel>> getDriverRoutes(String driverId) async {
await Future.delayed(const Duration(seconds: 1));
return _mockRoutes;
}
@override
Future<RouteModel?> getRouteById(String routeId) async {
await Future.delayed(const Duration(seconds: 1));
return _mockRoutes.firstWhere(
(route) => route.id == routeId,
orElse: () => _mockRoutes.first,
);
}
@override
Future<bool> updateRouteStatus(String routeId, RouteStatus status) async {
await Future.delayed(const Duration(milliseconds: 500));
return true;
}
@override
Future<bool> updateStopStatus(
String routeId,
String stopId,
StopStatus status, {
String? signature,
String? photo,
String? notes,
}) async {
await Future.delayed(const Duration(milliseconds: 500));
return true;
}
@override
Future<bool> reportIssue(String routeId, String stopId, String issue) async {
await Future.delayed(const Duration(milliseconds: 500));
return true;
}
}
```
2. Use it in `main.dart`:
```dart
void main() {
// Use mock service for development
// RouteApiService().initialize(); // Production
// In development, the provider will use mock data automatically
runApp(const FleetDriverApp());
}
```
## Mock Data Generator
Here's a utility to generate random mock data for testing:
```dart
import 'dart:math';
import 'package:uuid/uuid.dart';
class MockDataGenerator {
static final _random = Random();
static final _uuid = Uuid();
static final List<String> _customerNames = [
'Acme Corporation',
'Tech Solutions Inc',
'Global Supplies Ltd',
'Downtown Retail',
'Bay Area Logistics',
'Pacific Trading Co',
'Metro Wholesale',
'Summit Distribution',
];
static final List<String> _addresses = [
'123 Market St, San Francisco, CA',
'456 Mission St, San Francisco, CA',
'789 Howard St, San Francisco, CA',
'321 Broadway, San Francisco, CA',
'654 Valencia St, San Francisco, CA',
'987 Geary Blvd, San Francisco, CA',
];
static final List<String> _items = [
'Package A',
'Package B',
'Package C',
'Box 1',
'Box 2',
'Crate 1',
'Pallet A',
'Container X',
];
static RouteModel generateRoute({
required String driverId,
int stopCount = 3,
}) {
final stops = List.generate(
stopCount,
(index) => generateStop(orderNumber: index + 1),
);
return RouteModel(
id: 'RT${_random.nextInt(9999).toString().padLeft(4, '0')}',
driverId: driverId,
driverName: 'Driver ${_random.nextInt(100)}',
date: DateTime.now().add(Duration(days: _random.nextInt(7))),
status: RouteStatus.values[_random.nextInt(RouteStatus.values.length)],
stops: stops,
totalDistance: 20.0 + _random.nextDouble() * 80,
estimatedDuration: 60 + _random.nextInt(180),
vehicleId: 'VH${_random.nextInt(999)}',
);
}
static StopModel generateStop({required int orderNumber}) {
return StopModel(
id: _uuid.v4(),
customerId: 'C${_random.nextInt(9999)}',
customerName: _customerNames[_random.nextInt(_customerNames.length)],
customerPhone: '+1${_random.nextInt(999999999).toString().padLeft(9, '0')}',
location: LocationModel(
latitude: 37.7749 + (_random.nextDouble() - 0.5) * 0.1,
longitude: -122.4194 + (_random.nextDouble() - 0.5) * 0.1,
address: _addresses[_random.nextInt(_addresses.length)],
),
type: _random.nextBool() ? StopType.pickup : StopType.dropoff,
status: StopStatus.values[_random.nextInt(StopStatus.values.length)],
scheduledTime: DateTime.now().add(Duration(hours: orderNumber)),
items: List.generate(
1 + _random.nextInt(4),
(_) => _items[_random.nextInt(_items.length)],
),
orderNumber: orderNumber,
);
}
static List<RouteModel> generateRoutes({
required String driverId,
int count = 5,
}) {
return List.generate(
count,
(_) => generateRoute(driverId: driverId),
);
}
}
```
### Usage:
```dart
// In route_api_service.dart
Future<List<RouteModel>> getDriverRoutes(String driverId) async {
await Future.delayed(const Duration(seconds: 1));
return MockDataGenerator.generateRoutes(driverId: driverId, count: 5);
}
```
## Testing with Mock Data
### Local Testing
1. Use mock data during development
2. Test all UI states (loading, error, empty, success)
3. Test edge cases (no routes, single route, many routes)
### State Testing
Test different route and stop statuses:
- Routes: notStarted, inProgress, completed, cancelled
- Stops: pending, inProgress, completed, failed
### Example Test Scenarios
```dart
// Test empty state
Future<List<RouteModel>> getDriverRoutes(String driverId) async {
return [];
}
// Test error state
Future<List<RouteModel>> getDriverRoutes(String driverId) async {
throw Exception('Network error');
}
// Test single route
Future<List<RouteModel>> getDriverRoutes(String driverId) async {
return [MockDataGenerator.generateRoute(driverId: driverId)];
}
// Test many routes
Future<List<RouteModel>> getDriverRoutes(String driverId) async {
return MockDataGenerator.generateRoutes(driverId: driverId, count: 20);
}
```
## Switching to Real API
When your backend is ready:
1. Update API base URL in `lib/core/constants/app_constants.dart`:
```dart
static const String baseApiUrl = 'https://your-api-url.com/api';
```
2. Remove mock data from `route_api_service.dart`
3. Ensure your API returns data in the expected format (matching the models)
4. Test with real API:
```bash
flutter run --dart-define=API_URL=https://your-api-url.com/api
```
## API Response Format
Your backend should return JSON in this format:
### Get Routes Response
```json
[
{
"id": "RT001",
"driverId": "driver_1",
"driverName": "John Doe",
"date": "2025-10-27T10:00:00Z",
"status": "notStarted",
"totalDistance": 45.5,
"estimatedDuration": 120,
"vehicleId": "VH123",
"stops": [
{
"id": "ST001",
"customerId": "C001",
"customerName": "Acme Corporation",
"customerPhone": "+1234567890",
"location": {
"latitude": 37.7749,
"longitude": -122.4194,
"address": "123 Market St, San Francisco, CA"
},
"type": "pickup",
"status": "pending",
"scheduledTime": "2025-10-27T11:00:00Z",
"items": ["Package A", "Package B"],
"orderNumber": 1
}
]
}
]
```
## Tips for Mock Data
1. **Use realistic data**: Coordinates, addresses, names
2. **Test edge cases**: Empty lists, null values, long strings
3. **Simulate delays**: Add realistic network delays
4. **Test errors**: Simulate network failures and API errors
5. **Use different statuses**: Test all possible states
6. **Generate varied data**: Different route lengths, stop counts
7. **Include optional fields**: Test with and without optional data

346
PROJECT_STRUCTURE.md Normal file
View File

@ -0,0 +1,346 @@
# Project Structure Documentation
## Architecture Overview
This project follows a **Feature-First Clean Architecture** approach, organizing code by features rather than layers. This makes the codebase more maintainable and scalable.
## Directory Structure
### `/lib/core/`
Contains shared resources used across the entire application.
#### `/core/constants/`
- **app_constants.dart**: Application-wide constants
- API endpoints
- Configuration values
- App metadata
- Default settings
#### `/core/theme/`
- **app_theme.dart**: Application theme configuration
- Color schemes
- Text styles
- Component themes
- Helper methods for dynamic theming
#### `/core/utils/`
Utility functions and helper classes (to be added as needed)
- Date formatting helpers
- Validation functions
- Common calculations
#### `/core/widgets/`
Reusable widgets used throughout the app
- **status_badge.dart**: Badge widget for displaying status
### `/lib/features/`
Feature-based modules following clean architecture principles.
#### `/features/routes/`
Main feature for route management.
##### `/features/routes/data/`
Data layer - handles data sources and models.
**`/data/models/`**
- **location_model.dart**: Location data with latitude/longitude
- **stop_model.dart**: Stop information (pickup/dropoff)
- **route_model.dart**: Route details with stops and metadata
**`/data/repositories/`**
Implementation of repository interfaces (to be added as needed)
##### `/features/routes/domain/`
Domain layer - business logic and entities.
**`/domain/entities/`**
Pure business objects (if needed, separate from models)
**`/domain/repositories/`**
Repository interfaces/contracts
##### `/features/routes/presentation/`
Presentation layer - UI and state management.
**`/presentation/pages/`**
- **home_page.dart**: Main dashboard showing all routes
- **route_details_page.dart**: Detailed view of a single route
- **map_view_page.dart**: Map view showing all stops
**`/presentation/widgets/`**
Feature-specific widgets:
- **route_card.dart**: Card displaying route summary
- **stop_card.dart**: Card displaying stop information
**`/presentation/providers/`**
State management using Provider:
- **route_provider.dart**: Manages route state and business logic
#### `/features/navigation/`
Navigation-related features (to be expanded)
### `/lib/services/`
Application-wide services.
#### `/services/location/`
- **location_service.dart**: Handles device location
- Get current position
- Track location changes
- Handle permissions
- Calculate distances
#### `/services/maps/`
- **navigation_service.dart**: Google Maps navigation
- Open Google Maps navigation
- Open Apple Maps (fallback)
- Handle navigation URLs
#### `/services/api/`
- **route_api_service.dart**: Backend API communication
- Fetch routes
- Update route status
- Update stop status
- Report issues
### `/lib/main.dart`
Application entry point:
- Initializes services
- Sets up providers
- Configures app theme
- Defines root widget
## Data Flow
```
UI (Pages/Widgets)
Providers (State Management)
Services/Repositories
API/Data Sources
```
### Example: Loading Routes
1. **UI**: `HomePage` requests routes in `initState`
2. **Provider**: `RouteProvider.loadRoutes()` is called
3. **Service**: `RouteApiService.getDriverRoutes()` fetches data
4. **API**: Makes HTTP request to backend
5. **Response**: Data flows back up through the layers
6. **UI**: Provider notifies listeners, UI rebuilds with data
## State Management
Using **Provider** package for state management:
- **ChangeNotifier**: Used in providers to notify UI of changes
- **Consumer**: Used in widgets to listen to provider changes
- **Provider.of / context.read/watch**: Access provider data
### Example Usage
```dart
// In widget
Consumer<RouteProvider>(
builder: (context, routeProvider, child) {
return Text(routeProvider.currentRoute?.id ?? 'No route');
},
)
// Or
final routeProvider = context.watch<RouteProvider>();
// For actions (no rebuild)
context.read<RouteProvider>().loadRoutes(driverId);
```
## Models
### Location Model
```dart
LocationModel {
double latitude
double longitude
String? address
}
```
### Stop Model
```dart
StopModel {
String id
String customerId
String customerName
String? customerPhone
LocationModel location
StopType type // pickup | dropoff
StopStatus status // pending | inProgress | completed | failed
DateTime scheduledTime
DateTime? completedTime
String? notes
List<String> items
int orderNumber
String? signature
String? photo
}
```
### Route Model
```dart
RouteModel {
String id
String driverId
String driverName
DateTime date
RouteStatus status // notStarted | inProgress | completed | cancelled
List<StopModel> stops
double totalDistance
int estimatedDuration
DateTime? startTime
DateTime? endTime
String? vehicleId
String? notes
}
```
## Key Dependencies
### Core Dependencies
- **flutter**: UI framework
- **provider**: State management
- **google_maps_flutter**: Map integration
- **geolocator**: Location services
- **permission_handler**: Handle permissions
### Network & Data
- **dio**: HTTP client
- **url_launcher**: Open external apps
### Utilities
- **intl**: Internationalization and date formatting
- **uuid**: Generate unique identifiers
## Adding New Features
### Steps to Add a New Feature
1. **Create feature directory structure**
```
lib/features/new_feature/
├── data/
│ ├── models/
│ └── repositories/
├── domain/
│ ├── entities/
│ └── repositories/
└── presentation/
├── pages/
├── widgets/
└── providers/
```
2. **Create models** in `data/models/`
3. **Create services** if needed in `lib/services/`
4. **Create provider** in `presentation/providers/`
5. **Create UI** in `presentation/pages/` and `presentation/widgets/`
6. **Register provider** in `main.dart`:
```dart
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => RouteProvider()),
ChangeNotifierProvider(create: (_) => NewFeatureProvider()),
],
// ...
)
```
## Best Practices
### Code Organization
- Keep files small and focused
- One class per file
- Use meaningful names
- Group related functionality
### State Management
- Use Provider for global state
- Use StatefulWidget for local state
- Keep business logic in providers
- Keep UI logic in widgets
### Models
- Include `fromJson` and `toJson` methods
- Include `copyWith` method for immutability
- Add computed properties when useful
- Use enums for fixed values
### Services
- Make services singleton where appropriate
- Handle errors gracefully
- Log important operations
- Use async/await for asynchronous operations
### UI
- Extract reusable widgets
- Use const constructors when possible
- Follow Material Design guidelines
- Handle loading and error states
## Testing Strategy
### Unit Tests
- Test models (fromJson, toJson, copyWith)
- Test business logic in providers
- Test utility functions
### Widget Tests
- Test individual widgets
- Test widget interactions
- Test state changes
### Integration Tests
- Test complete user flows
- Test API integration
- Test navigation
## Performance Considerations
### Optimization Tips
- Use `const` constructors where possible
- Avoid rebuilding entire widget trees
- Use `ListView.builder` for long lists
- Optimize images and assets
- Cache network responses
- Use `compute` for heavy computations
### Memory Management
- Dispose controllers and streams
- Cancel subscriptions
- Clear caches when appropriate
- Monitor memory usage
## Future Enhancements
### Planned Features
1. Offline mode with local database
2. Push notifications
3. Real-time tracking
4. Analytics and reporting
5. Multi-language support
6. Dark mode
7. Driver authentication
8. Chat with dispatcher
### Technical Improvements
1. Add unit tests
2. Add integration tests
3. Implement CI/CD
4. Add error tracking (e.g., Sentry)
5. Add analytics (e.g., Firebase Analytics)
6. Implement proper logging
7. Add code generation (e.g., freezed, json_serializable)

154
README.md Normal file
View File

@ -0,0 +1,154 @@
# Fleet Driver App
A mobile application for drivers to manage delivery routes, handle pickups/dropoffs, and navigate to destinations with integrated Google Maps navigation.
## Features
- View and manage assigned delivery routes
- Track route progress in real-time
- View pickup and dropoff locations with details
- Integrated Google Maps navigation to destinations
- Mark stops as completed
- Real-time location tracking
- Interactive map view of all stops
- Route status management
- Stop status tracking (pending, in progress, completed, failed)
## Tech Stack
- **Flutter** - UI framework
- **Provider** - State management
- **Google Maps Flutter** - Map integration
- **Geolocator** - Location services
- **Dio** - HTTP client for API calls
- **URL Launcher** - Navigation integration
## Quick Start
1. **Clone the repository**
```bash
git clone <your-repo-url>
cd flutter_fleet_logistic_workforce_app
```
2. **Install dependencies**
```bash
flutter pub get
```
3. **Configure Google Maps API Key**
- Get your API key from [Google Cloud Console](https://console.cloud.google.com/)
- See [SETUP_GUIDE.md](SETUP_GUIDE.md) for detailed configuration steps
4. **Run the app**
```bash
flutter run
```
## Documentation
- **[SETUP_GUIDE.md](SETUP_GUIDE.md)** - Detailed setup and configuration instructions
- **[PROJECT_STRUCTURE.md](PROJECT_STRUCTURE.md)** - Architecture and code organization
## Project Structure
```
lib/
├── core/ # Shared resources
│ ├── constants/ # App constants
│ ├── theme/ # Theme configuration
│ └── widgets/ # Reusable widgets
├── features/ # Feature modules
│ └── routes/ # Route management feature
│ ├── data/ # Models and repositories
│ ├── domain/ # Business logic
│ └── presentation/ # UI and state management
├── services/ # App services
│ ├── location/ # Location tracking
│ ├── maps/ # Navigation
│ └── api/ # Backend API
└── main.dart # App entry point
```
## Screenshots
Coming soon...
## Requirements
- Flutter SDK >=3.7.2
- Dart SDK
- Android SDK (for Android)
- Xcode (for iOS)
- Google Maps API Key
## Configuration
### Android
Update `android/app/src/main/AndroidManifest.xml` with your Google Maps API key.
### iOS
Update `ios/Runner/AppDelegate.swift` with your Google Maps API key.
See [SETUP_GUIDE.md](SETUP_GUIDE.md) for detailed instructions.
## API Integration
The app is designed to work with a backend API. Configure your API endpoint in:
```dart
lib/core/constants/app_constants.dart
```
Expected API endpoints:
- `GET /routes/:driverId` - Get driver routes
- `GET /routes/detail/:routeId` - Get route details
- `PUT /routes/:routeId/status` - Update route status
- `PUT /stops/:stopId/status` - Update stop status
## Development
### Run in development mode
```bash
flutter run
```
### Build for production
```bash
# Android
flutter build apk --release
# iOS
flutter build ios --release
```
### Run tests
```bash
flutter test
```
## Future Enhancements
- [ ] Offline mode with local storage
- [ ] Photo capture for proof of delivery
- [ ] Digital signature collection
- [ ] Push notifications
- [ ] Route optimization
- [ ] Driver performance metrics
- [ ] Multi-language support
- [ ] Dark mode
## Contributing
1. Fork the repository
2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
4. Push to the branch (`git push origin feature/AmazingFeature`)
5. Open a Pull Request
## License
This project is proprietary software. All rights reserved.
## Support
For support, please contact your development team or open an issue in the repository.

233
SETUP_GUIDE.md Normal file
View File

@ -0,0 +1,233 @@
# Fleet Driver App - Setup Guide
## Overview
This is a mobile application for drivers to manage their delivery routes, handle pickups/dropoffs, and navigate to destinations using Google Maps integration.
## Prerequisites
- Flutter SDK 3.7.2 or higher
- Dart SDK
- Android Studio / Xcode
- Google Maps API Key
## Getting Started
### 1. Install Dependencies
```bash
flutter pub get
```
### 2. Configure Google Maps API Key
#### Get Your API Key
1. Go to [Google Cloud Console](https://console.cloud.google.com/)
2. Create a new project or select an existing one
3. Enable the following APIs:
- Maps SDK for Android
- Maps SDK for iOS
- Directions API (for navigation)
- Places API (optional, for address autocomplete)
4. Create credentials (API Key)
5. Copy your API key
#### Android Configuration
1. Open `android/app/src/main/AndroidManifest.xml`
2. Replace `YOUR_GOOGLE_MAPS_API_KEY_HERE` with your actual API key:
```xml
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="YOUR_ACTUAL_API_KEY"/>
```
#### iOS Configuration
1. Open `ios/Runner/AppDelegate.swift`
2. Replace `YOUR_GOOGLE_MAPS_API_KEY_HERE` with your actual API key:
```swift
GMSServices.provideAPIKey("YOUR_ACTUAL_API_KEY")
```
### 3. Configure Backend API (Optional)
If you have a backend API, update the API configuration in:
`lib/core/constants/app_constants.dart`
```dart
static const String baseApiUrl = 'https://your-api-url.com/api';
```
### 4. Run the App
#### Android
```bash
flutter run
```
#### iOS
```bash
cd ios
pod install
cd ..
flutter run
```
## Project Structure
```
lib/
├── core/
│ ├── constants/ # App-wide constants
│ ├── theme/ # App theme and colors
│ ├── utils/ # Utility functions
│ └── widgets/ # Reusable widgets
├── features/
│ ├── routes/
│ │ ├── data/
│ │ │ ├── models/ # Data models
│ │ │ └── repositories/
│ │ ├── domain/
│ │ │ ├── entities/
│ │ │ └── repositories/
│ │ └── presentation/
│ │ ├── pages/ # UI screens
│ │ ├── widgets/ # Feature-specific widgets
│ │ └── providers/ # State management
│ │
│ └── navigation/
├── services/
│ ├── location/ # Location services
│ ├── maps/ # Navigation services
│ └── api/ # API services
└── main.dart # App entry point
```
## Features
### Current Features
1. **Route Management**
- View assigned routes
- Track route progress
- Start/complete routes
2. **Stop Management**
- View pickup and dropoff locations
- Navigate to stops
- Mark stops as completed
- View stop details (customer info, items, etc.)
3. **Map Integration**
- View all stops on a map
- Real-time location tracking
- Navigate to destinations using Google Maps
4. **Status Tracking**
- Route status (not started, in progress, completed)
- Stop status (pending, in progress, completed, failed)
- Progress indicators
### Upcoming Features
- Photo capture for proof of delivery
- Signature collection
- Offline mode
- Push notifications
- Route optimization
- Driver performance metrics
## API Integration
The app is designed to work with a backend API. The main API endpoints expected are:
- `GET /routes/:driverId` - Get driver routes
- `GET /routes/detail/:routeId` - Get route details
- `PUT /routes/:routeId/status` - Update route status
- `PUT /stops/:stopId/status` - Update stop status
- `POST /stops/:stopId/issue` - Report an issue
### Mock Data for Development
If you don't have a backend yet, you can modify the `RouteApiService` to return mock data:
```dart
// In lib/services/api/route_api_service.dart
Future<List<RouteModel>> getDriverRoutes(String driverId) async {
// Return mock data instead of API call
return [
// Your mock route data here
];
}
```
## Permissions
### Android
The following permissions are configured in `AndroidManifest.xml`:
- `INTERNET` - For API calls
- `ACCESS_FINE_LOCATION` - For precise location
- `ACCESS_COARSE_LOCATION` - For approximate location
- `FOREGROUND_SERVICE` - For background location tracking
### iOS
The following permissions are configured in `Info.plist`:
- Location When In Use
- Location Always (for background tracking)
## Troubleshooting
### Google Maps Not Showing
1. Verify your API key is correct
2. Make sure you've enabled the required APIs in Google Cloud Console
3. Check if you've restricted your API key (it should allow your app's package name)
### Location Not Working
1. Check device location settings are enabled
2. Grant location permissions when prompted
3. Test on a real device (emulators may have location issues)
### Build Errors
```bash
# Clean and rebuild
flutter clean
flutter pub get
flutter run
```
## Testing
```bash
# Run tests
flutter test
# Run with coverage
flutter test --coverage
```
## Building for Production
### Android
```bash
flutter build apk --release
# or
flutter build appbundle --release
```
### iOS
```bash
flutter build ios --release
```
## Support
For issues or questions, please contact your development team or refer to the Flutter documentation at https://flutter.dev/docs

28
analysis_options.yaml Normal file
View File

@ -0,0 +1,28 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

14
android/.gitignore vendored Normal file
View File

@ -0,0 +1,14 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
.cxx/
# Remember to never publicly share your keystore.
# See https://flutter.dev/to/reference-keystore
key.properties
**/*.keystore
**/*.jks

View File

@ -0,0 +1,44 @@
plugins {
id("com.android.application")
id("kotlin-android")
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id("dev.flutter.flutter-gradle-plugin")
}
android {
namespace = "io.svrnty.flutter_fleet_logistic_workforce_app"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "io.svrnty.flutter_fleet_logistic_workforce_app"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.getByName("debug")
}
}
}
flutter {
source = "../.."
}

View File

@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@ -0,0 +1,56 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Permissions -->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<application
android:label="flutter_fleet_logistic_workforce_app"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
<!-- Google Maps API Key -->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="YOUR_GOOGLE_MAPS_API_KEY_HERE"/>
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
</manifest>

View File

@ -0,0 +1,5 @@
package io.svrnty.flutter_fleet_logistic_workforce_app
import io.flutter.embedding.android.FlutterActivity
class MainActivity : FlutterActivity()

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

21
android/build.gradle.kts Normal file
View File

@ -0,0 +1,21 @@
allprojects {
repositories {
google()
mavenCentral()
}
}
val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get()
rootProject.layout.buildDirectory.value(newBuildDir)
subprojects {
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
project.layout.buildDirectory.value(newSubprojectBuildDir)
}
subprojects {
project.evaluationDependsOn(":app")
}
tasks.register<Delete>("clean") {
delete(rootProject.layout.buildDirectory)
}

View File

@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true

View File

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip

View File

@ -0,0 +1,25 @@
pluginManagement {
val flutterSdkPath = run {
val properties = java.util.Properties()
file("local.properties").inputStream().use { properties.load(it) }
val flutterSdkPath = properties.getProperty("flutter.sdk")
require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
flutterSdkPath
}
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
id("com.android.application") version "8.7.0" apply false
id("org.jetbrains.kotlin.android") version "1.8.22" apply false
}
include(":app")

34
ios/.gitignore vendored Normal file
View File

@ -0,0 +1,34 @@
**/dgph
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>12.0</string>
</dict>
</plist>

View File

@ -0,0 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"

View File

@ -0,0 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"

43
ios/Podfile Normal file
View File

@ -0,0 +1,43 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '12.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end

View File

@ -0,0 +1,619 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
proxyType = 1;
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
remoteInfo = Runner;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
331C8082294A63A400263BE5 /* RunnerTests */ = {
isa = PBXGroup;
children = (
331C807B294A618700263BE5 /* RunnerTests.swift */,
);
path = RunnerTests;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
331C8080294A63A400263BE5 /* RunnerTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */,
);
buildRules = (
);
dependencies = (
331C8086294A63A400263BE5 /* PBXTargetDependency */,
);
name = RunnerTests;
productName = RunnerTests;
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
331C8080294A63A400263BE5 = {
CreatedOnToolsVersion = 14.0;
TestTargetID = 97C146ED1CF9000F007C117D;
};
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
331C8080294A63A400263BE5 /* RunnerTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
331C807F294A63A400263BE5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
331C807D294A63A400263BE5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 97C146ED1CF9000F007C117D /* Runner */;
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = LD76P8L42W;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = io.svrnty.flutterFleetLogisticWorkforceApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
331C8088294A63A400263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = io.svrnty.flutterFleetLogisticWorkforceApp.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Debug;
};
331C8089294A63A400263BE5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = io.svrnty.flutterFleetLogisticWorkforceApp.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Release;
};
331C808A294A63A400263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = io.svrnty.flutterFleetLogisticWorkforceApp.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = LD76P8L42W;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = io.svrnty.flutterFleetLogisticWorkforceApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = LD76P8L42W;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = io.svrnty.flutterFleetLogisticWorkforceApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
331C8088294A63A400263BE5 /* Debug */,
331C8089294A63A400263BE5 /* Release */,
331C808A294A63A400263BE5 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "331C8080294A63A400263BE5"
BuildableName = "RunnerTests.xctest"
BlueprintName = "RunnerTests"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
enableGPUValidationMode = "1"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@ -0,0 +1,17 @@
import Flutter
import UIKit
import GoogleMaps
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Configure Google Maps with API Key
GMSServices.provideAPIKey("YOUR_GOOGLE_MAPS_API_KEY_HERE")
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}

View File

@ -0,0 +1,122 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 762 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

View File

@ -0,0 +1,5 @@
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>

64
ios/Runner/Info.plist Normal file
View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Flutter Fleet Logistic Workforce App</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>flutter_fleet_logistic_workforce_app</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<!-- Location Permissions -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs location access to show your current position and navigate to destinations.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app needs location access to track your route progress in the background.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app needs location access to track your route progress in the background.</string>
<!-- Google Maps URL Scheme -->
<key>LSApplicationQueriesSchemes</key>
<array>
<string>comgooglemaps</string>
<string>googlemaps</string>
</array>
</dict>
</plist>

View File

@ -0,0 +1 @@
#import "GeneratedPluginRegistrant.h"

View File

@ -0,0 +1,12 @@
import Flutter
import UIKit
import XCTest
class RunnerTests: XCTestCase {
func testExample() {
// If you add code to the Runner application, consider adding tests here.
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
}
}

View File

@ -0,0 +1,36 @@
class AppConstants {
// App Info
static const String appName = 'Fleet Driver';
static const String appVersion = '1.0.0';
// Google Maps
static const String googleMapsApiKey = 'YOUR_GOOGLE_MAPS_API_KEY_HERE';
// Navigation URLs
static const String googleMapsUrlScheme = 'comgooglemaps://';
static const String appleMapsUrlScheme = 'maps://';
// API Endpoints (Replace with your actual backend URL)
static const String baseApiUrl = 'https://your-api-url.com/api';
static const String routesEndpoint = '/routes';
static const String stopsEndpoint = '/stops';
static const String updateStatusEndpoint = '/update-status';
// Timeouts
static const int apiTimeout = 30; // seconds
static const int locationUpdateInterval = 5; // seconds
// Permissions
static const String locationPermissionMessage =
'This app needs location access to show your current position and navigate to destinations.';
// Local Storage Keys
static const String driverIdKey = 'driver_id';
static const String driverNameKey = 'driver_name';
static const String authTokenKey = 'auth_token';
// Map Settings
static const double defaultZoom = 15.0;
static const double defaultTilt = 0.0;
static const double defaultBearing = 0.0;
}

View File

@ -0,0 +1,150 @@
import 'package:flutter/material.dart';
class AppTheme {
// Colors
static const Color primaryColor = Color(0xFF2196F3);
static const Color secondaryColor = Color(0xFF03DAC6);
static const Color backgroundColor = Color(0xFFF5F5F5);
static const Color surfaceColor = Colors.white;
static const Color errorColor = Color(0xFFB00020);
static const Color successColor = Color(0xFF4CAF50);
static const Color warningColor = Color(0xFFFFC107);
// Status Colors
static const Color pendingColor = Color(0xFFFF9800);
static const Color inProgressColor = Color(0xFF2196F3);
static const Color completedColor = Color(0xFF4CAF50);
static const Color failedColor = Color(0xFFB00020);
// Text Colors
static const Color textPrimaryColor = Color(0xFF212121);
static const Color textSecondaryColor = Color(0xFF757575);
static const Color textHintColor = Color(0xFFBDBDBD);
static ThemeData get lightTheme {
return ThemeData(
primaryColor: primaryColor,
scaffoldBackgroundColor: backgroundColor,
colorScheme: const ColorScheme.light(
primary: primaryColor,
secondary: secondaryColor,
surface: surfaceColor,
error: errorColor,
),
appBarTheme: const AppBarTheme(
backgroundColor: primaryColor,
foregroundColor: Colors.white,
elevation: 2,
centerTitle: true,
titleTextStyle: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
cardTheme: CardTheme(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: primaryColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
textStyle: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
floatingActionButtonTheme: const FloatingActionButtonThemeData(
backgroundColor: primaryColor,
foregroundColor: Colors.white,
),
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: Colors.white,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.grey),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.grey),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: primaryColor, width: 2),
),
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
),
textTheme: const TextTheme(
displayLarge: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
color: textPrimaryColor,
),
displayMedium: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: textPrimaryColor,
),
displaySmall: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: textPrimaryColor,
),
headlineMedium: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
color: textPrimaryColor,
),
titleLarge: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: textPrimaryColor,
),
titleMedium: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: textPrimaryColor,
),
bodyLarge: TextStyle(
fontSize: 16,
color: textPrimaryColor,
),
bodyMedium: TextStyle(
fontSize: 14,
color: textSecondaryColor,
),
bodySmall: TextStyle(
fontSize: 12,
color: textSecondaryColor,
),
),
);
}
static Color getStatusColor(String status) {
switch (status.toLowerCase()) {
case 'pending':
case 'notstartedCamel':
return pendingColor;
case 'inprogress':
return inProgressColor;
case 'completed':
return completedColor;
case 'failed':
case 'cancelled':
return failedColor;
default:
return textSecondaryColor;
}
}
}

View File

@ -0,0 +1,55 @@
import 'package:flutter/material.dart';
import '../theme/app_theme.dart';
class StatusBadge extends StatelessWidget {
final String status;
final double? fontSize;
const StatusBadge({
super.key,
required this.status,
this.fontSize,
});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: AppTheme.getStatusColor(status).withOpacity(0.2),
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: AppTheme.getStatusColor(status),
width: 1.5,
),
),
child: Text(
_formatStatus(status),
style: TextStyle(
color: AppTheme.getStatusColor(status),
fontWeight: FontWeight.bold,
fontSize: fontSize ?? 12,
),
),
);
}
String _formatStatus(String status) {
switch (status.toLowerCase()) {
case 'pending':
return 'Pending';
case 'notstarted':
return 'Not Started';
case 'inprogress':
return 'In Progress';
case 'completed':
return 'Completed';
case 'failed':
return 'Failed';
case 'cancelled':
return 'Cancelled';
default:
return status;
}
}
}

View File

@ -0,0 +1,39 @@
class LocationModel {
final double latitude;
final double longitude;
final String? address;
LocationModel({
required this.latitude,
required this.longitude,
this.address,
});
factory LocationModel.fromJson(Map<String, dynamic> json) {
return LocationModel(
latitude: json['latitude'] as double,
longitude: json['longitude'] as double,
address: json['address'] as String?,
);
}
Map<String, dynamic> toJson() {
return {
'latitude': latitude,
'longitude': longitude,
'address': address,
};
}
LocationModel copyWith({
double? latitude,
double? longitude,
String? address,
}) {
return LocationModel(
latitude: latitude ?? this.latitude,
longitude: longitude ?? this.longitude,
address: address ?? this.address,
);
}
}

View File

@ -0,0 +1,118 @@
import 'stop_model.dart';
enum RouteStatus { notStarted, inProgress, completed, cancelled }
class RouteModel {
final String id;
final String driverId;
final String driverName;
final DateTime date;
final RouteStatus status;
final List<StopModel> stops;
final double totalDistance; // in kilometers
final int estimatedDuration; // in minutes
final DateTime? startTime;
final DateTime? endTime;
final String? vehicleId;
final String? notes;
RouteModel({
required this.id,
required this.driverId,
required this.driverName,
required this.date,
required this.status,
required this.stops,
required this.totalDistance,
required this.estimatedDuration,
this.startTime,
this.endTime,
this.vehicleId,
this.notes,
});
factory RouteModel.fromJson(Map<String, dynamic> json) {
return RouteModel(
id: json['id'] as String,
driverId: json['driverId'] as String,
driverName: json['driverName'] as String,
date: DateTime.parse(json['date'] as String),
status: RouteStatus.values.firstWhere(
(e) => e.toString() == 'RouteStatus.${json['status']}',
),
stops: (json['stops'] as List<dynamic>)
.map((stop) => StopModel.fromJson(stop as Map<String, dynamic>))
.toList(),
totalDistance: (json['totalDistance'] as num).toDouble(),
estimatedDuration: json['estimatedDuration'] as int,
startTime: json['startTime'] != null
? DateTime.parse(json['startTime'] as String)
: null,
endTime: json['endTime'] != null
? DateTime.parse(json['endTime'] as String)
: null,
vehicleId: json['vehicleId'] as String?,
notes: json['notes'] as String?,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'driverId': driverId,
'driverName': driverName,
'date': date.toIso8601String(),
'status': status.toString().split('.').last,
'stops': stops.map((stop) => stop.toJson()).toList(),
'totalDistance': totalDistance,
'estimatedDuration': estimatedDuration,
'startTime': startTime?.toIso8601String(),
'endTime': endTime?.toIso8601String(),
'vehicleId': vehicleId,
'notes': notes,
};
}
RouteModel copyWith({
String? id,
String? driverId,
String? driverName,
DateTime? date,
RouteStatus? status,
List<StopModel>? stops,
double? totalDistance,
int? estimatedDuration,
DateTime? startTime,
DateTime? endTime,
String? vehicleId,
String? notes,
}) {
return RouteModel(
id: id ?? this.id,
driverId: driverId ?? this.driverId,
driverName: driverName ?? this.driverName,
date: date ?? this.date,
status: status ?? this.status,
stops: stops ?? this.stops,
totalDistance: totalDistance ?? this.totalDistance,
estimatedDuration: estimatedDuration ?? this.estimatedDuration,
startTime: startTime ?? this.startTime,
endTime: endTime ?? this.endTime,
vehicleId: vehicleId ?? this.vehicleId,
notes: notes ?? this.notes,
);
}
int get completedStopsCount =>
stops.where((stop) => stop.status == StopStatus.completed).length;
int get totalStopsCount => stops.length;
double get progressPercentage =>
totalStopsCount > 0 ? (completedStopsCount / totalStopsCount) * 100 : 0;
StopModel? get nextStop => stops.firstWhere(
(stop) => stop.status == StopStatus.pending,
orElse: () => stops.first,
);
}

View File

@ -0,0 +1,117 @@
import 'location_model.dart';
enum StopType { pickup, dropoff }
enum StopStatus { pending, inProgress, completed, failed }
class StopModel {
final String id;
final String customerId;
final String customerName;
final String? customerPhone;
final LocationModel location;
final StopType type;
final StopStatus status;
final DateTime scheduledTime;
final DateTime? completedTime;
final String? notes;
final List<String> items;
final int orderNumber;
final String? signature;
final String? photo;
StopModel({
required this.id,
required this.customerId,
required this.customerName,
this.customerPhone,
required this.location,
required this.type,
required this.status,
required this.scheduledTime,
this.completedTime,
this.notes,
required this.items,
required this.orderNumber,
this.signature,
this.photo,
});
factory StopModel.fromJson(Map<String, dynamic> json) {
return StopModel(
id: json['id'] as String,
customerId: json['customerId'] as String,
customerName: json['customerName'] as String,
customerPhone: json['customerPhone'] as String?,
location: LocationModel.fromJson(json['location'] as Map<String, dynamic>),
type: StopType.values.firstWhere(
(e) => e.toString() == 'StopType.${json['type']}',
),
status: StopStatus.values.firstWhere(
(e) => e.toString() == 'StopStatus.${json['status']}',
),
scheduledTime: DateTime.parse(json['scheduledTime'] as String),
completedTime: json['completedTime'] != null
? DateTime.parse(json['completedTime'] as String)
: null,
notes: json['notes'] as String?,
items: (json['items'] as List<dynamic>).cast<String>(),
orderNumber: json['orderNumber'] as int,
signature: json['signature'] as String?,
photo: json['photo'] as String?,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'customerId': customerId,
'customerName': customerName,
'customerPhone': customerPhone,
'location': location.toJson(),
'type': type.toString().split('.').last,
'status': status.toString().split('.').last,
'scheduledTime': scheduledTime.toIso8601String(),
'completedTime': completedTime?.toIso8601String(),
'notes': notes,
'items': items,
'orderNumber': orderNumber,
'signature': signature,
'photo': photo,
};
}
StopModel copyWith({
String? id,
String? customerId,
String? customerName,
String? customerPhone,
LocationModel? location,
StopType? type,
StopStatus? status,
DateTime? scheduledTime,
DateTime? completedTime,
String? notes,
List<String>? items,
int? orderNumber,
String? signature,
String? photo,
}) {
return StopModel(
id: id ?? this.id,
customerId: customerId ?? this.customerId,
customerName: customerName ?? this.customerName,
customerPhone: customerPhone ?? this.customerPhone,
location: location ?? this.location,
type: type ?? this.type,
status: status ?? this.status,
scheduledTime: scheduledTime ?? this.scheduledTime,
completedTime: completedTime ?? this.completedTime,
notes: notes ?? this.notes,
items: items ?? this.items,
orderNumber: orderNumber ?? this.orderNumber,
signature: signature ?? this.signature,
photo: photo ?? this.photo,
);
}
}

View File

@ -0,0 +1,227 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../../../core/theme/app_theme.dart';
import '../../data/models/route_model.dart';
import '../providers/route_provider.dart';
import '../widgets/route_card.dart';
import 'route_details_page.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
void initState() {
super.initState();
// Load routes for demo driver
// In production, use actual driver ID from authentication
Future.microtask(() {
context.read<RouteProvider>().loadRoutes('driver_1');
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('My Routes'),
actions: [
IconButton(
icon: const Icon(Icons.refresh),
onPressed: () {
context.read<RouteProvider>().loadRoutes('driver_1');
},
),
IconButton(
icon: const Icon(Icons.person),
onPressed: () {
// Navigate to profile page
},
),
],
),
body: Consumer<RouteProvider>(
builder: (context, routeProvider, child) {
if (routeProvider.isLoading) {
return const Center(
child: CircularProgressIndicator(),
);
}
if (routeProvider.error != null) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icons.error_outline,
size: 64,
color: AppTheme.errorColor,
),
const SizedBox(height: 16),
Text(
'Error loading routes',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 8),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 32),
child: Text(
routeProvider.error!,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium,
),
),
const SizedBox(height: 24),
ElevatedButton.icon(
onPressed: () {
routeProvider.loadRoutes('driver_1');
},
icon: const Icon(Icons.refresh),
label: const Text('Retry'),
),
],
),
);
}
if (routeProvider.routes.isEmpty) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icons.route,
size: 64,
color: Colors.grey,
),
const SizedBox(height: 16),
Text(
'No routes available',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 8),
Text(
'Check back later for new routes',
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
);
}
return RefreshIndicator(
onRefresh: () async {
await routeProvider.loadRoutes('driver_1');
},
child: ListView(
padding: const EdgeInsets.symmetric(vertical: 8),
children: [
_buildSummaryCard(context, routeProvider.routes),
const SizedBox(height: 8),
...routeProvider.routes.map((route) {
return RouteCard(
route: route,
onTap: () {
routeProvider.setCurrentRoute(route);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const RouteDetailsPage(),
),
);
},
);
}),
],
),
);
},
),
);
}
Widget _buildSummaryCard(BuildContext context, List<RouteModel> routes) {
final todayRoutes = routes.where((route) {
return route.date.day == DateTime.now().day &&
route.date.month == DateTime.now().month &&
route.date.year == DateTime.now().year;
}).toList();
final completedRoutes =
todayRoutes.where((r) => r.status == RouteStatus.completed).length;
return Card(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Today\'s Summary',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildSummaryItem(
context,
'Total Routes',
todayRoutes.length.toString(),
Icons.route,
AppTheme.primaryColor,
),
_buildSummaryItem(
context,
'Completed',
completedRoutes.toString(),
Icons.check_circle,
AppTheme.completedColor,
),
_buildSummaryItem(
context,
'Pending',
(todayRoutes.length - completedRoutes).toString(),
Icons.pending,
AppTheme.warningColor,
),
],
),
],
),
),
);
}
Widget _buildSummaryItem(
BuildContext context,
String label,
String value,
IconData icon,
Color color,
) {
return Column(
children: [
Icon(icon, color: color, size: 32),
const SizedBox(height: 8),
Text(
value,
style: Theme.of(context).textTheme.displaySmall?.copyWith(
color: color,
fontWeight: FontWeight.bold,
),
),
Text(
label,
style: Theme.of(context).textTheme.bodySmall,
),
],
);
}
}

View File

@ -0,0 +1,339 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import '../../../../core/constants/app_constants.dart';
import '../../../../core/theme/app_theme.dart';
import '../../../../services/location/location_service.dart';
import '../../data/models/route_model.dart';
import '../../data/models/stop_model.dart';
class MapViewPage extends StatefulWidget {
final RouteModel route;
const MapViewPage({super.key, required this.route});
@override
State<MapViewPage> createState() => _MapViewPageState();
}
class _MapViewPageState extends State<MapViewPage> {
final Completer<GoogleMapController> _mapController = Completer();
final LocationService _locationService = LocationService();
final Set<Marker> _markers = {};
final Set<Polyline> _polylines = {};
LatLng? _currentPosition;
StreamSubscription? _locationSubscription;
@override
void initState() {
super.initState();
_initializeMap();
_startLocationTracking();
}
@override
void dispose() {
_locationSubscription?.cancel();
super.dispose();
}
Future<void> _initializeMap() async {
await _createMarkers();
await _fitBounds();
}
Future<void> _createMarkers() async {
final markers = <Marker>{};
for (int i = 0; i < widget.route.stops.length; i++) {
final stop = widget.route.stops[i];
final position = LatLng(
stop.location.latitude,
stop.location.longitude,
);
markers.add(
Marker(
markerId: MarkerId(stop.id),
position: position,
icon: await _getMarkerIcon(stop),
infoWindow: InfoWindow(
title: '${i + 1}. ${stop.customerName}',
snippet: stop.type == StopType.pickup ? 'Pickup' : 'Dropoff',
),
onTap: () => _onMarkerTapped(stop),
),
);
}
if (mounted) {
setState(() {
_markers.addAll(markers);
});
}
}
Future<BitmapDescriptor> _getMarkerIcon(StopModel stop) async {
// Determine color based on status
final hue = switch (stop.status) {
StopStatus.completed => BitmapDescriptor.hueGreen,
StopStatus.inProgress => BitmapDescriptor.hueBlue,
StopStatus.failed => BitmapDescriptor.hueRed,
_ => BitmapDescriptor.hueOrange,
};
return BitmapDescriptor.defaultMarkerWithHue(hue);
}
Future<void> _fitBounds() async {
if (widget.route.stops.isEmpty) return;
final controller = await _mapController.future;
double minLat = widget.route.stops.first.location.latitude;
double maxLat = widget.route.stops.first.location.latitude;
double minLng = widget.route.stops.first.location.longitude;
double maxLng = widget.route.stops.first.location.longitude;
for (final stop in widget.route.stops) {
if (stop.location.latitude < minLat) minLat = stop.location.latitude;
if (stop.location.latitude > maxLat) maxLat = stop.location.latitude;
if (stop.location.longitude < minLng) minLng = stop.location.longitude;
if (stop.location.longitude > maxLng) maxLng = stop.location.longitude;
}
final bounds = LatLngBounds(
southwest: LatLng(minLat, minLng),
northeast: LatLng(maxLat, maxLng),
);
controller.animateCamera(
CameraUpdate.newLatLngBounds(bounds, 100),
);
}
void _startLocationTracking() {
_locationSubscription = _locationService.getLocationStream().listen(
(position) {
final newPosition = LatLng(position.latitude, position.longitude);
if (mounted) {
setState(() {
_currentPosition = newPosition;
// Add or update current location marker
_markers.removeWhere(
(marker) => marker.markerId.value == 'current_location',
);
_markers.add(
Marker(
markerId: const MarkerId('current_location'),
position: newPosition,
icon: BitmapDescriptor.defaultMarkerWithHue(
BitmapDescriptor.hueAzure,
),
infoWindow: const InfoWindow(title: 'Your Location'),
),
);
});
}
},
onError: (error) {
print('Error tracking location: $error');
},
);
}
void _onMarkerTapped(StopModel stop) {
showModalBottomSheet(
context: context,
builder: (context) => Container(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
stop.customerName,
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 8),
Text(
stop.type == StopType.pickup ? 'Pickup' : 'Dropoff',
style: Theme.of(context).textTheme.bodyMedium,
),
if (stop.location.address != null) ...[
const SizedBox(height: 8),
Text(
stop.location.address!,
style: Theme.of(context).textTheme.bodySmall,
),
],
const SizedBox(height: 16),
SizedBox(
width: double.infinity,
child: ElevatedButton.icon(
onPressed: () {
Navigator.pop(context);
_navigateToStop(stop);
},
icon: const Icon(Icons.navigation),
label: const Text('Navigate to this stop'),
),
),
],
),
),
);
}
Future<void> _navigateToStop(StopModel stop) async {
// This will use the NavigationService to open external navigation
final navigationService =
(() => throw UnimplementedError('Add NavigationService'))();
}
Future<void> _centerOnCurrentLocation() async {
if (_currentPosition != null) {
final controller = await _mapController.future;
controller.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(
target: _currentPosition!,
zoom: AppConstants.defaultZoom,
),
),
);
} else {
final position = await _locationService.getCurrentLocation();
if (position != null) {
final newPosition = LatLng(position.latitude, position.longitude);
final controller = await _mapController.future;
controller.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(
target: newPosition,
zoom: AppConstants.defaultZoom,
),
),
);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Route ${widget.route.id} Map'),
actions: [
IconButton(
icon: const Icon(Icons.layers),
onPressed: () {
// Toggle map type
},
),
],
),
body: Stack(
children: [
GoogleMap(
onMapCreated: (controller) {
_mapController.complete(controller);
},
initialCameraPosition: CameraPosition(
target: widget.route.stops.isNotEmpty
? LatLng(
widget.route.stops.first.location.latitude,
widget.route.stops.first.location.longitude,
)
: const LatLng(0, 0),
zoom: AppConstants.defaultZoom,
),
markers: _markers,
polylines: _polylines,
myLocationEnabled: true,
myLocationButtonEnabled: false,
mapToolbarEnabled: true,
zoomControlsEnabled: false,
),
Positioned(
top: 16,
left: 16,
right: 16,
child: Card(
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Route Progress',
style: Theme.of(context).textTheme.titleSmall,
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_buildLegendItem(
'Completed',
AppTheme.completedColor,
),
_buildLegendItem(
'In Progress',
AppTheme.inProgressColor,
),
_buildLegendItem(
'Pending',
AppTheme.pendingColor,
),
],
),
],
),
),
),
),
],
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
heroTag: 'center',
mini: true,
onPressed: _centerOnCurrentLocation,
child: const Icon(Icons.my_location),
),
const SizedBox(height: 12),
FloatingActionButton(
heroTag: 'fit',
mini: true,
onPressed: _fitBounds,
child: const Icon(Icons.zoom_out_map),
),
],
),
);
}
Widget _buildLegendItem(String label, Color color) {
return Row(
children: [
Container(
width: 12,
height: 12,
decoration: BoxDecoration(
color: color,
shape: BoxShape.circle,
),
),
const SizedBox(width: 4),
Text(
label,
style: const TextStyle(fontSize: 12),
),
],
);
}
}

View File

@ -0,0 +1,437 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:intl/intl.dart';
import '../../../../core/theme/app_theme.dart';
import '../../../../core/widgets/status_badge.dart';
import '../../../../services/location/location_service.dart';
import '../../../../services/maps/navigation_service.dart';
import '../../data/models/route_model.dart';
import '../../data/models/stop_model.dart';
import '../providers/route_provider.dart';
import '../widgets/stop_card.dart';
import 'map_view_page.dart';
class RouteDetailsPage extends StatelessWidget {
const RouteDetailsPage({super.key});
@override
Widget build(BuildContext context) {
return Consumer<RouteProvider>(
builder: (context, routeProvider, child) {
final route = routeProvider.currentRoute;
if (route == null) {
return Scaffold(
appBar: AppBar(
title: const Text('Route Details'),
),
body: const Center(
child: Text('No route selected'),
),
);
}
return Scaffold(
appBar: AppBar(
title: Text('Route ${route.id}'),
actions: [
IconButton(
icon: const Icon(Icons.map),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MapViewPage(route: route),
),
);
},
),
],
),
body: Column(
children: [
_buildRouteHeader(context, route),
const Divider(height: 1),
Expanded(
child: ListView.builder(
padding: const EdgeInsets.symmetric(vertical: 8),
itemCount: route.stops.length,
itemBuilder: (context, index) {
final stop = route.stops[index];
return StopCard(
stop: stop,
onTap: () {
_showStopDetails(context, route, stop);
},
onNavigate: () {
_navigateToStop(context, stop);
},
);
},
),
),
],
),
floatingActionButton: _buildActionButton(context, route),
);
},
);
}
Widget _buildRouteHeader(BuildContext context, RouteModel route) {
return Container(
padding: const EdgeInsets.all(16),
color: Colors.white,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
DateFormat('EEEE, MMM dd').format(route.date),
style: Theme.of(context).textTheme.titleMedium,
),
StatusBadge(
status: route.status.toString().split('.').last,
fontSize: 14,
),
],
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildInfoItem(
context,
Icons.route,
'${route.totalDistance.toStringAsFixed(1)} km',
'Distance',
),
_buildInfoItem(
context,
Icons.access_time,
'${route.estimatedDuration} min',
'Duration',
),
_buildInfoItem(
context,
Icons.location_on,
'${route.stops.length}',
'Stops',
),
],
),
const SizedBox(height: 16),
ClipRRect(
borderRadius: BorderRadius.circular(8),
child: LinearProgressIndicator(
value: route.progressPercentage / 100,
minHeight: 12,
backgroundColor: Colors.grey[300],
valueColor: AlwaysStoppedAnimation<Color>(
route.status == RouteStatus.completed
? AppTheme.completedColor
: AppTheme.inProgressColor,
),
),
),
const SizedBox(height: 8),
Text(
'${route.completedStopsCount}/${route.totalStopsCount} stops completed',
style: Theme.of(context).textTheme.bodySmall,
textAlign: TextAlign.center,
),
],
),
);
}
Widget _buildInfoItem(
BuildContext context,
IconData icon,
String value,
String label,
) {
return Column(
children: [
Icon(icon, color: AppTheme.primaryColor, size: 24),
const SizedBox(height: 8),
Text(
value,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
),
Text(
label,
style: Theme.of(context).textTheme.bodySmall,
),
],
);
}
Widget? _buildActionButton(BuildContext context, RouteModel route) {
if (route.status == RouteStatus.completed ||
route.status == RouteStatus.cancelled) {
return null;
}
final routeProvider = context.read<RouteProvider>();
if (route.status == RouteStatus.notStarted) {
return FloatingActionButton.extended(
onPressed: () async {
final success = await routeProvider.startRoute(route.id);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
success ? 'Route started!' : 'Failed to start route',
),
backgroundColor: success ? AppTheme.successColor : AppTheme.errorColor,
),
);
}
},
icon: const Icon(Icons.play_arrow),
label: const Text('Start Route'),
);
}
if (route.status == RouteStatus.inProgress) {
final allCompleted =
route.stops.every((stop) => stop.status == StopStatus.completed);
if (allCompleted) {
return FloatingActionButton.extended(
onPressed: () async {
final success = await routeProvider.completeRoute(route.id);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
success ? 'Route completed!' : 'Failed to complete route',
),
backgroundColor:
success ? AppTheme.successColor : AppTheme.errorColor,
),
);
}
},
icon: const Icon(Icons.check),
label: const Text('Complete Route'),
);
}
}
return null;
}
void _showStopDetails(
BuildContext context, RouteModel route, StopModel stop) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
builder: (context) => DraggableScrollableSheet(
initialChildSize: 0.7,
minChildSize: 0.5,
maxChildSize: 0.9,
expand: false,
builder: (context, scrollController) => Padding(
padding: const EdgeInsets.all(16),
child: ListView(
controller: scrollController,
children: [
Center(
child: Container(
width: 40,
height: 4,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(2),
),
),
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Stop Details',
style: Theme.of(context).textTheme.titleLarge,
),
StatusBadge(
status: stop.status.toString().split('.').last,
),
],
),
const SizedBox(height: 24),
_buildDetailRow(
context,
'Customer',
stop.customerName,
Icons.person,
),
_buildDetailRow(
context,
'Type',
stop.type == StopType.pickup ? 'Pickup' : 'Dropoff',
Icons.local_shipping,
),
if (stop.customerPhone != null)
_buildDetailRow(
context,
'Phone',
stop.customerPhone!,
Icons.phone,
),
_buildDetailRow(
context,
'Scheduled',
DateFormat('hh:mm a').format(stop.scheduledTime),
Icons.schedule,
),
if (stop.location.address != null)
_buildDetailRow(
context,
'Address',
stop.location.address!,
Icons.location_on,
),
if (stop.items.isNotEmpty) ...[
const SizedBox(height: 16),
Text(
'Items',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 8),
...stop.items.map((item) => Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Row(
children: [
const Icon(Icons.check_circle_outline, size: 20),
const SizedBox(width: 8),
Text(item),
],
),
)),
],
const SizedBox(height: 24),
if (stop.status == StopStatus.pending ||
stop.status == StopStatus.inProgress) ...[
Row(
children: [
Expanded(
child: ElevatedButton.icon(
onPressed: () {
Navigator.pop(context);
_navigateToStop(context, stop);
},
icon: const Icon(Icons.navigation),
label: const Text('Navigate'),
),
),
const SizedBox(width: 12),
Expanded(
child: ElevatedButton.icon(
onPressed: () async {
Navigator.pop(context);
final success = await context
.read<RouteProvider>()
.updateStopStatus(
route.id,
stop.id,
StopStatus.completed,
);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
success
? 'Stop completed!'
: 'Failed to complete stop',
),
backgroundColor: success
? AppTheme.successColor
: AppTheme.errorColor,
),
);
}
},
icon: const Icon(Icons.check),
label: const Text('Complete'),
),
),
],
),
],
],
),
),
),
);
}
Widget _buildDetailRow(
BuildContext context,
String label,
String value,
IconData icon,
) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(icon, size: 20, color: Colors.grey),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: Theme.of(context).textTheme.bodySmall,
),
const SizedBox(height: 4),
Text(
value,
style: Theme.of(context).textTheme.bodyLarge,
),
],
),
),
],
),
);
}
Future<void> _navigateToStop(BuildContext context, StopModel stop) async {
final locationService = LocationService();
final navigationService = NavigationService();
// Get current location
final currentPosition = await locationService.getCurrentLocation();
final success = await navigationService.openNavigation(
destinationLat: stop.location.latitude,
destinationLng: stop.location.longitude,
originLat: currentPosition?.latitude,
originLng: currentPosition?.longitude,
destinationName: stop.customerName,
);
if (!success && context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Failed to open navigation'),
backgroundColor: AppTheme.errorColor,
),
);
}
}
}

View File

@ -0,0 +1,130 @@
import 'package:flutter/material.dart';
import '../../data/models/route_model.dart';
import '../../data/models/stop_model.dart';
import '../../../../services/api/route_api_service.dart';
class RouteProvider extends ChangeNotifier {
final RouteApiService _apiService = RouteApiService();
List<RouteModel> _routes = [];
RouteModel? _currentRoute;
bool _isLoading = false;
String? _error;
List<RouteModel> get routes => _routes;
RouteModel? get currentRoute => _currentRoute;
bool get isLoading => _isLoading;
String? get error => _error;
Future<void> loadRoutes(String driverId) async {
_isLoading = true;
_error = null;
notifyListeners();
try {
_routes = await _apiService.getDriverRoutes(driverId);
_isLoading = false;
notifyListeners();
} catch (e) {
_error = e.toString();
_isLoading = false;
notifyListeners();
}
}
Future<void> loadRoute(String routeId) async {
_isLoading = true;
_error = null;
notifyListeners();
try {
_currentRoute = await _apiService.getRouteById(routeId);
_isLoading = false;
notifyListeners();
} catch (e) {
_error = e.toString();
_isLoading = false;
notifyListeners();
}
}
void setCurrentRoute(RouteModel route) {
_currentRoute = route;
notifyListeners();
}
Future<bool> startRoute(String routeId) async {
final success = await _apiService.updateRouteStatus(
routeId,
RouteStatus.inProgress,
);
if (success && _currentRoute != null) {
_currentRoute = _currentRoute!.copyWith(
status: RouteStatus.inProgress,
startTime: DateTime.now(),
);
notifyListeners();
}
return success;
}
Future<bool> completeRoute(String routeId) async {
final success = await _apiService.updateRouteStatus(
routeId,
RouteStatus.completed,
);
if (success && _currentRoute != null) {
_currentRoute = _currentRoute!.copyWith(
status: RouteStatus.completed,
endTime: DateTime.now(),
);
notifyListeners();
}
return success;
}
Future<bool> updateStopStatus(
String routeId,
String stopId,
StopStatus status, {
String? signature,
String? photo,
String? notes,
}) async {
final success = await _apiService.updateStopStatus(
routeId,
stopId,
status,
signature: signature,
photo: photo,
notes: notes,
);
if (success && _currentRoute != null) {
final updatedStops = _currentRoute!.stops.map((stop) {
if (stop.id == stopId) {
return stop.copyWith(
status: status,
completedTime:
status == StopStatus.completed ? DateTime.now() : null,
);
}
return stop;
}).toList();
_currentRoute = _currentRoute!.copyWith(stops: updatedStops);
notifyListeners();
}
return success;
}
void clearError() {
_error = null;
notifyListeners();
}
}

View File

@ -0,0 +1,111 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import '../../../../core/theme/app_theme.dart';
import '../../../../core/widgets/status_badge.dart';
import '../../data/models/route_model.dart';
class RouteCard extends StatelessWidget {
final RouteModel route;
final VoidCallback onTap;
const RouteCard({
super.key,
required this.route,
required this.onTap,
});
@override
Widget build(BuildContext context) {
return Card(
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(12),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
'Route ${route.id}',
style: Theme.of(context).textTheme.titleLarge,
overflow: TextOverflow.ellipsis,
),
),
StatusBadge(
status: route.status.toString().split('.').last,
),
],
),
const SizedBox(height: 12),
Row(
children: [
const Icon(Icons.calendar_today, size: 16, color: Colors.grey),
const SizedBox(width: 8),
Text(
DateFormat('MMM dd, yyyy').format(route.date),
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
const SizedBox(height: 8),
Row(
children: [
const Icon(Icons.location_on, size: 16, color: Colors.grey),
const SizedBox(width: 8),
Text(
'${route.stops.length} stops',
style: Theme.of(context).textTheme.bodyMedium,
),
const SizedBox(width: 16),
const Icon(Icons.directions_car, size: 16, color: Colors.grey),
const SizedBox(width: 8),
Text(
'${route.totalDistance.toStringAsFixed(1)} km',
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
const SizedBox(height: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Progress',
style: Theme.of(context).textTheme.bodySmall,
),
Text(
'${route.completedStopsCount}/${route.totalStopsCount}',
style: Theme.of(context).textTheme.bodySmall,
),
],
),
const SizedBox(height: 8),
ClipRRect(
borderRadius: BorderRadius.circular(4),
child: LinearProgressIndicator(
value: route.progressPercentage / 100,
minHeight: 8,
backgroundColor: Colors.grey[300],
valueColor: AlwaysStoppedAnimation<Color>(
route.status == RouteStatus.completed
? AppTheme.completedColor
: AppTheme.inProgressColor,
),
),
),
],
),
],
),
),
),
);
}
}

View File

@ -0,0 +1,132 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import '../../../../core/theme/app_theme.dart';
import '../../../../core/widgets/status_badge.dart';
import '../../data/models/stop_model.dart';
class StopCard extends StatelessWidget {
final StopModel stop;
final VoidCallback onTap;
final VoidCallback? onNavigate;
const StopCard({
super.key,
required this.stop,
required this.onTap,
this.onNavigate,
});
@override
Widget build(BuildContext context) {
return Card(
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(12),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: stop.type == StopType.pickup
? Colors.blue.withOpacity(0.1)
: Colors.green.withOpacity(0.1),
shape: BoxShape.circle,
),
child: Icon(
stop.type == StopType.pickup
? Icons.arrow_upward
: Icons.arrow_downward,
color: stop.type == StopType.pickup
? Colors.blue
: Colors.green,
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
stop.customerName,
style: Theme.of(context).textTheme.titleMedium,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 4),
Text(
stop.type == StopType.pickup ? 'Pickup' : 'Dropoff',
style: Theme.of(context).textTheme.bodySmall,
),
],
),
),
StatusBadge(
status: stop.status.toString().split('.').last,
),
],
),
const SizedBox(height: 12),
if (stop.location.address != null) ...[
Row(
children: [
const Icon(Icons.location_on, size: 16, color: Colors.grey),
const SizedBox(width: 8),
Expanded(
child: Text(
stop.location.address!,
style: Theme.of(context).textTheme.bodyMedium,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
],
),
const SizedBox(height: 8),
],
Row(
children: [
const Icon(Icons.schedule, size: 16, color: Colors.grey),
const SizedBox(width: 8),
Text(
DateFormat('hh:mm a').format(stop.scheduledTime),
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
if (stop.items.isNotEmpty) ...[
const SizedBox(height: 8),
Row(
children: [
const Icon(Icons.inventory_2, size: 16, color: Colors.grey),
const SizedBox(width: 8),
Text(
'${stop.items.length} items',
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
],
if (onNavigate != null &&
stop.status != StopStatus.completed) ...[
const SizedBox(height: 12),
SizedBox(
width: double.infinity,
child: ElevatedButton.icon(
onPressed: onNavigate,
icon: const Icon(Icons.navigation, size: 20),
label: const Text('Navigate'),
),
),
],
],
),
),
),
);
}
}

33
lib/main.dart Normal file
View File

@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'core/theme/app_theme.dart';
import 'core/constants/app_constants.dart';
import 'features/routes/presentation/pages/home_page.dart';
import 'features/routes/presentation/providers/route_provider.dart';
import 'services/api/route_api_service.dart';
void main() {
// Initialize services
RouteApiService().initialize();
runApp(const FleetDriverApp());
}
class FleetDriverApp extends StatelessWidget {
const FleetDriverApp({super.key});
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => RouteProvider()),
],
child: MaterialApp(
title: AppConstants.appName,
debugShowCheckedModeBanner: false,
theme: AppTheme.lightTheme,
home: const HomePage(),
),
);
}
}

View File

@ -0,0 +1,135 @@
import 'package:dio/dio.dart';
import '../../core/constants/app_constants.dart';
import '../../features/routes/data/models/route_model.dart';
import '../../features/routes/data/models/stop_model.dart';
class RouteApiService {
static final RouteApiService _instance = RouteApiService._internal();
factory RouteApiService() => _instance;
RouteApiService._internal();
late final Dio _dio;
void initialize({String? authToken}) {
_dio = Dio(
BaseOptions(
baseUrl: AppConstants.baseApiUrl,
connectTimeout: Duration(seconds: AppConstants.apiTimeout),
receiveTimeout: Duration(seconds: AppConstants.apiTimeout),
headers: {
'Content-Type': 'application/json',
if (authToken != null) 'Authorization': 'Bearer $authToken',
},
),
);
// Add interceptors for logging
_dio.interceptors.add(
LogInterceptor(
requestBody: true,
responseBody: true,
error: true,
),
);
}
Future<List<RouteModel>> getDriverRoutes(String driverId) async {
try {
final response = await _dio.get(
'${AppConstants.routesEndpoint}/$driverId',
);
if (response.statusCode == 200) {
final List<dynamic> data = response.data as List<dynamic>;
return data
.map((json) => RouteModel.fromJson(json as Map<String, dynamic>))
.toList();
}
return [];
} catch (e) {
print('Error fetching routes: $e');
rethrow;
}
}
Future<RouteModel?> getRouteById(String routeId) async {
try {
final response = await _dio.get(
'${AppConstants.routesEndpoint}/detail/$routeId',
);
if (response.statusCode == 200) {
return RouteModel.fromJson(response.data as Map<String, dynamic>);
}
return null;
} catch (e) {
print('Error fetching route: $e');
rethrow;
}
}
Future<bool> updateRouteStatus(String routeId, RouteStatus status) async {
try {
final response = await _dio.put(
'${AppConstants.routesEndpoint}/$routeId/status',
data: {
'status': status.toString().split('.').last,
'timestamp': DateTime.now().toIso8601String(),
},
);
return response.statusCode == 200;
} catch (e) {
print('Error updating route status: $e');
return false;
}
}
Future<bool> updateStopStatus(
String routeId,
String stopId,
StopStatus status, {
String? signature,
String? photo,
String? notes,
}) async {
try {
final response = await _dio.put(
'${AppConstants.stopsEndpoint}/$stopId/status',
data: {
'routeId': routeId,
'status': status.toString().split('.').last,
'timestamp': DateTime.now().toIso8601String(),
if (signature != null) 'signature': signature,
if (photo != null) 'photo': photo,
if (notes != null) 'notes': notes,
},
);
return response.statusCode == 200;
} catch (e) {
print('Error updating stop status: $e');
return false;
}
}
Future<bool> reportIssue(String routeId, String stopId, String issue) async {
try {
final response = await _dio.post(
'${AppConstants.stopsEndpoint}/$stopId/issue',
data: {
'routeId': routeId,
'issue': issue,
'timestamp': DateTime.now().toIso8601String(),
},
);
return response.statusCode == 200;
} catch (e) {
print('Error reporting issue: $e');
return false;
}
}
}

View File

@ -0,0 +1,69 @@
import 'package:geolocator/geolocator.dart';
import 'package:permission_handler/permission_handler.dart';
class LocationService {
static final LocationService _instance = LocationService._internal();
factory LocationService() => _instance;
LocationService._internal();
Future<bool> requestLocationPermission() async {
final status = await Permission.location.request();
return status.isGranted;
}
Future<bool> checkLocationPermission() async {
final status = await Permission.location.status;
return status.isGranted;
}
Future<Position?> getCurrentLocation() async {
try {
final hasPermission = await checkLocationPermission();
if (!hasPermission) {
final granted = await requestLocationPermission();
if (!granted) {
return null;
}
}
final isServiceEnabled = await Geolocator.isLocationServiceEnabled();
if (!isServiceEnabled) {
return null;
}
return await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
);
} catch (e) {
print('Error getting current location: $e');
return null;
}
}
Stream<Position> getLocationStream() {
return Geolocator.getPositionStream(
locationSettings: const LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 10,
),
);
}
Future<double> calculateDistance(
double startLatitude,
double startLongitude,
double endLatitude,
double endLongitude,
) async {
return Geolocator.distanceBetween(
startLatitude,
startLongitude,
endLatitude,
endLongitude,
) / 1000; // Convert to kilometers
}
Future<void> openLocationSettings() async {
await Geolocator.openLocationSettings();
}
}

View File

@ -0,0 +1,101 @@
import 'package:url_launcher/url_launcher.dart';
import '../../core/constants/app_constants.dart';
class NavigationService {
static final NavigationService _instance = NavigationService._internal();
factory NavigationService() => _instance;
NavigationService._internal();
Future<bool> openGoogleMapsNavigation({
required double destinationLat,
required double destinationLng,
double? originLat,
double? originLng,
}) async {
try {
// Try Google Maps first
final googleMapsUrl = Uri.parse(
'${AppConstants.googleMapsUrlScheme}?daddr=$destinationLat,$destinationLng' +
(originLat != null && originLng != null
? '&saddr=$originLat,$originLng'
: '') +
'&directionsmode=driving',
);
if (await canLaunchUrl(googleMapsUrl)) {
await launchUrl(googleMapsUrl);
return true;
}
// Fallback to web URL if Google Maps app is not installed
final webUrl = Uri.parse(
'https://www.google.com/maps/dir/?api=1' +
'&destination=$destinationLat,$destinationLng' +
(originLat != null && originLng != null
? '&origin=$originLat,$originLng'
: '') +
'&travelmode=driving',
);
if (await canLaunchUrl(webUrl)) {
await launchUrl(webUrl, mode: LaunchMode.externalApplication);
return true;
}
return false;
} catch (e) {
print('Error opening navigation: $e');
return false;
}
}
Future<bool> openAppleMapsNavigation({
required double destinationLat,
required double destinationLng,
String? destinationName,
}) async {
try {
final appleMapsUrl = Uri.parse(
'${AppConstants.appleMapsUrlScheme}?daddr=$destinationLat,$destinationLng' +
(destinationName != null ? '&q=$destinationName' : ''),
);
if (await canLaunchUrl(appleMapsUrl)) {
await launchUrl(appleMapsUrl);
return true;
}
return false;
} catch (e) {
print('Error opening Apple Maps: $e');
return false;
}
}
Future<bool> openNavigation({
required double destinationLat,
required double destinationLng,
double? originLat,
double? originLng,
String? destinationName,
}) async {
// Try Google Maps first
final googleMapsSuccess = await openGoogleMapsNavigation(
destinationLat: destinationLat,
destinationLng: destinationLng,
originLat: originLat,
originLng: originLng,
);
if (googleMapsSuccess) {
return true;
}
// Try Apple Maps as fallback
return await openAppleMapsNavigation(
destinationLat: destinationLat,
destinationLng: destinationLng,
destinationName: destinationName,
);
}
}

1
linux/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
flutter/ephemeral

128
linux/CMakeLists.txt Normal file
View File

@ -0,0 +1,128 @@
# Project-level configuration.
cmake_minimum_required(VERSION 3.13)
project(runner LANGUAGES CXX)
# The name of the executable created for the application. Change this to change
# the on-disk name of your application.
set(BINARY_NAME "flutter_fleet_logistic_workforce_app")
# The unique GTK application identifier for this application. See:
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
set(APPLICATION_ID "io.svrnty.flutter_fleet_logistic_workforce_app")
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
# versions of CMake.
cmake_policy(SET CMP0063 NEW)
# Load bundled libraries from the lib/ directory relative to the binary.
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
# Root filesystem for cross-building.
if(FLUTTER_TARGET_PLATFORM_SYSROOT)
set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
endif()
# Define build configuration options.
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "Debug" CACHE
STRING "Flutter build mode" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Profile" "Release")
endif()
# Compilation settings that should be applied to most targets.
#
# Be cautious about adding new options here, as plugins use this function by
# default. In most cases, you should add new options to specific targets instead
# of modifying this function.
function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_features(${TARGET} PUBLIC cxx_std_14)
target_compile_options(${TARGET} PRIVATE -Wall -Werror)
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
endfunction()
# Flutter library and tool build rules.
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
add_subdirectory(${FLUTTER_MANAGED_DIR})
# System-level dependencies.
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
# Application build; see runner/CMakeLists.txt.
add_subdirectory("runner")
# Run the Flutter tool portions of the build. This must not be removed.
add_dependencies(${BINARY_NAME} flutter_assemble)
# Only the install-generated bundle's copy of the executable will launch
# correctly, since the resources must in the right relative locations. To avoid
# people trying to run the unbundled copy, put it in a subdirectory instead of
# the default top-level location.
set_target_properties(${BINARY_NAME}
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
)
# Generated plugin build rules, which manage building the plugins and adding
# them to the application.
include(flutter/generated_plugins.cmake)
# === Installation ===
# By default, "installing" just makes a relocatable bundle in the build
# directory.
set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
endif()
# Start with a clean build bundle directory every time.
install(CODE "
file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
" COMPONENT Runtime)
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
COMPONENT Runtime)
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
COMPONENT Runtime)
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
install(FILES "${bundled_library}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
endforeach(bundled_library)
# Copy the native assets provided by the build.dart from all packages.
set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/")
install(DIRECTORY "${NATIVE_ASSETS_DIR}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
# Fully re-copy the assets directory on each build to avoid having stale files
# from a previous install.
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
install(CODE "
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
" COMPONENT Runtime)
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
# Install the AOT library on non-Debug builds only.
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
endif()

View File

@ -0,0 +1,88 @@
# This file controls Flutter-level build steps. It should not be edited.
cmake_minimum_required(VERSION 3.10)
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
# Configuration provided via flutter tool.
include(${EPHEMERAL_DIR}/generated_config.cmake)
# TODO: Move the rest of this into files in ephemeral. See
# https://github.com/flutter/flutter/issues/57146.
# Serves the same purpose as list(TRANSFORM ... PREPEND ...),
# which isn't available in 3.10.
function(list_prepend LIST_NAME PREFIX)
set(NEW_LIST "")
foreach(element ${${LIST_NAME}})
list(APPEND NEW_LIST "${PREFIX}${element}")
endforeach(element)
set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
endfunction()
# === Flutter Library ===
# System-level dependencies.
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
# Published to parent scope for install step.
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
list(APPEND FLUTTER_LIBRARY_HEADERS
"fl_basic_message_channel.h"
"fl_binary_codec.h"
"fl_binary_messenger.h"
"fl_dart_project.h"
"fl_engine.h"
"fl_json_message_codec.h"
"fl_json_method_codec.h"
"fl_message_codec.h"
"fl_method_call.h"
"fl_method_channel.h"
"fl_method_codec.h"
"fl_method_response.h"
"fl_plugin_registrar.h"
"fl_plugin_registry.h"
"fl_standard_message_codec.h"
"fl_standard_method_codec.h"
"fl_string_codec.h"
"fl_value.h"
"fl_view.h"
"flutter_linux.h"
)
list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
add_library(flutter INTERFACE)
target_include_directories(flutter INTERFACE
"${EPHEMERAL_DIR}"
)
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
target_link_libraries(flutter INTERFACE
PkgConfig::GTK
PkgConfig::GLIB
PkgConfig::GIO
)
add_dependencies(flutter flutter_assemble)
# === Flutter tool backend ===
# _phony_ is a non-existent file to force this command to run every time,
# since currently there's no way to get a full input/output list from the
# flutter tool.
add_custom_command(
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
${CMAKE_CURRENT_BINARY_DIR}/_phony_
COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
VERBATIM
)
add_custom_target(flutter_assemble DEPENDS
"${FLUTTER_LIBRARY}"
${FLUTTER_LIBRARY_HEADERS}
)

View File

@ -0,0 +1,15 @@
//
// Generated file. Do not edit.
//
// clang-format off
#include "generated_plugin_registrant.h"
#include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
}

View File

@ -0,0 +1,15 @@
//
// Generated file. Do not edit.
//
// clang-format off
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
#include <flutter_linux/flutter_linux.h>
// Registers Flutter plugins.
void fl_register_plugins(FlPluginRegistry* registry);
#endif // GENERATED_PLUGIN_REGISTRANT_

View File

@ -0,0 +1,24 @@
#
# Generated file, do not edit.
#
list(APPEND FLUTTER_PLUGIN_LIST
url_launcher_linux
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST
)
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
endforeach(ffi_plugin)

View File

@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 3.13)
project(runner LANGUAGES CXX)
# Define the application target. To change its name, change BINARY_NAME in the
# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
# work.
#
# Any new source files that you add to the application should be added here.
add_executable(${BINARY_NAME}
"main.cc"
"my_application.cc"
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
)
# Apply the standard set of build settings. This can be removed for applications
# that need different build settings.
apply_standard_settings(${BINARY_NAME})
# Add preprocessor definitions for the application ID.
add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
# Add dependency libraries. Add any application-specific dependencies here.
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")

6
linux/runner/main.cc Normal file
View File

@ -0,0 +1,6 @@
#include "my_application.h"
int main(int argc, char** argv) {
g_autoptr(MyApplication) app = my_application_new();
return g_application_run(G_APPLICATION(app), argc, argv);
}

View File

@ -0,0 +1,130 @@
#include "my_application.h"
#include <flutter_linux/flutter_linux.h>
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#endif
#include "flutter/generated_plugin_registrant.h"
struct _MyApplication {
GtkApplication parent_instance;
char** dart_entrypoint_arguments;
};
G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
// Implements GApplication::activate.
static void my_application_activate(GApplication* application) {
MyApplication* self = MY_APPLICATION(application);
GtkWindow* window =
GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
// Use a header bar when running in GNOME as this is the common style used
// by applications and is the setup most users will be using (e.g. Ubuntu
// desktop).
// If running on X and not using GNOME then just use a traditional title bar
// in case the window manager does more exotic layout, e.g. tiling.
// If running on Wayland assume the header bar will work (may need changing
// if future cases occur).
gboolean use_header_bar = TRUE;
#ifdef GDK_WINDOWING_X11
GdkScreen* screen = gtk_window_get_screen(window);
if (GDK_IS_X11_SCREEN(screen)) {
const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
use_header_bar = FALSE;
}
}
#endif
if (use_header_bar) {
GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
gtk_widget_show(GTK_WIDGET(header_bar));
gtk_header_bar_set_title(header_bar, "flutter_fleet_logistic_workforce_app");
gtk_header_bar_set_show_close_button(header_bar, TRUE);
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
} else {
gtk_window_set_title(window, "flutter_fleet_logistic_workforce_app");
}
gtk_window_set_default_size(window, 1280, 720);
gtk_widget_show(GTK_WIDGET(window));
g_autoptr(FlDartProject) project = fl_dart_project_new();
fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);
FlView* view = fl_view_new(project);
gtk_widget_show(GTK_WIDGET(view));
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
fl_register_plugins(FL_PLUGIN_REGISTRY(view));
gtk_widget_grab_focus(GTK_WIDGET(view));
}
// Implements GApplication::local_command_line.
static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) {
MyApplication* self = MY_APPLICATION(application);
// Strip out the first argument as it is the binary name.
self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
g_autoptr(GError) error = nullptr;
if (!g_application_register(application, nullptr, &error)) {
g_warning("Failed to register: %s", error->message);
*exit_status = 1;
return TRUE;
}
g_application_activate(application);
*exit_status = 0;
return TRUE;
}
// Implements GApplication::startup.
static void my_application_startup(GApplication* application) {
//MyApplication* self = MY_APPLICATION(object);
// Perform any actions required at application startup.
G_APPLICATION_CLASS(my_application_parent_class)->startup(application);
}
// Implements GApplication::shutdown.
static void my_application_shutdown(GApplication* application) {
//MyApplication* self = MY_APPLICATION(object);
// Perform any actions required at application shutdown.
G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application);
}
// Implements GObject::dispose.
static void my_application_dispose(GObject* object) {
MyApplication* self = MY_APPLICATION(object);
g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
}
static void my_application_class_init(MyApplicationClass* klass) {
G_APPLICATION_CLASS(klass)->activate = my_application_activate;
G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
G_APPLICATION_CLASS(klass)->startup = my_application_startup;
G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown;
G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
}
static void my_application_init(MyApplication* self) {}
MyApplication* my_application_new() {
// Set the program name to the application ID, which helps various systems
// like GTK and desktop environments map this running application to its
// corresponding .desktop file. This ensures better integration by allowing
// the application to be recognized beyond its binary name.
g_set_prgname(APPLICATION_ID);
return MY_APPLICATION(g_object_new(my_application_get_type(),
"application-id", APPLICATION_ID,
"flags", G_APPLICATION_NON_UNIQUE,
nullptr));
}

View File

@ -0,0 +1,18 @@
#ifndef FLUTTER_MY_APPLICATION_H_
#define FLUTTER_MY_APPLICATION_H_
#include <gtk/gtk.h>
G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
GtkApplication)
/**
* my_application_new:
*
* Creates a new Flutter-based application.
*
* Returns: a new #MyApplication.
*/
MyApplication* my_application_new();
#endif // FLUTTER_MY_APPLICATION_H_

7
macos/.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
# Flutter-related
**/Flutter/ephemeral/
**/Pods/
# Xcode-related
**/dgph
**/xcuserdata/

View File

@ -0,0 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"

View File

@ -0,0 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"

View File

@ -0,0 +1,14 @@
//
// Generated file. Do not edit.
//
import FlutterMacOS
import Foundation
import geolocator_apple
import url_launcher_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
}

42
macos/Podfile Normal file
View File

@ -0,0 +1,42 @@
platform :osx, '10.14'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_macos_podfile_setup
target 'Runner' do
use_frameworks!
flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_macos_build_settings(target)
end
end

29
macos/Podfile.lock Normal file
View File

@ -0,0 +1,29 @@
PODS:
- FlutterMacOS (1.0.0)
- geolocator_apple (1.2.0):
- Flutter
- FlutterMacOS
- url_launcher_macos (0.0.1):
- FlutterMacOS
DEPENDENCIES:
- FlutterMacOS (from `Flutter/ephemeral`)
- geolocator_apple (from `Flutter/ephemeral/.symlinks/plugins/geolocator_apple/darwin`)
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
EXTERNAL SOURCES:
FlutterMacOS:
:path: Flutter/ephemeral
geolocator_apple:
:path: Flutter/ephemeral/.symlinks/plugins/geolocator_apple/darwin
url_launcher_macos:
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
SPEC CHECKSUMS:
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e
url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673
PODFILE CHECKSUM: 7eb978b976557c8c1cd717d8185ec483fd090a82
COCOAPODS: 1.16.2

View File

@ -0,0 +1,801 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXAggregateTarget section */
33CC111A2044C6BA0003C045 /* Flutter Assemble */ = {
isa = PBXAggregateTarget;
buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */;
buildPhases = (
33CC111E2044C6BF0003C045 /* ShellScript */,
);
dependencies = (
);
name = "Flutter Assemble";
productName = FLX;
};
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; };
335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };
33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
BE9E1EAD243FF1D0AB8A9953 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE5A3A64389B75D1CB55249F /* Pods_RunnerTests.framework */; };
C863A4708FA478320581E2EF /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA723CE40B0CB98B38E1D987 /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 33CC10E52044A3C60003C045 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 33CC10EC2044A3C60003C045;
remoteInfo = Runner;
};
33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 33CC10E52044A3C60003C045 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 33CC111A2044C6BA0003C045;
remoteInfo = FLX;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
33CC110E2044A8840003C045 /* Bundle Framework */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Bundle Framework";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
2E4B91F1A834870257AA4093 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
33CC10ED2044A3C60003C045 /* flutter_fleet_logistic_workforce_app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = flutter_fleet_logistic_workforce_app.app; sourceTree = BUILT_PRODUCTS_DIR; };
33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = "<group>"; };
33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = "<group>"; };
33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = "<group>"; };
33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = "<group>"; };
33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = "<group>"; };
33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
35DDEC237A5BEA1BD2822675 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
7839F10D7F1DB0AF11E77385 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
AE5A3A64389B75D1CB55249F /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
BA723CE40B0CB98B38E1D987 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
C66F17341232459BBEF997CF /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
CBCFC60A48ED6B66B68ACA72 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
EAB4ED62725D4B6A483768EF /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
331C80D2294CF70F00263BE5 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
BE9E1EAD243FF1D0AB8A9953 /* Pods_RunnerTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
33CC10EA2044A3C60003C045 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
C863A4708FA478320581E2EF /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
0229E5840FCC79612B88E8FD /* Pods */ = {
isa = PBXGroup;
children = (
7839F10D7F1DB0AF11E77385 /* Pods-Runner.debug.xcconfig */,
35DDEC237A5BEA1BD2822675 /* Pods-Runner.release.xcconfig */,
C66F17341232459BBEF997CF /* Pods-Runner.profile.xcconfig */,
CBCFC60A48ED6B66B68ACA72 /* Pods-RunnerTests.debug.xcconfig */,
2E4B91F1A834870257AA4093 /* Pods-RunnerTests.release.xcconfig */,
EAB4ED62725D4B6A483768EF /* Pods-RunnerTests.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
331C80D6294CF71000263BE5 /* RunnerTests */ = {
isa = PBXGroup;
children = (
331C80D7294CF71000263BE5 /* RunnerTests.swift */,
);
path = RunnerTests;
sourceTree = "<group>";
};
33BA886A226E78AF003329D5 /* Configs */ = {
isa = PBXGroup;
children = (
33E5194F232828860026EE4D /* AppInfo.xcconfig */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
333000ED22D3DE5D00554162 /* Warnings.xcconfig */,
);
path = Configs;
sourceTree = "<group>";
};
33CC10E42044A3C60003C045 = {
isa = PBXGroup;
children = (
33FAB671232836740065AC1E /* Runner */,
33CEB47122A05771004F2AC0 /* Flutter */,
331C80D6294CF71000263BE5 /* RunnerTests */,
33CC10EE2044A3C60003C045 /* Products */,
D73912EC22F37F3D000D13A0 /* Frameworks */,
0229E5840FCC79612B88E8FD /* Pods */,
);
sourceTree = "<group>";
};
33CC10EE2044A3C60003C045 /* Products */ = {
isa = PBXGroup;
children = (
33CC10ED2044A3C60003C045 /* flutter_fleet_logistic_workforce_app.app */,
331C80D5294CF71000263BE5 /* RunnerTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
33CC11242044D66E0003C045 /* Resources */ = {
isa = PBXGroup;
children = (
33CC10F22044A3C60003C045 /* Assets.xcassets */,
33CC10F42044A3C60003C045 /* MainMenu.xib */,
33CC10F72044A3C60003C045 /* Info.plist */,
);
name = Resources;
path = ..;
sourceTree = "<group>";
};
33CEB47122A05771004F2AC0 /* Flutter */ = {
isa = PBXGroup;
children = (
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */,
33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */,
33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */,
33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */,
);
path = Flutter;
sourceTree = "<group>";
};
33FAB671232836740065AC1E /* Runner */ = {
isa = PBXGroup;
children = (
33CC10F02044A3C60003C045 /* AppDelegate.swift */,
33CC11122044BFA00003C045 /* MainFlutterWindow.swift */,
33E51913231747F40026EE4D /* DebugProfile.entitlements */,
33E51914231749380026EE4D /* Release.entitlements */,
33CC11242044D66E0003C045 /* Resources */,
33BA886A226E78AF003329D5 /* Configs */,
);
path = Runner;
sourceTree = "<group>";
};
D73912EC22F37F3D000D13A0 /* Frameworks */ = {
isa = PBXGroup;
children = (
BA723CE40B0CB98B38E1D987 /* Pods_Runner.framework */,
AE5A3A64389B75D1CB55249F /* Pods_RunnerTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
331C80D4294CF70F00263BE5 /* RunnerTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
65AE974314B26AE803DBF17D /* [CP] Check Pods Manifest.lock */,
331C80D1294CF70F00263BE5 /* Sources */,
331C80D2294CF70F00263BE5 /* Frameworks */,
331C80D3294CF70F00263BE5 /* Resources */,
);
buildRules = (
);
dependencies = (
331C80DA294CF71000263BE5 /* PBXTargetDependency */,
);
name = RunnerTests;
productName = RunnerTests;
productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
33CC10EC2044A3C60003C045 /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
43397FE6EA853985614190E0 /* [CP] Check Pods Manifest.lock */,
33CC10E92044A3C60003C045 /* Sources */,
33CC10EA2044A3C60003C045 /* Frameworks */,
33CC10EB2044A3C60003C045 /* Resources */,
33CC110E2044A8840003C045 /* Bundle Framework */,
3399D490228B24CF009A79C7 /* ShellScript */,
9569D20E32A7C19FA3F4F8E4 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
33CC11202044C79F0003C045 /* PBXTargetDependency */,
);
name = Runner;
productName = Runner;
productReference = 33CC10ED2044A3C60003C045 /* flutter_fleet_logistic_workforce_app.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
33CC10E52044A3C60003C045 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
331C80D4294CF70F00263BE5 = {
CreatedOnToolsVersion = 14.0;
TestTargetID = 33CC10EC2044A3C60003C045;
};
33CC10EC2044A3C60003C045 = {
CreatedOnToolsVersion = 9.2;
LastSwiftMigration = 1100;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.Sandbox = {
enabled = 1;
};
};
};
33CC111A2044C6BA0003C045 = {
CreatedOnToolsVersion = 9.2;
ProvisioningStyle = Manual;
};
};
};
buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 33CC10E42044A3C60003C045;
productRefGroup = 33CC10EE2044A3C60003C045 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
33CC10EC2044A3C60003C045 /* Runner */,
331C80D4294CF70F00263BE5 /* RunnerTests */,
33CC111A2044C6BA0003C045 /* Flutter Assemble */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
331C80D3294CF70F00263BE5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
33CC10EB2044A3C60003C045 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */,
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3399D490228B24CF009A79C7 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n";
};
33CC111E2044C6BF0003C045 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
Flutter/ephemeral/FlutterInputs.xcfilelist,
);
inputPaths = (
Flutter/ephemeral/tripwire,
);
outputFileListPaths = (
Flutter/ephemeral/FlutterOutputs.xcfilelist,
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
};
43397FE6EA853985614190E0 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
65AE974314B26AE803DBF17D /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
9569D20E32A7C19FA3F4F8E4 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
331C80D1294CF70F00263BE5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
33CC10E92044A3C60003C045 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */,
33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */,
335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
331C80DA294CF71000263BE5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 33CC10EC2044A3C60003C045 /* Runner */;
targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */;
};
33CC11202044C79F0003C045 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */;
targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
33CC10F42044A3C60003C045 /* MainMenu.xib */ = {
isa = PBXVariantGroup;
children = (
33CC10F52044A3C60003C045 /* Base */,
);
name = MainMenu.xib;
path = Runner;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
331C80DB294CF71000263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = CBCFC60A48ED6B66B68ACA72 /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = io.svrnty.flutterFleetLogisticWorkforceApp.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/flutter_fleet_logistic_workforce_app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/flutter_fleet_logistic_workforce_app";
};
name = Debug;
};
331C80DC294CF71000263BE5 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 2E4B91F1A834870257AA4093 /* Pods-RunnerTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = io.svrnty.flutterFleetLogisticWorkforceApp.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/flutter_fleet_logistic_workforce_app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/flutter_fleet_logistic_workforce_app";
};
name = Release;
};
331C80DD294CF71000263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = EAB4ED62725D4B6A483768EF /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = io.svrnty.flutterFleetLogisticWorkforceApp.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/flutter_fleet_logistic_workforce_app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/flutter_fleet_logistic_workforce_app";
};
name = Profile;
};
338D0CE9231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Profile;
};
338D0CEA231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
};
name = Profile;
};
338D0CEB231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Manual;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Profile;
};
33CC10F92044A3C60003C045 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
33CC10FA2044A3C60003C045 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Release;
};
33CC10FC2044A3C60003C045 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
33CC10FD2044A3C60003C045 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
};
name = Release;
};
33CC111C2044C6BA0003C045 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Manual;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
33CC111D2044C6BA0003C045 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
331C80DB294CF71000263BE5 /* Debug */,
331C80DC294CF71000263BE5 /* Release */,
331C80DD294CF71000263BE5 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC10F92044A3C60003C045 /* Debug */,
33CC10FA2044A3C60003C045 /* Release */,
338D0CE9231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC10FC2044A3C60003C045 /* Debug */,
33CC10FD2044A3C60003C045 /* Release */,
338D0CEA231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC111C2044C6BA0003C045 /* Debug */,
33CC111D2044C6BA0003C045 /* Release */,
338D0CEB231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 33CC10E52044A3C60003C045 /* Project object */;
}

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

Some files were not shown because too many files have changed in this diff Show More