我正在使用 API,我希望如果用户之前已经登录,当我在启动屏幕后打开应用程序时,他会直接重定向到主页而不是协议页面(我只希望新登录的用户请参阅协议页)。
这是 main.dart:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:project/firebase_options.dart';
import 'package:project/screens/home_page.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:project/screens/splash_screen.dart';
import 'package:shared_preferences/shared_preferences.dart';
// Import your theme provider class
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
await dotenv.load();
}
class MyApp extends StatefulWidget {
const MyApp({Key? key,}) : super(key: key);
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
@override
void initState() {
super.initState();
_configureFirebaseMessaging();
}
Future<String?> _loadGlobalId() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
return prefs.getString('globalId');
}
@override
Widget build(BuildContext context) {
final Brightness brightness = MediaQuery.of(context).platformBrightness;
final bool isDarkMode = brightness == Brightness.dark;
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: isDarkMode ? ThemeData.dark() : ThemeData.light(),
home: SplashScreen()
);
}
}
这里是agreement_page.dart:
class AgreementPage extends StatefulWidget {
@override
_AgreementPageState createState() => _AgreementPageState();
}
class _AgreementPageState extends State<AgreementPage> {
bool _accepted = false;
bool _loggedIn = false;
String _code = '';
Color _buttonColor = Colors.grey;
String _url =
'https://example.com/auth/example';
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
backgroundColor: Color(0xff429588),
title: Text('Terms and Conditions'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'End-User License Agreement',
style: TextStyle(
fontSize: 24.0,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 16.0),
Text(
),
SizedBox(height: 16.0),
Row(
children: [
Checkbox(
value: _accepted,
onChanged: (value) {
setState(() {
_accepted = value!;
_buttonColor =
_accepted ? Color(0xff429588) : Colors.grey;
});
},
),
Text(
'I accept the terms and conditions',
style: TextStyle(fontSize: 16.0),
),
],
),
SizedBox(height: 16.0),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
ElevatedButton(
onPressed: _accepted
? () async {
// Show a webview with the url from bottom to top
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => Container(
height:
MediaQuery.of(context).size.height * 0.9,
child: WebView(
initialUrl: _url,
javascriptMode: JavascriptMode.unrestricted,
navigationDelegate: (request) {
// Check if the user has logged in successfully
if (request.url.startsWith(
'https://exp.example.com/exp')) {
setState(() {
_loggedIn = true;
});
// Extract the code from the query parameter
final uri = Uri.parse(request.url);
final code = uri.queryParameters['code'];
if (code != null) {
setState(() {
_code = code;
});
}
// Close the webview and navigate to the homepage with the code
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HomePage(
code:
_code, // Pass the code to the homepage
),
),
);
return NavigationDecision.prevent;
}
return NavigationDecision.navigate;
},
gestureRecognizers: Set()
..add(
Factory<VerticalDragGestureRecognizer>(
() => VerticalDragGestureRecognizer(),
),
),
),
),
);
}
: null,
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all<Color>(_buttonColor),
), // Disable the button if not accepted
child: Text(
'Accept',
style: TextStyle(color: Colors.white),
),
),
ElevatedButton(
onPressed: () {
// Handle the case when the user doesn't accept the agreement.
// You can navigate back or perform any other action.
// Exit the app
exit(0);
},
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all<Color>(Color(0xff429588)),
),
child: Text(
'Don\'t Accept',
style: TextStyle(color: Colors.white),
),
),
],
),
],
),
),
),
);
}
}
这是 home_page.dart:
class HomePage extends StatefulWidget {
const HomePage({Key? key, this.code}) : super(key: key);
final String? code;
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
late Future<Map<String, dynamic>> userInfo;
PersistentTabController _controller =
PersistentTabController(initialIndex: 0);
@override
void initState() {
super.initState();
if (widget.code != null && widget.code!.isNotEmpty) {
userInfo = _authenticate(widget.code!);
}
}
Future<Map<String, dynamic>> _authenticate(String code) async {
try {
final tokenData = await AuthService.authenticate(code);
final accessToken = tokenData['access_token'];
final refreshToken = tokenData['refresh_token'];
return await _fetchUserInfo(accessToken);
} catch (e) {
// Handle authentication error
print('Authentication error: $e');
throw e;
}
}
Future<Map<String, dynamic>> _fetchUserInfo(String accessToken) async {
try {
final userInfo = await UserService.fetchUserInfo(accessToken);
final String userName = userInfo['name'] ?? 'Unknown User';
final String userEmail = userInfo['email'] ?? 'Unknown Email';
final String userBirthdate = userInfo['birthdate'] ?? 'Unknown Birthdate';
final String userGender = userInfo['gender'] ?? 'Unknown Gender';
final String userRegion =
userInfo['address']['region'] ?? 'Unknown Region';
final String userPostalCode =
userInfo['address']['postal_code'] ?? 'Unknown Postal Code';
final String userCountry =
userInfo['address']['country'] ?? 'Unknown Country';
final String userPreferredUsername =
userInfo['preferred_username'] ?? 'Unknown Preferred Username';
final String sub = userInfo['sub'] ?? 'Unknown Global ID';
return {
'userName': userName,
'userEmail': userEmail,
'userBirthdate': userBirthdate,
'userGender': userGender,
'userRegion': userRegion,
'userPostalCode': userPostalCode,
'userCountry': userCountry,
'userPreferredUsername': userPreferredUsername,
'globalId': sub,
'_getTabAccessCode': await _getTabAccessCode(sub, accessToken),
};
} catch (e) {
// Handle user info fetch error
print('Error fetching user information: $e');
throw e;
}
}
Future<Map<String, dynamic>> _getTabAccessCode(
String globalId, String accessToken) async {
try {
final tabAccessCode =
await UserService.getTabAccessCode(globalId, accessToken);
print('Tab Access Code: $tabAccessCode');
print(
'Condition result: ${tabAccessCode['pid'] == tabAccessCode['doctorid']}');
print('PID: ${tabAccessCode['pid']}');
print('DoctorID: ${tabAccessCode['doctorid']}');
// Get a reference to the Firestore instance
FirebaseFirestore firestore = FirebaseFirestore.instance;
// Determine user type based on pid and doctorid
String userType = (tabAccessCode['pid'] == tabAccessCode['doctorid'])
? 'doctor'
: 'patient';
// Store the tab access code and user type in Firestore
await firestore.collection('users').doc(globalId).set({
'pid': tabAccessCode['pid'],
'TabAccCode': tabAccessCode['TabAccCode'],
'user_type': userType // Add this line
});
return {
'pid': tabAccessCode['pid'],
'TabAccCode': tabAccessCode['TabAccCode'],
'user_type': userType // Add this line
};
} catch (e) {
// Handle tab access code fetch error
print('Error getting Tab Access Code: $e');
throw e;
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
drawer: AppDrawer(userInfo: userInfo, controller: _controller),
body: PersistentTabView(
context,
controller: _controller,
screens: [
HomeContent(userInfo: userInfo),
FutureBuilder<Map<String, dynamic>>(
future: userInfo,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: SizedBox(
width: 50,
height: 50,
child: CircularProgressIndicator(),
),
);
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return ConversationPage(
TabAccCode: snapshot.data!['_getTabAccessCode']['TabAccCode'],
pid: snapshot.data!['_getTabAccessCode']['pid'],
user_type: snapshot.data!['_getTabAccessCode']['user_type'],
userInfo: userInfo,
);
}
},
),
AppointmentPage(),
Documents_Page(),
MyAppsPage()
],
items: [
PersistentBottomNavBarItem(
icon: Icon(Icons.home),
title: ("Home"),
activeColorPrimary: Color(0xff429588),
inactiveColorPrimary: Colors.grey,
),
PersistentBottomNavBarItem(
icon: Icon(Icons.message),
title: ("Messages"),
activeColorPrimary: Color(0xff429588),
inactiveColorPrimary: Colors.grey,
),
PersistentBottomNavBarItem(
icon: Icon(Icons.calendar_month),
title: ("Appointments"),
activeColorPrimary: Color(0xff429588),
inactiveColorPrimary: Colors.grey,
),
PersistentBottomNavBarItem(
icon: Icon(Icons.edit_document),
title: ("Documents"),
activeColorPrimary: Color(0xff429588),
inactiveColorPrimary: Colors.grey,
),
PersistentBottomNavBarItem(
icon: Icon(Icons.apps),
title: ("My Apps"),
activeColorPrimary: Color(0xff429588),
inactiveColorPrimary: Colors.grey,
),
],
),
);
}
}
我尝试像这样共享首选项:
splash_screen.dart
void initState() {
super.initState();
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
// Introduce a 2-second delay before navigating to the agreement page
Future.delayed(Duration(seconds: 2), () async {
// Get the instance of SharedPreferences
SharedPreferences prefs = await SharedPreferences.getInstance();
// Check if the user is already logged in
bool isLoggedIn = prefs.getBool('isLoggedIn') ?? false;
// Use Navigator to navigate based on the login state
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) => isLoggedIn ? HomePage() : AgreementPage()),
);
});
}
在agreement_page.dart中,用户接受:
ElevatedButton(
onPressed: _accepted
? () async {
SharedPreferences prefs =
await SharedPreferences.getInstance();
prefs.setBool('isLoggedIn',
true); // Set to true when logging in
// Show a webview with the url from bottom to top
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => Container(
height:
MediaQuery.of(context).size.height * 0.9,
child: WebView(
initialUrl: _url,
javascriptMode: JavascriptMode.unrestricted,
navigationDelegate: (request) {
// Check if the user has logged in successfully
if (request.url.startsWith(
'https://example.com')) {
setState(() {
_loggedIn = true;
});
// Extract the code from the query parameter
final uri = Uri.parse(request.url);
final code = uri.queryParameters['code'];
if (code != null) {
setState(() {
_code = code;
});
}
// Close the webview and navigate to the homepage with the code
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HomePage(
code:
_code, // Pass the code to the homepage
),
),
);
return NavigationDecision.prevent;
}
return NavigationDecision.navigate;
},
gestureRecognizers: Set()
..add(
Factory<VerticalDragGestureRecognizer>(
() => VerticalDragGestureRecognizer(),
),
),
),
),
);
}
: null,
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all<Color>(_buttonColor),
), // Disable the button if not accepted
child: Text(
'Accept',
style: TextStyle(color: Colors.white),
),
),
但我从 home_page.dart 收到错误:
“LateError(LateInitializationError:字段'userInfo'尚未初始化。)”
如果有人可以帮忙的话。
您在 home_page.dart 中遇到 LateInitializationError ,因为当您从AgreementPage导航到HomePage时,您正在传递代码,但是当您从Splash导航到HomePage时,您没有传递任何代码,因此您的userInfo不会被初始化,因为条件失败。
if (widget.code != null && widget.code!.isNotEmpty) {
userInfo = _authenticate(widget.code!);
}
从 Splash 导航时,不要在主页中遇到任何 LateInitializationError 密码。
希望您遇到问题并且此解决方案适合您。