B standing video
www.bilibili.com/video/BV1vV… www.bilibili.com/video/BV1SA… www.bilibili.com/video/BV1jt… www.bilibili.com/video/BV1wt… www.bilibili.com/video/BV1b5… www.bilibili.com/video/BV11z…
In this section, the target
- The welcome page is displayed after the first login
- Offline login
- Provider responds to data management
- APP color gray processing is realized
- Log out
- Http Status 401 Authentication and authorization
- Home disk cache
- Home page cache policy, delay 1 to 3 seconds
- Home skeleton screen
video
- B station
- Tubing mirror
resources
-
Blue Lake design draft (plus wechat to authorized Ducafecat) lanhuapp.com/url/wbhGq
-
YAPI Interface management yapi.demo.qunar.com/
-
Code github.com/ducafecat/f…
-
reference
- provider
- pk_skeleton
The welcome page is displayed for the first time and offline login is performed
- lib/global.dart
// open it for the first time
static bool isFirstOpen = false;
/// Whether to log in offline
static bool isOfflineLogin = false;
/// init
static Future init() async{...// Read device turned on for the first timeisFirstOpen = ! StorageUtil().getBool(STORAGE_DEVICE_ALREADY_OPEN_KEY);if (isFirstOpen) {
StorageUtil().setBool(STORAGE_DEVICE_ALREADY_OPEN_KEY, true);
}
// Read the offline user information
var _profileJSON = StorageUtil().getJSON(STORAGE_USER_PROFILE_KEY);
if(_profileJSON ! =null) {
profile = UserLoginResponseEntity.fromJson(_profileJSON);
isOfflineLogin = true;
}
Copy the code
- lib/pages/index/index.dart
class IndexPage extends StatefulWidget {
IndexPage({Key key}) : super(key: key);
@override
_IndexPageState createState() => _IndexPageState();
}
class _IndexPageState extends State<IndexPage> {
@override
Widget build(BuildContext context) {
ScreenUtil.init(
context,
width: 375,
height: 812 - 44 - 34,
allowFontScaling: true,);return Scaffold(
body: Global.isFirstOpen == true
? WelcomePage()
: Global.isOfflineLogin == true? ApplicationPage() : SignInPage(), ); }}Copy the code
Provider implements dynamic gray processing
Pub. Flutter – IO. Cn/packages/pr…
Step 1: Install dependencies
dependencies:
provider: ^ 4.0.4
Copy the code
Step 2: Create the response data class
- lib/common/provider/app.dart
import 'package:flutter/material.dart';
/// The corresponding system status
class AppState with ChangeNotifier {
bool _isGrayFilter;
get isGrayFilter => _isGrayFilter;
AppState({bool isGrayFilter = false{})this._isGrayFilter = isGrayFilter; }}Copy the code
Step 3: Initial response data
Method 1: Create a data object and then mount it
- lib/global.dart
/// Application status
static AppState appState = AppState();
Copy the code
- lib/main.dart
void main() => Global.init().then((e) => runApp(
MultiProvider(
providers: [
ChangeNotifierProvider<AppState>.value(
value: Global.appState,
),
],
child: MyApp(),
),
));
Copy the code
Method 2: Create objects during mounting
- lib/main.dart
void main() => Global.init().then((e) => runApp(
MultiProvider(
providers: [
ChangeNotifierProvider<AppState>(
Create: (_) => new AppState(),
),
],
child: MyApp(),
),
));
Copy the code
Step 4: Notify the data of sound changes
- lib/common/provider/app.dart
class AppState with ChangeNotifier {...// Toggle the grey filter
switchGrayFilter() {
_isGrayFilter = !_isGrayFilter;
notifyListeners();
}
}
Copy the code
Step 5: Voice change of received data
Method 1: Consumer
- lib/main.dart
void main() => Global.init().then((e) => runApp(
MultiProvider(
providers: [
ChangeNotifierProvider<AppState>.value(
value: Global.appState,
),
],
child: Consumer<AppState>(builder: (context, appState, _) {
if (appState.isGrayFilter) {
return ColorFiltered(
colorFilter: ColorFilter.mode(Colors.white, BlendMode.color),
child: MyApp(),
);
} else {
returnMyApp(); }}),),));Copy the code
Method 2: provider.of
- lib/pages/account/account.dart
final appState = Provider.of<AppState>(context);
return Column(
children: <Widget>[
MaterialButton(
onPressed: () {
appState.switchGrayFilter();
},
child: Text('Grey switch${appState.isGrayFilter}'),),,);Copy the code
Multiple response data processing
-
Mount using MultiProvider
-
Receive with Consumer2 ~ Consumer6
Log out
- lib/common/utils/authentication.dart
// check whether there is a token
Future<bool> isAuthenticated() async {
var profileJSON = StorageUtil().getJSON(STORAGE_USER_PROFILE_KEY);
returnprofileJSON ! =null ? true : false;
}
// delete the cache token
Future deleteAuthentication() async {
await StorageUtil().remove(STORAGE_USER_PROFILE_KEY);
Global.profile = null;
}
/// Log in again
Future goLoginPage(BuildContext context) async {
await deleteAuthentication();
Navigator.pushNamedAndRemoveUntil(
context, "/sign-in", (Route<dynamic> route) => false);
}
Copy the code
- lib/pages/account/account.dart
class _AccountPageState extends State<AccountPage> {
@override
Widget build(BuildContext context) {
final appState = Provider.of<AppState>(context);
return Column(
children: <Widget>[
Text('users:${Global.profile.displayName}'),
Divider(),
MaterialButton(
onPressed: () {
goLoginPage(context);
},
child: Text('exit'),),,); }}Copy the code
Http Status 401 Authentication and authorization
Dio wraps the interface’s context object BuildContext Context
- lib/common/utils/http.dart
Future post(
String path, {
@required BuildContext context,
dynamic params,
Options options,
}) async {
Options requestOptions = options ?? Options();
requestOptions = requestOptions.merge(extra: {
"context": context, }); . }Copy the code
Error handling 401 go to login screen
- lib/common/utils/http.dart
// Add interceptor
dio.interceptors
.add(InterceptorsWrapper(onRequest: (RequestOptions options) {
return options; //continue
}, onResponse: (Response response) {
return response; // continue
}, onError: (DioError e) {
ErrorEntity eInfo = createErrorEntity(e);
// Error message
toastInfo(msg: eInfo.message);
// Error interaction handling
var context = e.request.extra["context"];
if(context ! =null) {
switch (eInfo.code) {
case 401: // No permission to log in again
goLoginPage(context);
break;
default:}}return eInfo;
}));
Copy the code
Home disk cache
- lib/common/utils/net_cache.dart
// Strategy 1 memory cache first, 2 disk cache second
// 1 Memory cache
var ob = cache[key];
if(ob ! =null) {
// If the cache is not expired, the cache contents are returned
if ((DateTime.now().millisecondsSinceEpoch - ob.timeStamp) / 1000 <
CACHE_MAXAGE) {
return cache[key].response;
} else {
// If it has expired, delete the cache and continue to request the servercache.remove(key); }}// 2 Disk cache
if (cacheDisk) {
var cacheData = StorageUtil().getJSON(key);
if(cacheData ! =null) {
return Response(
statusCode: 200, data: cacheData, ); }}Copy the code
Home page cache policy, delay 1 to 3 seconds
- lib/pages/main/channels_widget.dart
// If there is disk cache, delay 3 seconds to pull update file
_loadLatestWithDiskCache() {
if (CACHE_ENABLE == true) {
var cacheData = StorageUtil().getJSON(STORAGE_INDEX_NEWS_CACHE_KEY);
if(cacheData ! =null) {
Timer(Duration(seconds: 3), () { _controller.callRefresh(); }); }}}Copy the code
Home skeleton screen
Pub. Flutter – IO. Cn/packages/pk…
- lib/pages/main/main.dart
@override
Widget build(BuildContext context) {
return _newsPageList == null
? cardListSkeleton()
: EasyRefresh(
enableControlFinishRefresh: true,
controller: _controller,
...
Copy the code