Refactor Flutter app architecture
Build and deploy Flutter Web / build (push) Successful in 3m7s

This commit is contained in:
Ruslan Bakiev
2026-06-12 14:25:24 +07:00
parent be41f74b33
commit 5e78a134b0
17 changed files with 821 additions and 751 deletions
@@ -0,0 +1,26 @@
import 'package:flutter/material.dart';
class TelegramLoginButton extends StatelessWidget {
const TelegramLoginButton({
required this.onPressed,
required this.loading,
super.key,
});
final VoidCallback? onPressed;
final bool loading;
@override
Widget build(BuildContext context) {
return FilledButton.icon(
onPressed: loading ? null : onPressed,
icon: loading
? const SizedBox.square(
dimension: 18,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Icon(Icons.telegram),
label: const Text('Войти через Telegram'),
);
}
}
+2
View File
@@ -0,0 +1,2 @@
export 'telegram_session_stub.dart'
if (dart.library.html) 'telegram_session_web.dart';
@@ -0,0 +1,17 @@
String telegramInitData() => '';
String telegramLoginData() => '';
String mapflowSessionToken() => '';
String telegramLoginTokenFromUrl() => '';
void saveMapflowSessionToken(String token) {}
void clearMapflowSession() {}
void configureTelegramWebApp() {}
void openExternalUrl(String url) {}
void reloadApp() {}
+75
View File
@@ -0,0 +1,75 @@
import 'dart:js_interop';
import 'package:web/web.dart' as web;
const telegramLoginStorageKey = 'mapflow.telegramLoginData';
const mapflowSessionStorageKey = 'mapflow.sessionToken';
@JS('Telegram')
external _Telegram? get _telegram;
extension type _Telegram(JSObject _) implements JSObject {
@JS('WebApp')
external _TelegramWebApp? get webApp;
}
extension type _TelegramWebApp(JSObject _) implements JSObject {
external JSString? get initData;
external void ready();
external void expand();
external bool isVersionAtLeast(String version);
external void disableVerticalSwipes();
}
@JS('JSON.stringify')
external JSString _jsonStringify(JSAny? value);
_TelegramWebApp? get _webApp => _telegram?.webApp;
String telegramInitData() => _webApp?.initData?.toDart ?? '';
String telegramLoginData() =>
web.window.localStorage.getItem(telegramLoginStorageKey) ?? '';
String mapflowSessionToken() =>
web.window.localStorage.getItem(mapflowSessionStorageKey) ?? '';
String telegramLoginTokenFromUrl() {
final uri = Uri.parse(web.window.location.href);
return uri.queryParameters['telegram_login'] ?? '';
}
void saveTelegramLoginData(JSAny? user) {
final encoded = _jsonStringify(user).toDart;
web.window.localStorage.setItem(telegramLoginStorageKey, encoded);
}
void saveMapflowSessionToken(String token) {
web.window.localStorage.setItem(mapflowSessionStorageKey, token);
}
void clearMapflowSession() {
web.window.localStorage.removeItem(mapflowSessionStorageKey);
web.window.localStorage.removeItem(telegramLoginStorageKey);
}
void configureTelegramWebApp() {
final webApp = _webApp;
if (webApp == null) {
return;
}
webApp.ready();
webApp.expand();
if (webApp.isVersionAtLeast('7.7')) {
webApp.disableVerticalSwipes();
}
}
void openExternalUrl(String url) {
web.window.location.assign(url);
}
void reloadApp() {
web.window.location.assign(web.window.location.origin);
}
+32
View File
@@ -0,0 +1,32 @@
import 'package:geolocator/geolocator.dart';
import 'package:latlong2/latlong.dart';
class CurrentLocation {
Future<LatLng?> resolve() async {
final serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
return null;
}
final permission = await _resolvePermission();
if (permission != LocationPermission.whileInUse &&
permission != LocationPermission.always) {
return null;
}
final position = await Geolocator.getCurrentPosition(
locationSettings: const LocationSettings(accuracy: LocationAccuracy.high),
);
return LatLng(position.latitude, position.longitude);
}
Future<LocationPermission> _resolvePermission() async {
final permission = await Geolocator.checkPermission();
if (permission != LocationPermission.denied) {
return permission;
}
return Geolocator.requestPermission();
}
}