Add application source code and update project structure
This commit is contained in:
293
Application Product/Source/source/lib/flutter_flow/nav/nav.dart
Executable file
293
Application Product/Source/source/lib/flutter_flow/nav/nav.dart
Executable file
@@ -0,0 +1,293 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:page_transition/page_transition.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '/index.dart';
|
||||
import '/main.dart';
|
||||
import '/flutter_flow/flutter_flow_theme.dart';
|
||||
import '/flutter_flow/lat_lng.dart';
|
||||
import '/flutter_flow/place.dart';
|
||||
import '/flutter_flow/flutter_flow_util.dart';
|
||||
import 'serialization_util.dart';
|
||||
|
||||
export 'package:go_router/go_router.dart';
|
||||
export 'serialization_util.dart';
|
||||
|
||||
const kTransitionInfoKey = '__transition_info__';
|
||||
|
||||
class AppStateNotifier extends ChangeNotifier {
|
||||
AppStateNotifier._();
|
||||
|
||||
static AppStateNotifier? _instance;
|
||||
static AppStateNotifier get instance => _instance ??= AppStateNotifier._();
|
||||
|
||||
bool showSplashImage = true;
|
||||
|
||||
void stopShowingSplashImage() {
|
||||
showSplashImage = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
GoRouter createRouter(AppStateNotifier appStateNotifier) => GoRouter(
|
||||
initialLocation: '/',
|
||||
debugLogDiagnostics: true,
|
||||
refreshListenable: appStateNotifier,
|
||||
errorBuilder: (context, state) => appStateNotifier.showSplashImage
|
||||
? Builder(
|
||||
builder: (context) => Container(
|
||||
color: Colors.transparent,
|
||||
child: Image.asset(
|
||||
'assets/images/Settings_(4).png',
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
)
|
||||
: NavBarPage(),
|
||||
routes: [
|
||||
FFRoute(
|
||||
name: '_initialize',
|
||||
path: '/',
|
||||
builder: (context, _) => appStateNotifier.showSplashImage
|
||||
? Builder(
|
||||
builder: (context) => Container(
|
||||
color: Colors.transparent,
|
||||
child: Image.asset(
|
||||
'assets/images/Settings_(4).png',
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
)
|
||||
: NavBarPage(),
|
||||
),
|
||||
FFRoute(
|
||||
name: 'HomePage',
|
||||
path: '/homePage',
|
||||
builder: (context, params) => params.isEmpty
|
||||
? NavBarPage(initialPage: 'HomePage')
|
||||
: HomePageWidget(),
|
||||
),
|
||||
FFRoute(
|
||||
name: 'Analyst',
|
||||
path: '/analyst',
|
||||
builder: (context, params) => params.isEmpty
|
||||
? NavBarPage(initialPage: 'Analyst')
|
||||
: AnalystWidget(),
|
||||
),
|
||||
FFRoute(
|
||||
name: 'Infomation',
|
||||
path: '/infomation',
|
||||
builder: (context, params) => params.isEmpty
|
||||
? NavBarPage(initialPage: 'Infomation')
|
||||
: InfomationWidget(),
|
||||
),
|
||||
FFRoute(
|
||||
name: 'setting',
|
||||
path: '/setting',
|
||||
builder: (context, params) => params.isEmpty
|
||||
? NavBarPage(initialPage: 'setting')
|
||||
: SettingWidget(),
|
||||
),
|
||||
FFRoute(
|
||||
name: 'NEWS',
|
||||
path: '/news',
|
||||
builder: (context, params) =>
|
||||
params.isEmpty ? NavBarPage(initialPage: 'NEWS') : NewsWidget(),
|
||||
)
|
||||
].map((r) => r.toRoute(appStateNotifier)).toList(),
|
||||
);
|
||||
|
||||
extension NavParamExtensions on Map<String, String?> {
|
||||
Map<String, String> get withoutNulls => Map.fromEntries(
|
||||
entries
|
||||
.where((e) => e.value != null)
|
||||
.map((e) => MapEntry(e.key, e.value!)),
|
||||
);
|
||||
}
|
||||
|
||||
extension NavigationExtensions on BuildContext {
|
||||
void safePop() {
|
||||
// If there is only one route on the stack, navigate to the initial
|
||||
// page instead of popping.
|
||||
if (canPop()) {
|
||||
pop();
|
||||
} else {
|
||||
go('/');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension _GoRouterStateExtensions on GoRouterState {
|
||||
Map<String, dynamic> get extraMap =>
|
||||
extra != null ? extra as Map<String, dynamic> : {};
|
||||
Map<String, dynamic> get allParams => <String, dynamic>{}
|
||||
..addAll(pathParameters)
|
||||
..addAll(uri.queryParameters)
|
||||
..addAll(extraMap);
|
||||
TransitionInfo get transitionInfo => extraMap.containsKey(kTransitionInfoKey)
|
||||
? extraMap[kTransitionInfoKey] as TransitionInfo
|
||||
: TransitionInfo.appDefault();
|
||||
}
|
||||
|
||||
class FFParameters {
|
||||
FFParameters(this.state, [this.asyncParams = const {}]);
|
||||
|
||||
final GoRouterState state;
|
||||
final Map<String, Future<dynamic> Function(String)> asyncParams;
|
||||
|
||||
Map<String, dynamic> futureParamValues = {};
|
||||
|
||||
// Parameters are empty if the params map is empty or if the only parameter
|
||||
// present is the special extra parameter reserved for the transition info.
|
||||
bool get isEmpty =>
|
||||
state.allParams.isEmpty ||
|
||||
(state.allParams.length == 1 &&
|
||||
state.extraMap.containsKey(kTransitionInfoKey));
|
||||
bool isAsyncParam(MapEntry<String, dynamic> param) =>
|
||||
asyncParams.containsKey(param.key) && param.value is String;
|
||||
bool get hasFutures => state.allParams.entries.any(isAsyncParam);
|
||||
Future<bool> completeFutures() => Future.wait(
|
||||
state.allParams.entries.where(isAsyncParam).map(
|
||||
(param) async {
|
||||
final doc = await asyncParams[param.key]!(param.value)
|
||||
.onError((_, __) => null);
|
||||
if (doc != null) {
|
||||
futureParamValues[param.key] = doc;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
),
|
||||
).onError((_, __) => [false]).then((v) => v.every((e) => e));
|
||||
|
||||
dynamic getParam<T>(
|
||||
String paramName,
|
||||
ParamType type, {
|
||||
bool isList = false,
|
||||
}) {
|
||||
if (futureParamValues.containsKey(paramName)) {
|
||||
return futureParamValues[paramName];
|
||||
}
|
||||
if (!state.allParams.containsKey(paramName)) {
|
||||
return null;
|
||||
}
|
||||
final param = state.allParams[paramName];
|
||||
// Got parameter from `extras`, so just directly return it.
|
||||
if (param is! String) {
|
||||
return param;
|
||||
}
|
||||
// Return serialized value.
|
||||
return deserializeParam<T>(
|
||||
param,
|
||||
type,
|
||||
isList,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FFRoute {
|
||||
const FFRoute({
|
||||
required this.name,
|
||||
required this.path,
|
||||
required this.builder,
|
||||
this.requireAuth = false,
|
||||
this.asyncParams = const {},
|
||||
this.routes = const [],
|
||||
});
|
||||
|
||||
final String name;
|
||||
final String path;
|
||||
final bool requireAuth;
|
||||
final Map<String, Future<dynamic> Function(String)> asyncParams;
|
||||
final Widget Function(BuildContext, FFParameters) builder;
|
||||
final List<GoRoute> routes;
|
||||
|
||||
GoRoute toRoute(AppStateNotifier appStateNotifier) => GoRoute(
|
||||
name: name,
|
||||
path: path,
|
||||
pageBuilder: (context, state) {
|
||||
fixStatusBarOniOS16AndBelow(context);
|
||||
final ffParams = FFParameters(state, asyncParams);
|
||||
final page = ffParams.hasFutures
|
||||
? FutureBuilder(
|
||||
future: ffParams.completeFutures(),
|
||||
builder: (context, _) => builder(context, ffParams),
|
||||
)
|
||||
: builder(context, ffParams);
|
||||
final child = page;
|
||||
|
||||
final transitionInfo = state.transitionInfo;
|
||||
return transitionInfo.hasTransition
|
||||
? CustomTransitionPage(
|
||||
key: state.pageKey,
|
||||
child: child,
|
||||
transitionDuration: transitionInfo.duration,
|
||||
transitionsBuilder:
|
||||
(context, animation, secondaryAnimation, child) =>
|
||||
PageTransition(
|
||||
type: transitionInfo.transitionType,
|
||||
duration: transitionInfo.duration,
|
||||
reverseDuration: transitionInfo.duration,
|
||||
alignment: transitionInfo.alignment,
|
||||
child: child,
|
||||
).buildTransitions(
|
||||
context,
|
||||
animation,
|
||||
secondaryAnimation,
|
||||
child,
|
||||
),
|
||||
)
|
||||
: MaterialPage(key: state.pageKey, child: child);
|
||||
},
|
||||
routes: routes,
|
||||
);
|
||||
}
|
||||
|
||||
class TransitionInfo {
|
||||
const TransitionInfo({
|
||||
required this.hasTransition,
|
||||
this.transitionType = PageTransitionType.fade,
|
||||
this.duration = const Duration(milliseconds: 300),
|
||||
this.alignment,
|
||||
});
|
||||
|
||||
final bool hasTransition;
|
||||
final PageTransitionType transitionType;
|
||||
final Duration duration;
|
||||
final Alignment? alignment;
|
||||
|
||||
static TransitionInfo appDefault() => TransitionInfo(hasTransition: false);
|
||||
}
|
||||
|
||||
class RootPageContext {
|
||||
const RootPageContext(this.isRootPage, [this.errorRoute]);
|
||||
final bool isRootPage;
|
||||
final String? errorRoute;
|
||||
|
||||
static bool isInactiveRootPage(BuildContext context) {
|
||||
final rootPageContext = context.read<RootPageContext?>();
|
||||
final isRootPage = rootPageContext?.isRootPage ?? false;
|
||||
final location = GoRouterState.of(context).uri.toString();
|
||||
return isRootPage &&
|
||||
location != '/' &&
|
||||
location != rootPageContext?.errorRoute;
|
||||
}
|
||||
|
||||
static Widget wrap(Widget child, {String? errorRoute}) => Provider.value(
|
||||
value: RootPageContext(true, errorRoute),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
extension GoRouterLocationExtension on GoRouter {
|
||||
String getCurrentLocation() {
|
||||
final RouteMatch lastMatch = routerDelegate.currentConfiguration.last;
|
||||
final RouteMatchList matchList = lastMatch is ImperativeRouteMatch
|
||||
? lastMatch.matches
|
||||
: routerDelegate.currentConfiguration;
|
||||
return matchList.uri.toString();
|
||||
}
|
||||
}
|
||||
206
Application Product/Source/source/lib/flutter_flow/nav/serialization_util.dart
Executable file
206
Application Product/Source/source/lib/flutter_flow/nav/serialization_util.dart
Executable file
@@ -0,0 +1,206 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:from_css_color/from_css_color.dart';
|
||||
|
||||
import '../../flutter_flow/lat_lng.dart';
|
||||
import '../../flutter_flow/place.dart';
|
||||
import '../../flutter_flow/uploaded_file.dart';
|
||||
|
||||
/// SERIALIZATION HELPERS
|
||||
|
||||
String dateTimeRangeToString(DateTimeRange dateTimeRange) {
|
||||
final startStr = dateTimeRange.start.millisecondsSinceEpoch.toString();
|
||||
final endStr = dateTimeRange.end.millisecondsSinceEpoch.toString();
|
||||
return '$startStr|$endStr';
|
||||
}
|
||||
|
||||
String placeToString(FFPlace place) => jsonEncode({
|
||||
'latLng': place.latLng.serialize(),
|
||||
'name': place.name,
|
||||
'address': place.address,
|
||||
'city': place.city,
|
||||
'state': place.state,
|
||||
'country': place.country,
|
||||
'zipCode': place.zipCode,
|
||||
});
|
||||
|
||||
String uploadedFileToString(FFUploadedFile uploadedFile) =>
|
||||
uploadedFile.serialize();
|
||||
|
||||
String? serializeParam(
|
||||
dynamic param,
|
||||
ParamType paramType, {
|
||||
bool isList = false,
|
||||
}) {
|
||||
try {
|
||||
if (param == null) {
|
||||
return null;
|
||||
}
|
||||
if (isList) {
|
||||
final serializedValues = (param as Iterable)
|
||||
.map((p) => serializeParam(p, paramType, isList: false))
|
||||
.where((p) => p != null)
|
||||
.map((p) => p!)
|
||||
.toList();
|
||||
return json.encode(serializedValues);
|
||||
}
|
||||
String? data;
|
||||
switch (paramType) {
|
||||
case ParamType.int:
|
||||
data = param.toString();
|
||||
case ParamType.double:
|
||||
data = param.toString();
|
||||
case ParamType.String:
|
||||
data = param;
|
||||
case ParamType.bool:
|
||||
data = param ? 'true' : 'false';
|
||||
case ParamType.DateTime:
|
||||
data = (param as DateTime).millisecondsSinceEpoch.toString();
|
||||
case ParamType.DateTimeRange:
|
||||
data = dateTimeRangeToString(param as DateTimeRange);
|
||||
case ParamType.LatLng:
|
||||
data = (param as LatLng).serialize();
|
||||
case ParamType.Color:
|
||||
data = (param as Color).toCssString();
|
||||
case ParamType.FFPlace:
|
||||
data = placeToString(param as FFPlace);
|
||||
case ParamType.FFUploadedFile:
|
||||
data = uploadedFileToString(param as FFUploadedFile);
|
||||
case ParamType.JSON:
|
||||
data = json.encode(param);
|
||||
|
||||
default:
|
||||
data = null;
|
||||
}
|
||||
return data;
|
||||
} catch (e) {
|
||||
print('Error serializing parameter: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// END SERIALIZATION HELPERS
|
||||
|
||||
/// DESERIALIZATION HELPERS
|
||||
|
||||
DateTimeRange? dateTimeRangeFromString(String dateTimeRangeStr) {
|
||||
final pieces = dateTimeRangeStr.split('|');
|
||||
if (pieces.length != 2) {
|
||||
return null;
|
||||
}
|
||||
return DateTimeRange(
|
||||
start: DateTime.fromMillisecondsSinceEpoch(int.parse(pieces.first)),
|
||||
end: DateTime.fromMillisecondsSinceEpoch(int.parse(pieces.last)),
|
||||
);
|
||||
}
|
||||
|
||||
LatLng? latLngFromString(String? latLngStr) {
|
||||
final pieces = latLngStr?.split(',');
|
||||
if (pieces == null || pieces.length != 2) {
|
||||
return null;
|
||||
}
|
||||
return LatLng(
|
||||
double.parse(pieces.first.trim()),
|
||||
double.parse(pieces.last.trim()),
|
||||
);
|
||||
}
|
||||
|
||||
FFPlace placeFromString(String placeStr) {
|
||||
final serializedData = jsonDecode(placeStr) as Map<String, dynamic>;
|
||||
final data = {
|
||||
'latLng': serializedData.containsKey('latLng')
|
||||
? latLngFromString(serializedData['latLng'] as String)
|
||||
: const LatLng(0.0, 0.0),
|
||||
'name': serializedData['name'] ?? '',
|
||||
'address': serializedData['address'] ?? '',
|
||||
'city': serializedData['city'] ?? '',
|
||||
'state': serializedData['state'] ?? '',
|
||||
'country': serializedData['country'] ?? '',
|
||||
'zipCode': serializedData['zipCode'] ?? '',
|
||||
};
|
||||
return FFPlace(
|
||||
latLng: data['latLng'] as LatLng,
|
||||
name: data['name'] as String,
|
||||
address: data['address'] as String,
|
||||
city: data['city'] as String,
|
||||
state: data['state'] as String,
|
||||
country: data['country'] as String,
|
||||
zipCode: data['zipCode'] as String,
|
||||
);
|
||||
}
|
||||
|
||||
FFUploadedFile uploadedFileFromString(String uploadedFileStr) =>
|
||||
FFUploadedFile.deserialize(uploadedFileStr);
|
||||
|
||||
enum ParamType {
|
||||
int,
|
||||
double,
|
||||
String,
|
||||
bool,
|
||||
DateTime,
|
||||
DateTimeRange,
|
||||
LatLng,
|
||||
Color,
|
||||
FFPlace,
|
||||
FFUploadedFile,
|
||||
JSON,
|
||||
}
|
||||
|
||||
dynamic deserializeParam<T>(
|
||||
String? param,
|
||||
ParamType paramType,
|
||||
bool isList,
|
||||
) {
|
||||
try {
|
||||
if (param == null) {
|
||||
return null;
|
||||
}
|
||||
if (isList) {
|
||||
final paramValues = json.decode(param);
|
||||
if (paramValues is! Iterable || paramValues.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
return paramValues
|
||||
.where((p) => p is String)
|
||||
.map((p) => p as String)
|
||||
.map((p) => deserializeParam<T>(p, paramType, false))
|
||||
.where((p) => p != null)
|
||||
.map((p) => p! as T)
|
||||
.toList();
|
||||
}
|
||||
switch (paramType) {
|
||||
case ParamType.int:
|
||||
return int.tryParse(param);
|
||||
case ParamType.double:
|
||||
return double.tryParse(param);
|
||||
case ParamType.String:
|
||||
return param;
|
||||
case ParamType.bool:
|
||||
return param == 'true';
|
||||
case ParamType.DateTime:
|
||||
final milliseconds = int.tryParse(param);
|
||||
return milliseconds != null
|
||||
? DateTime.fromMillisecondsSinceEpoch(milliseconds)
|
||||
: null;
|
||||
case ParamType.DateTimeRange:
|
||||
return dateTimeRangeFromString(param);
|
||||
case ParamType.LatLng:
|
||||
return latLngFromString(param);
|
||||
case ParamType.Color:
|
||||
return fromCssColor(param);
|
||||
case ParamType.FFPlace:
|
||||
return placeFromString(param);
|
||||
case ParamType.FFUploadedFile:
|
||||
return uploadedFileFromString(param);
|
||||
case ParamType.JSON:
|
||||
return json.decode(param);
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error deserializing parameter: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user