new icons, remove upload dests
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 69 B After Width: | Height: | Size: 69 B |
|
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 435 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 805 KiB After Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 69 B After Width: | Height: | Size: 69 B |
@@ -1,7 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?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">
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:drawable="@color/launch_background" />
|
|
||||||
<item>
|
<item>
|
||||||
<bitmap android:gravity="fill" android:src="@drawable/background"/>
|
<bitmap android:gravity="fill" android:src="@drawable/background"/>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 757 KiB After Width: | Height: | Size: 96 KiB |
@@ -3,14 +3,18 @@
|
|||||||
appver=$(cat lib/dev_config.dart | grep "kClientVersion" | cut -d '=' -f 2 | tr -d ';' | tr -d "\'" | tr -d " ")
|
appver=$(cat lib/dev_config.dart | grep "kClientVersion" | cut -d '=' -f 2 | tr -d ';' | tr -d "\'" | tr -d " ")
|
||||||
echo
|
echo
|
||||||
echo "Building app version ${appver}..."
|
echo "Building app version ${appver}..."
|
||||||
|
|
||||||
flutter build ios --no-codesign
|
flutter build ios --no-codesign
|
||||||
flutter build apk
|
flutter build apk
|
||||||
echo
|
echo
|
||||||
|
|
||||||
echo "Converting .app to .ipa..."
|
echo "Converting .app to .ipa..."
|
||||||
./app2ipa.sh build/ios/iphoneos/Runner.app
|
./app2ipa.sh build/ios/iphoneos/Runner.app
|
||||||
echo
|
echo
|
||||||
|
|
||||||
echo "Moving files..."
|
echo "Moving files..."
|
||||||
cp build/app/outputs/flutter-apk/app-release.apk ../flockmap_v${appver}.apk
|
cp build/app/outputs/flutter-apk/app-release.apk ../flockmap_v${appver}.apk
|
||||||
mv Runner.ipa ../flockmap_v${appver}.ipa
|
mv Runner.ipa ../flockmap_v${appver}.ipa
|
||||||
echo
|
echo
|
||||||
|
|
||||||
echo "Done."
|
echo "Done."
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 805 KiB After Width: | Height: | Size: 269 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 875 B |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 8.0 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 8.0 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 69 B After Width: | Height: | Size: 69 B |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 435 KiB After Width: | Height: | Size: 57 KiB |
@@ -16,13 +16,19 @@
|
|||||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
|
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" image="LaunchBackground" translatesAutoresizingMaskIntoConstraints="NO" id="tWc-Dq-wcI"/>
|
||||||
</imageView>
|
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4"></imageView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" red="0.125" green="0.125" blue="0.125" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
|
<constraint firstItem="YRO-k0-Ey4" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="3T2-ad-Qdv"/>
|
||||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
|
<constraint firstItem="tWc-Dq-wcI" firstAttribute="bottom" secondItem="Ze5-6b-2t3" secondAttribute="bottom" id="RPx-PI-7Xg"/>
|
||||||
|
<constraint firstItem="tWc-Dq-wcI" firstAttribute="top" secondItem="Ze5-6b-2t3" secondAttribute="top" id="SdS-ul-q2q"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="tWc-Dq-wcI" secondAttribute="trailing" id="Swv-Gf-Rwn"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="YRO-k0-Ey4" secondAttribute="trailing" id="TQA-XW-tRk"/>
|
||||||
|
<constraint firstItem="YRO-k0-Ey4" firstAttribute="bottom" secondItem="Ze5-6b-2t3" secondAttribute="bottom" id="duK-uY-Gun"/>
|
||||||
|
<constraint firstItem="tWc-Dq-wcI" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="kV7-tw-vXt"/>
|
||||||
|
<constraint firstItem="YRO-k0-Ey4" firstAttribute="top" secondItem="Ze5-6b-2t3" secondAttribute="top" id="xPn-NY-SIU"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
</viewController>
|
</viewController>
|
||||||
@@ -32,6 +38,7 @@
|
|||||||
</scene>
|
</scene>
|
||||||
</scenes>
|
</scenes>
|
||||||
<resources>
|
<resources>
|
||||||
<image name="LaunchImage" width="168" height="185"/>
|
<image name="LaunchImage" width="512" height="512"/>
|
||||||
|
<image name="LaunchBackground" width="1" height="1"/>
|
||||||
</resources>
|
</resources>
|
||||||
</document>
|
</document>
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ const double kAddPinYOffset = 0.0;
|
|||||||
const String kClientName = 'DeFlock';
|
const String kClientName = 'DeFlock';
|
||||||
const String kClientVersion = '0.9.8';
|
const String kClientVersion = '0.9.8';
|
||||||
|
|
||||||
|
// Development/testing features - set to false for production builds
|
||||||
|
const bool kEnableDevelopmentModes = false; // Set to false to hide sandbox/simulate modes and force production mode
|
||||||
|
|
||||||
// Marker/node interaction
|
// Marker/node interaction
|
||||||
const int kCameraMinZoomLevel = 10; // Minimum zoom to show nodes or warning
|
const int kCameraMinZoomLevel = 10; // Minimum zoom to show nodes or warning
|
||||||
const Duration kMarkerTapTimeout = Duration(milliseconds: 250);
|
const Duration kMarkerTapTimeout = Duration(milliseconds: 250);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import 'settings_screen_sections/max_nodes_section.dart';
|
|||||||
import 'settings_screen_sections/tile_provider_section.dart';
|
import 'settings_screen_sections/tile_provider_section.dart';
|
||||||
import 'settings_screen_sections/language_section.dart';
|
import 'settings_screen_sections/language_section.dart';
|
||||||
import '../services/localization_service.dart';
|
import '../services/localization_service.dart';
|
||||||
|
import '../dev_config.dart';
|
||||||
|
|
||||||
class SettingsScreen extends StatelessWidget {
|
class SettingsScreen extends StatelessWidget {
|
||||||
const SettingsScreen({super.key});
|
const SettingsScreen({super.key});
|
||||||
@@ -23,28 +24,31 @@ class SettingsScreen extends StatelessWidget {
|
|||||||
appBar: AppBar(title: Text(LocalizationService.instance.t('settings.title'))),
|
appBar: AppBar(title: Text(LocalizationService.instance.t('settings.title'))),
|
||||||
body: ListView(
|
body: ListView(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
children: const [
|
children: [
|
||||||
UploadModeSection(),
|
// Only show upload mode section in development builds
|
||||||
Divider(),
|
if (kEnableDevelopmentModes) ...[
|
||||||
AuthSection(),
|
const UploadModeSection(),
|
||||||
Divider(),
|
const Divider(),
|
||||||
QueueSection(),
|
],
|
||||||
Divider(),
|
const AuthSection(),
|
||||||
ProfileListSection(),
|
const Divider(),
|
||||||
Divider(),
|
const QueueSection(),
|
||||||
OperatorProfileListSection(),
|
const Divider(),
|
||||||
Divider(),
|
const ProfileListSection(),
|
||||||
MaxNodesSection(),
|
const Divider(),
|
||||||
Divider(),
|
const OperatorProfileListSection(),
|
||||||
TileProviderSection(),
|
const Divider(),
|
||||||
Divider(),
|
const MaxNodesSection(),
|
||||||
OfflineModeSection(),
|
const Divider(),
|
||||||
Divider(),
|
const TileProviderSection(),
|
||||||
OfflineAreasSection(),
|
const Divider(),
|
||||||
Divider(),
|
const OfflineModeSection(),
|
||||||
LanguageSection(),
|
const Divider(),
|
||||||
Divider(),
|
const OfflineAreasSection(),
|
||||||
AboutSection(),
|
const Divider(),
|
||||||
|
const LanguageSection(),
|
||||||
|
const Divider(),
|
||||||
|
const AboutSection(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -106,6 +106,36 @@ class AuthService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore login state from stored token (for app startup)
|
||||||
|
Future<String?> restoreLogin() async {
|
||||||
|
if (_mode == UploadMode.simulate) {
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
final isLoggedIn = prefs.getBool('sim_user_logged_in') ?? false;
|
||||||
|
if (isLoggedIn) {
|
||||||
|
_displayName = 'Demo User';
|
||||||
|
return _displayName;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get stored token directly from SharedPreferences
|
||||||
|
final accessToken = await getAccessToken();
|
||||||
|
if (accessToken == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
_displayName = await _fetchUsername(accessToken);
|
||||||
|
return _displayName;
|
||||||
|
} catch (e) {
|
||||||
|
print('AuthService: Error restoring login with stored token: $e');
|
||||||
|
log('Error restoring login with stored token: $e');
|
||||||
|
// Token might be expired or invalid, clear it
|
||||||
|
await logout();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> logout() async {
|
Future<void> logout() async {
|
||||||
if (_mode == UploadMode.simulate) {
|
if (_mode == UploadMode.simulate) {
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class AuthState extends ChangeNotifier {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (await _auth.isLoggedIn()) {
|
if (await _auth.isLoggedIn()) {
|
||||||
_username = await _auth.login();
|
_username = await _auth.restoreLogin();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("AuthState: Error during auth initialization: $e");
|
print("AuthState: Error during auth initialization: $e");
|
||||||
@@ -44,7 +44,7 @@ class AuthState extends ChangeNotifier {
|
|||||||
Future<void> refreshAuthState() async {
|
Future<void> refreshAuthState() async {
|
||||||
try {
|
try {
|
||||||
if (await _auth.isLoggedIn()) {
|
if (await _auth.isLoggedIn()) {
|
||||||
_username = await _auth.login();
|
_username = await _auth.restoreLogin();
|
||||||
} else {
|
} else {
|
||||||
_username = null;
|
_username = null;
|
||||||
}
|
}
|
||||||
@@ -83,7 +83,7 @@ class AuthState extends ChangeNotifier {
|
|||||||
if (await _auth.isLoggedIn()) {
|
if (await _auth.isLoggedIn()) {
|
||||||
final isValid = await validateToken();
|
final isValid = await validateToken();
|
||||||
if (isValid) {
|
if (isValid) {
|
||||||
_username = await _auth.login();
|
_username = await _auth.restoreLogin();
|
||||||
} else {
|
} else {
|
||||||
await logout(); // This clears _username also.
|
await logout(); // This clears _username also.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:shared_preferences/shared_preferences.dart';
|
|||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
|
|
||||||
import '../models/tile_provider.dart';
|
import '../models/tile_provider.dart';
|
||||||
|
import '../dev_config.dart';
|
||||||
|
|
||||||
// Enum for upload mode (Production, OSM Sandbox, Simulate)
|
// Enum for upload mode (Production, OSM Sandbox, Simulate)
|
||||||
enum UploadMode { production, sandbox, simulate }
|
enum UploadMode { production, sandbox, simulate }
|
||||||
@@ -26,7 +27,7 @@ class SettingsState extends ChangeNotifier {
|
|||||||
|
|
||||||
bool _offlineMode = false;
|
bool _offlineMode = false;
|
||||||
int _maxCameras = 250;
|
int _maxCameras = 250;
|
||||||
UploadMode _uploadMode = UploadMode.simulate;
|
UploadMode _uploadMode = kEnableDevelopmentModes ? UploadMode.simulate : UploadMode.production;
|
||||||
FollowMeMode _followMeMode = FollowMeMode.northUp;
|
FollowMeMode _followMeMode = FollowMeMode.northUp;
|
||||||
List<TileProvider> _tileProviders = [];
|
List<TileProvider> _tileProviders = [];
|
||||||
String _selectedTileTypeId = '';
|
String _selectedTileTypeId = '';
|
||||||
@@ -98,6 +99,13 @@ class SettingsState extends ChangeNotifier {
|
|||||||
await prefs.setInt(_uploadModePrefsKey, _uploadMode.index);
|
await prefs.setInt(_uploadModePrefsKey, _uploadMode.index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In production builds, force production mode if development modes are disabled
|
||||||
|
if (!kEnableDevelopmentModes && _uploadMode != UploadMode.production) {
|
||||||
|
debugPrint('SettingsState: Development modes disabled, forcing production mode');
|
||||||
|
_uploadMode = UploadMode.production;
|
||||||
|
await prefs.setInt(_uploadModePrefsKey, _uploadMode.index);
|
||||||
|
}
|
||||||
|
|
||||||
// Load tile providers (default to built-in providers if none saved)
|
// Load tile providers (default to built-in providers if none saved)
|
||||||
await _loadTileProviders(prefs);
|
await _loadTileProviders(prefs);
|
||||||
|
|
||||||
@@ -170,6 +178,12 @@ class SettingsState extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setUploadMode(UploadMode mode) async {
|
Future<void> setUploadMode(UploadMode mode) async {
|
||||||
|
// In production builds, only allow production mode
|
||||||
|
if (!kEnableDevelopmentModes && mode != UploadMode.production) {
|
||||||
|
debugPrint('SettingsState: Development modes disabled, forcing production mode');
|
||||||
|
mode = UploadMode.production;
|
||||||
|
}
|
||||||
|
|
||||||
_uploadMode = mode;
|
_uploadMode = mode;
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
await prefs.setInt(_uploadModePrefsKey, mode.index);
|
await prefs.setInt(_uploadModePrefsKey, mode.index);
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ flutter:
|
|||||||
- lib/localizations/
|
- lib/localizations/
|
||||||
|
|
||||||
flutter_native_splash:
|
flutter_native_splash:
|
||||||
color: "#202020"
|
color: "#152131"
|
||||||
image: assets/app_icon.png
|
image: assets/app_icon.png
|
||||||
android: true
|
android: true
|
||||||
ios: true
|
ios: true
|
||||||
|
|||||||