mirror of
https://github.com/qinglong-app/qinglong_app.git
synced 2025-10-09 16:48:19 +08:00
add homepage
This commit is contained in:
84
lib/base/base_state_widget.dart
Normal file
84
lib/base/base_state_widget.dart
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'base_viewmodel.dart';
|
||||||
|
|
||||||
|
class BaseStateWidget<T extends BaseViewModel> extends ConsumerStatefulWidget {
|
||||||
|
final Widget Function(BuildContext context, T value, Widget? child) builder;
|
||||||
|
final ProviderBase<T> model;
|
||||||
|
final Widget? child;
|
||||||
|
final Function(T)? onReady;
|
||||||
|
|
||||||
|
const BaseStateWidget({
|
||||||
|
Key? key,
|
||||||
|
required this.builder,
|
||||||
|
required this.model,
|
||||||
|
this.child,
|
||||||
|
this.onReady,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_BaseStateWidgetState<T> createState() => _BaseStateWidgetState<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BaseStateWidgetState<T extends BaseViewModel> extends ConsumerState<BaseStateWidget<T>> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
if (widget.onReady != null) {
|
||||||
|
widget.onReady!(ref.read<T>(widget.model));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var viewModel = ref.watch<T>(widget.model);
|
||||||
|
if (viewModel.currentState == PageState.CONTENT) {
|
||||||
|
return widget.builder(context, viewModel, widget.child);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viewModel.currentState == PageState.LOADING) {
|
||||||
|
return Container(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: const CupertinoActivityIndicator(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viewModel.currentState == PageState.FAILED) {
|
||||||
|
return Container(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Text("请求失败"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viewModel.currentState == PageState.EMPTY) {
|
||||||
|
return Container(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Text("暂无数据"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class BaseState<T extends StatefulWidget> extends State {
|
||||||
|
late T parent;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
parent = widget as T;
|
||||||
|
super.initState();
|
||||||
|
WidgetsBinding.instance?.endOfFrame.then((_) {
|
||||||
|
firstFrameCalled();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void firstFrameCalled() {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return buildWidgets(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildWidgets(BuildContext context);
|
||||||
|
}
|
||||||
41
lib/base/base_viewmodel.dart
Normal file
41
lib/base/base_viewmodel.dart
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
|
class BaseViewModel extends ChangeNotifier {
|
||||||
|
PageState currentState = PageState.START;
|
||||||
|
|
||||||
|
void loading({bool notify = false}) {
|
||||||
|
currentState = PageState.LOADING;
|
||||||
|
if (notify) {
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void success({bool notify = true}) {
|
||||||
|
currentState = PageState.CONTENT;
|
||||||
|
if (notify) {
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void failed({bool notify = false}) {
|
||||||
|
currentState = PageState.FAILED;
|
||||||
|
if (notify) {
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void empty({bool notify = false}) {
|
||||||
|
currentState = PageState.EMPTY;
|
||||||
|
if (notify) {
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PageState {
|
||||||
|
START,
|
||||||
|
LOADING,
|
||||||
|
EMPTY,
|
||||||
|
CONTENT,
|
||||||
|
FAILED,
|
||||||
|
}
|
||||||
48
lib/base/ql_app_bar.dart
Normal file
48
lib/base/ql_app_bar.dart
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class QlAppBar extends StatelessWidget with PreferredSizeWidget {
|
||||||
|
final String title;
|
||||||
|
final List<Widget>? actions;
|
||||||
|
final VoidCallback? backCall;
|
||||||
|
final bool canBack;
|
||||||
|
final Widget? backWidget;
|
||||||
|
|
||||||
|
QlAppBar({
|
||||||
|
Key? key,
|
||||||
|
required this.title,
|
||||||
|
this.actions,
|
||||||
|
this.backCall,
|
||||||
|
this.canBack = true,
|
||||||
|
this.backWidget,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Widget back = backWidget ??
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
if (backCall != null) {
|
||||||
|
backCall!();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: const Center(
|
||||||
|
child: Icon(
|
||||||
|
CupertinoIcons.left_chevron,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return AppBar(
|
||||||
|
leading: canBack ? back : null,
|
||||||
|
automaticallyImplyLeading: canBack,
|
||||||
|
title: Text(title),
|
||||||
|
centerTitle: true,
|
||||||
|
actions: [...?actions],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Size get preferredSize => const Size.fromHeight(kToolbarHeight);
|
||||||
|
}
|
||||||
20
lib/base/theme.dart
Normal file
20
lib/base/theme.dart
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
|
var themeProvider = ChangeNotifierProvider((ref) => ThemeViewModel());
|
||||||
|
|
||||||
|
class ThemeViewModel extends ChangeNotifier {
|
||||||
|
ThemeData currentTheme = lightTheme;
|
||||||
|
|
||||||
|
void changeTheme() {
|
||||||
|
if (currentTheme == darkTheme) {
|
||||||
|
currentTheme = lightTheme;
|
||||||
|
} else {
|
||||||
|
currentTheme = darkTheme;
|
||||||
|
}
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ThemeData darkTheme = ThemeData.dark().copyWith();
|
||||||
|
ThemeData lightTheme = ThemeData.light().copyWith();
|
||||||
126
lib/main.dart
126
lib/main.dart
@@ -1,115 +1,35 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:qinglong_app/base/theme.dart';
|
||||||
|
|
||||||
|
import 'module/home/home_page.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(const MyApp());
|
runApp(
|
||||||
|
ProviderScope(
|
||||||
|
overrides: [
|
||||||
|
themeProvider,
|
||||||
|
],
|
||||||
|
child: const MyApp(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
SystemUiOverlayStyle style = const SystemUiOverlayStyle(statusBarColor: Colors.transparent);
|
||||||
|
SystemChrome.setSystemUIOverlayStyle(style);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends ConsumerWidget {
|
||||||
const MyApp({Key? key}) : super(key: key);
|
const MyApp({Key? key}) : super(key: key);
|
||||||
|
|
||||||
// This widget is the root of your application.
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
title: 'Flutter Demo',
|
theme: ref.watch<ThemeViewModel>(themeProvider).currentTheme,
|
||||||
theme: ThemeData(
|
home: HomePage(),
|
||||||
// This is the theme of your application.
|
|
||||||
//
|
|
||||||
// Try running your application with "flutter run". You'll see the
|
|
||||||
// application has a blue toolbar. Then, without quitting the app, try
|
|
||||||
// changing the primarySwatch below to Colors.green and then invoke
|
|
||||||
// "hot reload" (press "r" in the console where you ran "flutter run",
|
|
||||||
// or simply save your changes to "hot reload" in a Flutter IDE).
|
|
||||||
// Notice that the counter didn't reset back to zero; the application
|
|
||||||
// is not restarted.
|
|
||||||
primarySwatch: Colors.blue,
|
|
||||||
),
|
|
||||||
home: const MyHomePage(title: 'Flutter Demo Home Page'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyHomePage extends StatefulWidget {
|
|
||||||
const MyHomePage({Key? key, required this.title}) : super(key: key);
|
|
||||||
|
|
||||||
// This widget is the home page of your application. It is stateful, meaning
|
|
||||||
// that it has a State object (defined below) that contains fields that affect
|
|
||||||
// how it looks.
|
|
||||||
|
|
||||||
// This class is the configuration for the state. It holds the values (in this
|
|
||||||
// case the title) provided by the parent (in this case the App widget) and
|
|
||||||
// used by the build method of the State. Fields in a Widget subclass are
|
|
||||||
// always marked "final".
|
|
||||||
|
|
||||||
final String title;
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<MyHomePage> createState() => _MyHomePageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _MyHomePageState extends State<MyHomePage> {
|
|
||||||
int _counter = 0;
|
|
||||||
|
|
||||||
void _incrementCounter() {
|
|
||||||
setState(() {
|
|
||||||
// This call to setState tells the Flutter framework that something has
|
|
||||||
// changed in this State, which causes it to rerun the build method below
|
|
||||||
// so that the display can reflect the updated values. If we changed
|
|
||||||
// _counter without calling setState(), then the build method would not be
|
|
||||||
// called again, and so nothing would appear to happen.
|
|
||||||
_counter++;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
// This method is rerun every time setState is called, for instance as done
|
|
||||||
// by the _incrementCounter method above.
|
|
||||||
//
|
|
||||||
// The Flutter framework has been optimized to make rerunning build methods
|
|
||||||
// fast, so that you can just rebuild anything that needs updating rather
|
|
||||||
// than having to individually change instances of widgets.
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
// Here we take the value from the MyHomePage object that was created by
|
|
||||||
// the App.build method, and use it to set our appbar title.
|
|
||||||
title: Text(widget.title),
|
|
||||||
),
|
|
||||||
body: Center(
|
|
||||||
// Center is a layout widget. It takes a single child and positions it
|
|
||||||
// in the middle of the parent.
|
|
||||||
child: Column(
|
|
||||||
// Column is also a layout widget. It takes a list of children and
|
|
||||||
// arranges them vertically. By default, it sizes itself to fit its
|
|
||||||
// children horizontally, and tries to be as tall as its parent.
|
|
||||||
//
|
|
||||||
// Invoke "debug painting" (press "p" in the console, choose the
|
|
||||||
// "Toggle Debug Paint" action from the Flutter Inspector in Android
|
|
||||||
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
|
|
||||||
// to see the wireframe for each widget.
|
|
||||||
//
|
|
||||||
// Column has various properties to control how it sizes itself and
|
|
||||||
// how it positions its children. Here we use mainAxisAlignment to
|
|
||||||
// center the children vertically; the main axis here is the vertical
|
|
||||||
// axis because Columns are vertical (the cross axis would be
|
|
||||||
// horizontal).
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
const Text(
|
|
||||||
'You have pushed the button this many times:',
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'$_counter',
|
|
||||||
style: Theme.of(context).textTheme.headline4,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
floatingActionButton: FloatingActionButton(
|
|
||||||
onPressed: _incrementCounter,
|
|
||||||
tooltip: 'Increment',
|
|
||||||
child: const Icon(Icons.add),
|
|
||||||
), // This trailing comma makes auto-formatting nicer for build methods.
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
0
lib/module/a.dart
Normal file
0
lib/module/a.dart
Normal file
15
lib/module/config/config_page.dart
Normal file
15
lib/module/config/config_page.dart
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class ConfigPage extends StatefulWidget {
|
||||||
|
const ConfigPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_ConfigPageState createState() => _ConfigPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ConfigPageState extends State<ConfigPage> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold();
|
||||||
|
}
|
||||||
|
}
|
||||||
16
lib/module/env/env_page.dart
vendored
Normal file
16
lib/module/env/env_page.dart
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class EnvPage extends StatefulWidget {
|
||||||
|
const EnvPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_EnvPageState createState() => _EnvPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _EnvPageState extends State<EnvPage> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold();
|
||||||
|
}
|
||||||
|
}
|
||||||
117
lib/module/home/home_page.dart
Normal file
117
lib/module/home/home_page.dart
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:qinglong_app/base/ql_app_bar.dart';
|
||||||
|
import 'package:qinglong_app/base/theme.dart';
|
||||||
|
import 'package:qinglong_app/module/config/config_page.dart';
|
||||||
|
import 'package:qinglong_app/module/env/env_page.dart';
|
||||||
|
import 'package:qinglong_app/module/others/other_page.dart';
|
||||||
|
import 'package:qinglong_app/module/task/task_page.dart';
|
||||||
|
|
||||||
|
class HomePage extends StatefulWidget {
|
||||||
|
const HomePage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_HomePageState createState() => _HomePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HomePageState extends State<HomePage> {
|
||||||
|
int _index = 0;
|
||||||
|
String _title = "";
|
||||||
|
|
||||||
|
List<IndexBean> titles = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
initTitles();
|
||||||
|
_title = titles[0].title;
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: QlAppBar(
|
||||||
|
canBack: false,
|
||||||
|
title: _title,
|
||||||
|
actions: [
|
||||||
|
Consumer(builder: (context, ref, child) {
|
||||||
|
return InkWell(
|
||||||
|
onTap: () {
|
||||||
|
ref.read(themeProvider).changeTheme();
|
||||||
|
},
|
||||||
|
child: Center(child: Text("改变主题")),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: IndexedStack(
|
||||||
|
index: _index,
|
||||||
|
children: const [
|
||||||
|
TaskPage(),
|
||||||
|
EnvPage(),
|
||||||
|
ConfigPage(),
|
||||||
|
OtherPage(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
bottomNavigationBar: BottomNavigationBar(
|
||||||
|
items: titles
|
||||||
|
.map(
|
||||||
|
(e) => BottomNavigationBarItem(
|
||||||
|
icon: Icon(e.icon),
|
||||||
|
activeIcon: Icon(e.checkedIcon),
|
||||||
|
label: e.title,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
currentIndex: _index,
|
||||||
|
onTap: (index) {
|
||||||
|
_index = index;
|
||||||
|
_title = titles[index].title;
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
type: BottomNavigationBarType.fixed,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initTitles() {
|
||||||
|
titles.clear();
|
||||||
|
titles.add(
|
||||||
|
IndexBean(
|
||||||
|
CupertinoIcons.timer,
|
||||||
|
CupertinoIcons.timer_fill,
|
||||||
|
"定时任务",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
titles.add(
|
||||||
|
IndexBean(
|
||||||
|
CupertinoIcons.hammer,
|
||||||
|
CupertinoIcons.hammer_fill,
|
||||||
|
"环境变量",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
titles.add(
|
||||||
|
IndexBean(
|
||||||
|
CupertinoIcons.settings,
|
||||||
|
CupertinoIcons.settings_solid,
|
||||||
|
"配置文件",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
titles.add(
|
||||||
|
IndexBean(
|
||||||
|
CupertinoIcons.cube,
|
||||||
|
CupertinoIcons.cube_fill,
|
||||||
|
"其他",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class IndexBean {
|
||||||
|
IconData icon;
|
||||||
|
IconData checkedIcon;
|
||||||
|
String title;
|
||||||
|
|
||||||
|
IndexBean(this.icon, this.checkedIcon, this.title);
|
||||||
|
}
|
||||||
15
lib/module/others/other_page.dart
Normal file
15
lib/module/others/other_page.dart
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class OtherPage extends StatefulWidget {
|
||||||
|
const OtherPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_OtherPageState createState() => _OtherPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _OtherPageState extends State<OtherPage> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold();
|
||||||
|
}
|
||||||
|
}
|
||||||
33
lib/module/task/task_page.dart
Normal file
33
lib/module/task/task_page.dart
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:qinglong_app/base/base_state_widget.dart';
|
||||||
|
import 'package:qinglong_app/module/task/task_viewmodel.dart';
|
||||||
|
|
||||||
|
class TaskPage extends StatefulWidget {
|
||||||
|
const TaskPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_TaskPageState createState() => _TaskPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TaskPageState extends State<TaskPage> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BaseStateWidget<TaskViewModel>(
|
||||||
|
builder: (context, model, child) {
|
||||||
|
return ListView.builder(
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return ListTile(
|
||||||
|
title: Text(model.list[index]),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
itemCount: model.list.length,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
model: taskProvider,
|
||||||
|
onReady: (viewModel) {
|
||||||
|
viewModel.loadData();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
31
lib/module/task/task_viewmodel.dart
Normal file
31
lib/module/task/task_viewmodel.dart
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:qinglong_app/base/base_viewmodel.dart';
|
||||||
|
|
||||||
|
var taskProvider = ChangeNotifierProvider((ref) => TaskViewModel());
|
||||||
|
|
||||||
|
class TaskViewModel extends BaseViewModel {
|
||||||
|
List<String> list = [];
|
||||||
|
|
||||||
|
void loadData() {
|
||||||
|
loading(notify: true);
|
||||||
|
|
||||||
|
Future.delayed(Duration(seconds: 2), () {
|
||||||
|
list.add("sdfsf");
|
||||||
|
list.add("sdfsf");
|
||||||
|
list.add("sdfsf");
|
||||||
|
list.add("sdfsf");
|
||||||
|
list.add("sdfsf");
|
||||||
|
list.add("sdfsf");
|
||||||
|
list.add("sdfsf");
|
||||||
|
list.add("sdfsf");
|
||||||
|
list.add("sdfsf");
|
||||||
|
list.add("sdfsf");
|
||||||
|
list.add("sdfsf");
|
||||||
|
list.add("sdfsf");
|
||||||
|
list.add("sdfsf");
|
||||||
|
list.add("sdfsf");
|
||||||
|
list.add("sdfsf");
|
||||||
|
success();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
171
lib/utils/sp_utils.dart
Normal file
171
lib/utils/sp_utils.dart
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'package:synchronized/synchronized.dart';
|
||||||
|
|
||||||
|
class SpUtil {
|
||||||
|
static SpUtil? _singleton;
|
||||||
|
static SharedPreferences? _prefs;
|
||||||
|
static Lock _lock = Lock();
|
||||||
|
|
||||||
|
static Future<SpUtil> getInstance() async {
|
||||||
|
if (_singleton == null) {
|
||||||
|
await _lock.synchronized(() async {
|
||||||
|
if (_singleton == null) {
|
||||||
|
var singleton = SpUtil._();
|
||||||
|
await singleton._init();
|
||||||
|
_singleton = singleton;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return _singleton!;
|
||||||
|
}
|
||||||
|
|
||||||
|
SpUtil._();
|
||||||
|
|
||||||
|
Future _init() async {
|
||||||
|
_prefs = await SharedPreferences.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// put object.
|
||||||
|
static Future<bool>? putObject(String key, Object value) {
|
||||||
|
if (_prefs == null) return null;
|
||||||
|
return _prefs!.setString(key, json.encode(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get obj.
|
||||||
|
static T? getObj<T>(String key, T f(Map v), {T? defValue}) {
|
||||||
|
Map? map = getObject(key);
|
||||||
|
return map == null ? defValue : f(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get object.
|
||||||
|
static Map? getObject(String key) {
|
||||||
|
if (_prefs == null) return null;
|
||||||
|
String? _data = _prefs!.getString(key);
|
||||||
|
return (_data == null || _data.isEmpty) ? null : json.decode(_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// put object list.
|
||||||
|
static Future<bool>? putObjectList(String key, List<Object> list) {
|
||||||
|
if (_prefs == null) return null;
|
||||||
|
List<String> _dataList = list.map((value) {
|
||||||
|
return json.encode(value);
|
||||||
|
}).toList();
|
||||||
|
return _prefs!.setStringList(key, _dataList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get obj list.
|
||||||
|
static List<T>? getObjList<T>(String key, T f(Map v), {List<T> defValue = const []}) {
|
||||||
|
List<Map>? dataList = getObjectList(key);
|
||||||
|
List<T>? list = dataList?.map((value) {
|
||||||
|
return f(value);
|
||||||
|
}).toList();
|
||||||
|
return list ?? defValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get object list.
|
||||||
|
static List<Map>? getObjectList(String key) {
|
||||||
|
if (_prefs == null) return null;
|
||||||
|
List<String>? dataLis = _prefs!.getStringList(key);
|
||||||
|
return dataLis?.map((value) {
|
||||||
|
Map _dataMap = json.decode(value);
|
||||||
|
return _dataMap;
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get string.
|
||||||
|
static String getString(String key, {String defValue = ''}) {
|
||||||
|
if (_prefs == null) return defValue;
|
||||||
|
return _prefs!.getString(key) ?? defValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// put string.
|
||||||
|
static Future<bool>? putString(String key, String value) {
|
||||||
|
if (_prefs == null) return null;
|
||||||
|
return _prefs!.setString(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get bool.
|
||||||
|
static bool getBool(String key, {bool defValue = false}) {
|
||||||
|
if (_prefs == null) return defValue;
|
||||||
|
return _prefs!.getBool(key) ?? defValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// put bool.
|
||||||
|
static Future<bool>? putBool(String key, bool value) {
|
||||||
|
if (_prefs == null) return null;
|
||||||
|
return _prefs!.setBool(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get int.
|
||||||
|
static int getInt(String key, {int defValue = 0}) {
|
||||||
|
if (_prefs == null) return defValue;
|
||||||
|
return _prefs!.getInt(key) ?? defValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// put int.
|
||||||
|
static Future<bool>? putInt(String key, int value) {
|
||||||
|
if (_prefs == null) return null;
|
||||||
|
return _prefs!.setInt(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get double.
|
||||||
|
static double getDouble(String key, {double defValue = 0.0}) {
|
||||||
|
if (_prefs == null) return defValue;
|
||||||
|
return _prefs!.getDouble(key) ?? defValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// put double.
|
||||||
|
static Future<bool>? putDouble(String key, double value) {
|
||||||
|
if (_prefs == null) return null;
|
||||||
|
return _prefs!.setDouble(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get string list.
|
||||||
|
static List<String> getStringList(String key, {List<String> defValue = const []}) {
|
||||||
|
if (_prefs == null) return defValue;
|
||||||
|
return _prefs!.getStringList(key) ?? defValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// put string list.
|
||||||
|
static Future<bool>? putStringList(String key, List<String> value) {
|
||||||
|
if (_prefs == null) return null;
|
||||||
|
return _prefs!.setStringList(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get dynamic.
|
||||||
|
static dynamic getDynamic(String key, {Object? defValue}) {
|
||||||
|
if (_prefs == null) return defValue;
|
||||||
|
return _prefs!.get(key) ?? defValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// have key.
|
||||||
|
static bool haveKey(String key) {
|
||||||
|
if (_prefs == null) return false;
|
||||||
|
return _prefs!.getKeys().contains(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get keys.
|
||||||
|
static Set<String>? getKeys() {
|
||||||
|
if (_prefs == null) return null;
|
||||||
|
return _prefs!.getKeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// remove.
|
||||||
|
static Future<bool>? remove(String key) {
|
||||||
|
if (_prefs == null) return null;
|
||||||
|
return _prefs!.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// clear.
|
||||||
|
static Future<bool>? clear() {
|
||||||
|
if (_prefs == null) return null;
|
||||||
|
return _prefs!.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
///Sp is initialized.
|
||||||
|
static bool isInitialized() {
|
||||||
|
return _prefs != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
167
pubspec.lock
167
pubspec.lock
@@ -57,6 +57,20 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.2.0"
|
||||||
|
ffi:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: ffi
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.2"
|
||||||
|
file:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "6.1.2"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -69,11 +83,30 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.4"
|
||||||
|
flutter_riverpod:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_riverpod
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.3"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_web_plugins:
|
||||||
|
dependency: transitive
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
|
js:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: js
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "0.6.3"
|
||||||
lints:
|
lints:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -102,6 +135,111 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.0"
|
version: "1.8.0"
|
||||||
|
path_provider_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_linux
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.5"
|
||||||
|
path_provider_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_platform_interface
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.3"
|
||||||
|
path_provider_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_windows
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.5"
|
||||||
|
platform:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: platform
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.0"
|
||||||
|
plugin_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: plugin_platform_interface
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
|
process:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: process
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "4.2.4"
|
||||||
|
riverpod:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: riverpod
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.3"
|
||||||
|
shared_preferences:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: shared_preferences
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.12"
|
||||||
|
shared_preferences_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_android
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.10"
|
||||||
|
shared_preferences_ios:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_ios
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.9"
|
||||||
|
shared_preferences_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_linux
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.4"
|
||||||
|
shared_preferences_macos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_macos
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.2"
|
||||||
|
shared_preferences_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_platform_interface
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
|
shared_preferences_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_web
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.3"
|
||||||
|
shared_preferences_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_windows
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.4"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -121,6 +259,13 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.10.0"
|
version: "1.10.0"
|
||||||
|
state_notifier:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: state_notifier
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.1"
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -135,6 +280,13 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.0"
|
||||||
|
synchronized:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: synchronized
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
term_glyph:
|
term_glyph:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -163,5 +315,20 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.1"
|
||||||
|
win32:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: win32
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.3"
|
||||||
|
xdg_directories:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: xdg_directories
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.0"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.15.1 <3.0.0"
|
dart: ">=2.15.1 <3.0.0"
|
||||||
|
flutter: ">=2.5.0"
|
||||||
|
|||||||
37
pubspec.yaml
37
pubspec.yaml
@@ -1,55 +1,28 @@
|
|||||||
name: qinglong_app
|
name: qinglong_app
|
||||||
description: A new Flutter project.
|
description: A new Flutter project.
|
||||||
|
|
||||||
# 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
|
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||||
|
|
||||||
# The following defines the version and build number for your application.
|
|
||||||
# A version number is three numbers separated by dots, like 1.2.43
|
|
||||||
# followed by an optional build number separated by a +.
|
|
||||||
# Both the version and the builder number may be overridden in flutter
|
|
||||||
# build by specifying --build-name and --build-number, respectively.
|
|
||||||
# In Android, build-name is used as versionName while build-number used as versionCode.
|
|
||||||
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
|
|
||||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
|
||||||
# Read more about iOS versioning at
|
|
||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
|
||||||
version: 1.0.0+1
|
version: 1.0.0+1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.15.1 <3.0.0"
|
sdk: ">=2.15.1 <3.0.0"
|
||||||
|
|
||||||
# Dependencies specify other packages that your package needs in order to work.
|
|
||||||
# To automatically upgrade your package dependencies to the latest versions
|
|
||||||
# consider running `flutter pub upgrade --major-versions`. Alternatively,
|
|
||||||
# dependencies can be manually updated by changing the version numbers below to
|
|
||||||
# the latest version available on pub.dev. To see which dependencies have newer
|
|
||||||
# versions available, run `flutter pub outdated`.
|
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
|
|
||||||
# The following adds the Cupertino Icons font to your application.
|
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
|
||||||
cupertino_icons: ^1.0.2
|
cupertino_icons: ^1.0.2
|
||||||
|
flutter_riverpod: ^1.0.3
|
||||||
|
shared_preferences: ^2.0.12
|
||||||
|
synchronized: ^3.0.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
# The "flutter_lints" package below contains a set of recommended lints to
|
|
||||||
# encourage good coding practices. The lint set provided by the package is
|
|
||||||
# activated in the `analysis_options.yaml` file located at the root of your
|
|
||||||
# package. See that file for information about deactivating specific lint
|
|
||||||
# rules and activating additional ones.
|
|
||||||
flutter_lints: ^1.0.0
|
flutter_lints: ^1.0.0
|
||||||
|
|
||||||
# For information on the generic Dart part of this file, see the
|
|
||||||
# following page: https://dart.dev/tools/pub/pubspec
|
|
||||||
|
|
||||||
# The following section is specific to Flutter.
|
|
||||||
flutter:
|
flutter:
|
||||||
|
|
||||||
# The following line ensures that the Material Icons font is
|
# The following line ensures that the Material Icons font is
|
||||||
|
|||||||
Reference in New Issue
Block a user