This commit is contained in:
dmit.b
2026-07-05 12:42:04 +03:00
parent f011a121d7
commit 98cd704234
8 changed files with 81 additions and 69 deletions
+1 -15
View File
@@ -11,27 +11,13 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:label="family_safety_frontend"
android:label="GeoShare"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<service
android:name="com.pravera.flutter_foreground_task.service.ForegroundService"
android:foregroundServiceType="location"
android:exported="false" />
<receiver
android:name="com.pravera.flutter_foreground_task.receiver.AlarmReceiver"
android:exported="false">
<intent-filter>
<action android:name="com.pravera.flutter_foreground_task.action.ALARM" />
</intent-filter>
</receiver>
<receiver
android:name="com.pravera.flutter_foreground_task.receiver.BootReceiver"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<activity
android:name=".MainActivity"
android:exported="true"
+1 -1
View File
@@ -1,5 +1,5 @@
class ApiConfig {
static String _baseUrl = 'https://family-safety.onrender.com/api';
static String _baseUrl = 'https://test';
static String get baseUrl => _baseUrl;
+1
View File
@@ -12,6 +12,7 @@ import 'services/settings_service.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final settings = SettingsService();
await settings.initialize();
ApiConfig.setBaseUrl(settings.baseUrl);
final bgGeo = BackgroundGeoService();
await bgGeo.init();
+8 -15
View File
@@ -30,13 +30,18 @@ class _LoginScreenState extends State<LoginScreen>
_tabController.addListener(() {
setState(() {});
});
WidgetsBinding.instance.addPostFrameCallback((_) {
final settings = context.read<SettingsService>();
_serverUrlController.text = settings.baseUrl;
_loginController.text = settings.login ?? "";
_passwordController.text = settings.pwd ?? "";
if (settings.login != null && settings.pwd != null) {
savedAuth = true;
final authProvider = context.read<AuthProvider>();
login(settings.login!, settings.pwd!, authProvider);
Navigator.of(context).pushReplacementNamed('/map');
}
});
}
@override
@@ -53,15 +58,6 @@ class _LoginScreenState extends State<LoginScreen>
Widget build(BuildContext context) {
final authProvider = context.watch<AuthProvider>();
final settings = context.read<SettingsService>();
if (savedAuth) {
login(
_loginController.text,
_passwordController.text,
context,
authProvider,
settings,
);
}
return Scaffold(
resizeToAvoidBottomInset: true,
body: SingleChildScrollView(
@@ -77,7 +73,7 @@ class _LoginScreenState extends State<LoginScreen>
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
'Family Safety',
'Авторизация',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 32,
@@ -174,11 +170,13 @@ class _LoginScreenState extends State<LoginScreen>
}
}
if (_tabController.index == 0) {
print("Login...");
try {
await authProvider.login(
_loginController.text,
_passwordController.text,
);
settings.saveAuth(_loginController.text, _passwordController.text);
if (!context.mounted) return;
Navigator.of(
context,
@@ -233,15 +231,10 @@ class _LoginScreenState extends State<LoginScreen>
Future<void> login(
String login,
String pwd,
BuildContext ctx,
AuthProvider authProvider,
SettingsService settings,
) async {
try {
await authProvider.login(login, pwd);
settings.saveAuth(login, pwd);
if (!ctx.mounted) return;
Navigator.of(ctx).pushReplacementNamed('/map');
} catch (e) {
// Error is handled by provider
}
+32 -10
View File
@@ -1,4 +1,5 @@
import 'dart:async';
import 'package:GeoShare/services/settings_service.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_map/flutter_map.dart';
@@ -27,7 +28,7 @@ class _MapScreenState extends State<MapScreen> {
@override
void initState() {
super.initState();
_initLocationAndShare();
//_initLocationAndShare();
}
@override
@@ -150,7 +151,8 @@ class _MapScreenState extends State<MapScreen> {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => _WatchMenu(
builder: (context) =>
_WatchMenu(
token: authProvider.token,
onAdd: (shareId) async {
await shareProvider.addTracking(shareId, authProvider.token);
@@ -207,6 +209,7 @@ class _MapScreenState extends State<MapScreen> {
final authProvider = context.watch<AuthProvider>();
final _ = context.watch<MapProvider>();
final shareProvider = context.watch<ShareProvider>();
final settings = context.read<SettingsService>();
if (_loading) {
return Scaffold(body: const Center(child: CircularProgressIndicator()));
@@ -215,7 +218,8 @@ class _MapScreenState extends State<MapScreen> {
return Scaffold(
appBar: AppBar(
title: Text(
'Family Safety Map\n${_center.latitude.toStringAsFixed(4)}, ${_center.longitude.toStringAsFixed(4)}',
'Карта\n${_center.latitude.toStringAsFixed(4)}, ${_center
.longitude.toStringAsFixed(4)}',
textAlign: TextAlign.center,
),
actions: [
@@ -223,7 +227,10 @@ class _MapScreenState extends State<MapScreen> {
icon: const Icon(Icons.refresh),
onPressed: _updateGeolocation,
),
IconButton(icon: const Icon(Icons.share), onPressed: _copyShareLink),
IconButton(icon: const Icon(Icons.share), onPressed: () {
_initLocationAndShare();
_copyShareLink();
}),
IconButton(
icon: const Icon(Icons.visibility),
onPressed: _openWatchMenu,
@@ -236,6 +243,7 @@ class _MapScreenState extends State<MapScreen> {
await bgGeo.stop();
bgGeo.dispose();
authProvider.logout();
settings.logOut();
Navigator.of(context).pushReplacementNamed('/');
},
),
@@ -287,7 +295,10 @@ class _WatchMenuState extends State<_WatchMenu> {
return Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
bottom: MediaQuery
.of(context)
.viewInsets
.bottom,
),
child: Container(
constraints: const BoxConstraints(maxHeight: 400),
@@ -297,7 +308,10 @@ class _WatchMenuState extends State<_WatchMenu> {
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainerHighest,
color: Theme
.of(context)
.colorScheme
.surfaceContainerHighest,
borderRadius: const BorderRadius.vertical(
top: Radius.circular(16),
),
@@ -354,7 +368,8 @@ class _WatchMenuState extends State<_WatchMenu> {
title: Text(person.name),
subtitle: hasPosition
? Text(
'${person.position!['y'].toStringAsFixed(4)}, ${person.position!['x'].toStringAsFixed(4)}',
'${person.position!['y'].toStringAsFixed(4)}, ${person
.position!['x'].toStringAsFixed(4)}',
)
: const Text('Нет данных'),
trailing: IconButton(
@@ -368,7 +383,10 @@ class _WatchMenuState extends State<_WatchMenu> {
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainerHighest,
color: Theme
.of(context)
.colorScheme
.surfaceContainerHighest,
borderRadius: const BorderRadius.vertical(
bottom: Radius.circular(16),
),
@@ -387,7 +405,9 @@ class _WatchMenuState extends State<_WatchMenu> {
),
),
onSubmitted: (value) {
if (value.trim().isNotEmpty) {
if (value
.trim()
.isNotEmpty) {
widget.onAdd(value.trim());
_controller.clear();
}
@@ -397,7 +417,9 @@ class _WatchMenuState extends State<_WatchMenu> {
const SizedBox(width: 8),
ElevatedButton(
onPressed: () {
if (_controller.text.trim().isNotEmpty) {
if (_controller.text
.trim()
.isNotEmpty) {
widget.onAdd(_controller.text.trim());
_controller.clear();
}
+3
View File
@@ -8,6 +8,7 @@ class AuthService {
AuthService({http.Client? client}) : _client = client ?? http.Client();
Future<String> login(String login, String password) async {
print(ApiConfig.loginUrl);
final response = await _client.post(
Uri.parse(ApiConfig.loginUrl),
headers: {'Content-Type': 'application/json'},
@@ -17,6 +18,8 @@ class AuthService {
if (response.statusCode == 200) {
return response.body;
} else {
print(response.statusCode);
print(response.body);
throw Exception('Invalid credentials');
}
}
+9 -2
View File
@@ -1,7 +1,6 @@
import 'package:shared_preferences/shared_preferences.dart';
class SettingsService {
SettingsService(){initialize();}
static const String _baseUrlKey = 'server_base_url';
static const String _defaultBaseUrl =
'https://family-safety.onrender.com/api';
@@ -13,6 +12,7 @@ class SettingsService {
String get baseUrl => _baseUrl;
String? login;
String? pwd;
bool loggedIn=false;
Future<void> initialize() async {
if (_initialized) return;
@@ -34,7 +34,14 @@ class SettingsService {
pwd = pass;
final prefs = await SharedPreferences.getInstance();
await prefs.setString(_loginKey, user);
await prefs.setString(_loginKey, user);
await prefs.setString(_pwdKey, pass);
}
Future<void> logOut() async {
final prefs = await SharedPreferences.getInstance();
login = null;
pwd = null;
await prefs.remove(_loginKey);
await prefs.remove(_pwdKey);
}
void resetToDefault() {
+2 -2
View File
@@ -1,5 +1,5 @@
name: family_safety_frontend
description: "A new Flutter project."
name: GeoShare
description: "GeoShare"
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev