提交 a5ca16e2 authored 作者: yueweilu's avatar yueweilu

书架界面

上级 d9bb1748
...@@ -25,7 +25,7 @@ class MyApp extends StatelessWidget { ...@@ -25,7 +25,7 @@ class MyApp extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ScreenUtilInit( return ScreenUtilInit(
designSize: const Size(428, 926), designSize: const Size(375, 667),
builder: (context, child) => RefreshConfiguration( builder: (context, child) => RefreshConfiguration(
headerBuilder: () => const ClassicHeader( headerBuilder: () => const ClassicHeader(
refreshingIcon: CupertinoActivityIndicator(), refreshingIcon: CupertinoActivityIndicator(),
......
library about;
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_book/widgets/index.dart';
part 'view.dart';
\ No newline at end of file
part of about;
class AboutPage extends StatelessWidget {
const AboutPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return SafeArea(
top: false,
child: Scaffold(
appBar: AppBar(
title: Text('关于我们'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
// crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
children: [
Container(
margin: EdgeInsets.only(top: 40),
height: 50,
width: 50,
color: Colors.cyan,
child: CustomImage.asset(url: 'assets/images/banner.png'),
),
Text('云教材'),
Text('V1.0.1'),
],
),
Container(
color: Colors.cyan,
alignment: Alignment.center,
height: 50,
child: Row(
mainAxisAlignment:MainAxisAlignment.spaceBetween,
children: [
Expanded(child: Text('《用户协议》',textAlign: TextAlign.right,)),
Expanded(child: Text('《隐私协议》',textAlign: TextAlign.left)),
],
),
)
],
),
),
);
}
}
part of book_shop;
\ No newline at end of file
library book_shop;
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../../theme.dart';
part 'controller.dart';
part 'view.dart';
part 'widgets/book.dart';
part 'widgets/count.dart';
\ No newline at end of file
part of book_shop;
class BookShopPage extends StatefulWidget {
const BookShopPage({Key? key}) : super(key: key);
@override
State<BookShopPage> createState() => _BookShopPageState();
}
class _BookShopPageState extends State<BookShopPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('书架'),
),
body: Column(
children: [
Expanded(
child: ListView.builder(
itemBuilder: (BuildContext context,int index){
return const BookCell();
},
itemCount: 2,
),
),
createCounter()
],
),
);
}
Widget createCounter() {
return Container(
color: Colors.white,
padding: EdgeInsets.only(left: 20,right: 15),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
child: Row(
children: [
Container(
height: 17,
width: 17,
color: Colors.yellow,
),
SizedBox(width: 11),
Text('全选',style: TextStyle(color: Color(0xFF333333),fontSize: 12,fontWeight: FontWeight.w500)),
SizedBox(width: 15,),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('合计 ¥98.9',style: TextStyle(color: AppTheme.primary,fontSize: 12,fontWeight: FontWeight.w500)),
Text('已选 2 件',style: TextStyle(color: Color(0xFF9999999),fontSize: 10,))
],
)
],
),
),
Container(
margin: EdgeInsets.symmetric(vertical: 9),
decoration: BoxDecoration(
color: AppTheme.primary,
borderRadius: BorderRadius.circular(15),
),
padding: EdgeInsets.symmetric(vertical: 5,horizontal: 18),
child: Text('结算(2)',style: TextStyle(color: Colors.white,fontSize: 12,fontWeight: FontWeight.w500),),
)
],
),
Container(
height: 1,
color: Color(0xFFF9F9F9),
)
],
),
);
}
}
part of book_shop;
class BookCell extends StatelessWidget {
const BookCell({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius:BorderRadius.circular(5),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Color(0xFFC7C7C7).withOpacity(0.5),
spreadRadius: 2,
blurRadius: 5,
offset: Offset(3, 0), // changes the position of the shadow
),
]
),
margin: const EdgeInsets.only(left: 10,right: 10,top: 10),
height: 110,
child: Row(
children: [
///左侧
Container(
margin: const EdgeInsets.only(left: 12,right: 11),
child: Row(
children: [
Container(
height: 17,
width: 17,
color: Colors.cyan,
),
const SizedBox(width: 12,),
Container(
child: Container(
padding: EdgeInsets.all(2),
child: Container(
color: Colors.cyan,
),
),
decoration: BoxDecoration(
color: Colors.cyan,
borderRadius: BorderRadius.circular(3),
boxShadow: [
BoxShadow(
color: Color(0xFF707070).withOpacity(0.5),
spreadRadius: 2,
blurRadius: 5,
offset: Offset(3, 0), // changes the position of the shadow
),
]
),
// color: Colors.white,
height: 86,
width: 72,
)
],
),
),
///右侧
Expanded(
child: Container(
padding: const EdgeInsets.only(top: 12,bottom: 10),
child: const Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('一想到还有95%的问题留给人类,我就放一想到还有95%的问题留给人类,我就放一想到还有95%的问题留给人类,我就放',style: TextStyle(fontSize: 13,fontWeight: FontWeight.w500,color: Color(0xFF333333)),maxLines: 2,overflow: TextOverflow.ellipsis,),
SizedBox(height: 5,),
Text('威廉·莎士比亚',style: TextStyle(fontSize: 11,fontWeight: FontWeight.w400,color: Color(0xFF999999))),
],
),
Text('¥88',style: TextStyle(fontSize: 14,fontWeight: FontWeight.w500,color: AppTheme.primary)),
],
),
),
)
],
)
);
}
}
part of book_shop;
class Counter extends StatelessWidget {
const Counter({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
children: [
GestureDetector(
onTap: (){
},
child: Row(
children: [
Container(width: 20,height: 20,color: Colors.cyan,),
const SizedBox(width: 11,),
const Text('全选',style: TextStyle(color: Color(0xFF333333),fontSize: 12,fontWeight:FontWeight.w500)),
],
),
),
Column(
children: [
Text('合计',style: TextStyle(color: AppTheme.primary)),
Text('已选1件',style: TextStyle(color: Color(0xFF333333)),)
],
),
],
);
}
}
...@@ -17,13 +17,31 @@ class _HomePageState extends State<HomePage> { ...@@ -17,13 +17,31 @@ class _HomePageState extends State<HomePage> {
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
ElevatedButton( GestureDetector(
onPressed: (){ onTap: (){
context.pushNamed(Routes.web); context.pushNamed(Routes.web);
}, },
child: const Text('web'), child: Container(
color: Colors.cyan,
child: Text('web'),
height: 40,
// width: double.infinity,
alignment: Alignment.center,
),
),
GestureDetector(
onTap: (){
context.pushNamed(Routes.about);
},
child: Container(
color: Colors.indigo,
child: Text('关于我们'),
height: 40,
width: double.infinity,
alignment: Alignment.center,
),
) )
], ],
) )
); );
......
...@@ -7,6 +7,7 @@ import 'package:flutter_book/theme.dart'; ...@@ -7,6 +7,7 @@ import 'package:flutter_book/theme.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:ionicons/ionicons.dart'; import 'package:ionicons/ionicons.dart';
import '../book_shop/index.dart';
import '../record/index.dart'; import '../record/index.dart';
import '../tts/index.dart'; import '../tts/index.dart';
import '../web/index.dart'; import '../web/index.dart';
......
...@@ -41,8 +41,8 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver{ ...@@ -41,8 +41,8 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver{
children: const [ children: const [
HomePage(), HomePage(),
LibraryPage(), LibraryPage(),
TestTTSPage(), BookShopPage(),
RecordPage(), // RecordPage(),
HomePage(), HomePage(),
], ],
), ),
...@@ -57,7 +57,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver{ ...@@ -57,7 +57,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver{
BottomNavigationBarItem( BottomNavigationBarItem(
icon: Icon(Ionicons.home_outline), icon: Icon(Ionicons.home_outline),
activeIcon:Icon(Ionicons.home), activeIcon:Icon(Ionicons.home),
label: '发现', label: '课程',
), ),
BottomNavigationBarItem( BottomNavigationBarItem(
icon: Icon(Ionicons.bookmarks), icon: Icon(Ionicons.bookmarks),
...@@ -69,11 +69,6 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver{ ...@@ -69,11 +69,6 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver{
activeIcon:Icon(Ionicons.chatbubbles), activeIcon:Icon(Ionicons.chatbubbles),
label: '书架', label: '书架',
), ),
BottomNavigationBarItem(
icon: Icon(Ionicons.person_outline),
activeIcon:Icon(Ionicons.person),
label: '课程',
),
BottomNavigationBarItem( BottomNavigationBarItem(
icon: Icon(Ionicons.person_outline), icon: Icon(Ionicons.person_outline),
activeIcon:Icon(Ionicons.person), activeIcon:Icon(Ionicons.person),
......
part of mine;
\ No newline at end of file
library mine;
\ No newline at end of file
part of mine;
\ No newline at end of file
...@@ -4,16 +4,19 @@ class ReadController extends GetxController with GetSingleTickerProviderStateMix ...@@ -4,16 +4,19 @@ class ReadController extends GetxController with GetSingleTickerProviderStateMix
late AnimationController _controller; late AnimationController _controller;
bool _show = false; bool _show = false;
bool get show => _show; bool get show => _show;
void setShow(bool value) { void setShow(bool value) {
_show = !value; _show = !value;
if (_show) { if (_show) {
/// 显示状态栏
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
/// 开启动画
_controller.forward(); _controller.forward();
} }
else { else {
/// 不显示状态栏
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
/// 收回动画
_controller.reverse(); _controller.reverse();
} }
update(); update();
...@@ -25,7 +28,9 @@ class ReadController extends GetxController with GetSingleTickerProviderStateMix ...@@ -25,7 +28,9 @@ class ReadController extends GetxController with GetSingleTickerProviderStateMix
@override @override
void onInit() { void onInit() {
/// 默认不显示状态栏
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
/// 初始化
_controller = AnimationController( _controller = AnimationController(
vsync: this, vsync: this,
duration: const Duration(milliseconds: 100), duration: const Duration(milliseconds: 100),
......
...@@ -8,8 +8,9 @@ class WebPage extends StatefulWidget { ...@@ -8,8 +8,9 @@ class WebPage extends StatefulWidget {
} }
class _WebPageState extends State<WebPage> { class _WebPageState extends State<WebPage> {
final GlobalKey webViewKey = GlobalKey();
InAppWebViewController? webViewController;
late ContextMenu contextMenu;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
...@@ -19,42 +20,73 @@ class _WebPageState extends State<WebPage> { ...@@ -19,42 +20,73 @@ class _WebPageState extends State<WebPage> {
return GetBuilder<ReadController>( return GetBuilder<ReadController>(
init: ReadController(), init: ReadController(),
builder: (readController) => Scaffold( builder: (readController) => Scaffold(
// appBar: AppBar(title:const Text('章节名称'),),
body: Stack( body: Stack(
children: [ children: [
Container(
height: 40,
width: double.infinity,
color: Colors.lightBlue,
),
InAppWebView( InAppWebView(
initialUrlRequest: URLRequest( initialUrlRequest: URLRequest(
url: Uri.parse('http://192.168.11.39:5500/'), url: Uri.parse('http://192.168.11.39:5500/'),
), ),
onWebViewCreated: (InAppWebViewController controller) {
webViewController = controller;
},
// onLoadError: (InAppWebViewController controller, Uri url, int code ,String msg){ // onLoadError: (InAppWebViewController controller, Uri url, int code ,String msg){
// //
// }, // },
contextMenu: ContextMenu( contextMenu: ContextMenu(
menuItems: [ menuItems: [
ContextMenuItem(title: '划线',androidId: 1,iosId: '1'), ContextMenuItem(title: '划线',androidId: 1,iosId: '1',action: (){
ContextMenuItem(title: '提问',androidId: 2,iosId: '2'), const snackBar = SnackBar(
ContextMenuItem(title: '笔记',androidId: 3,iosId: '3'), content: Text("划线"),
ContextMenuItem(title: '划线1',androidId: 1,iosId: '1'), duration: Duration(seconds: 1),
ContextMenuItem(title: '划线2',androidId: 1,iosId: '1'), );
ContextMenuItem(title: '划线3',androidId: 1,iosId: '1'), ScaffoldMessenger.of(context).showSnackBar(snackBar);
ContextMenuItem(title: '划线4',androidId: 1,iosId: '1'), }),
ContextMenuItem(title: '提问',androidId: 2,iosId: '2',action: (){
}),
ContextMenuItem(title: '笔记',androidId: 3,iosId: '3',action: (){
}),
], ],
options: ContextMenuOptions( onCreateContextMenu: (hitTestResult) async {
hideDefaultSystemContextMenuItems: false, String selectedText = await webViewController?.getSelectedText() ?? "";
), final snackBar = SnackBar(
onContextMenuActionItemClicked: (ContextMenuItem item) async { content: Text(
switch (item.title){ "Selected text: '$selectedText', of type: ${hitTestResult.type.toString()}"),
case '划线': duration: const Duration(seconds: 1),
Console.log('----------划线-----------'); );
break; ScaffoldMessenger.of(context).showSnackBar(snackBar);
case '提问': },
Console.log('----------提问-----------'); // options: ContextMenuOptions(
break; // hideDefaultSystemContextMenuItems: true,
case '笔记': // ),
Console.log('----------笔记-----------'); onContextMenuActionItemClicked: (ContextMenuItem menuItem) async {
break; final snackBar = SnackBar(
content: Text(
"Menu item with ID ${menuItem.iosId} and title '${menuItem.title}' clicked!"),
duration: const Duration(seconds: 1),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
} // switch (item.title){
// case '划线':
// Console.log('----------划线-----------');
// break;
// case '提问':
// Console.log('----------提问-----------');
// break;
// case '笔记':
// Console.log('----------笔记-----------');
// break;
//
// }
} }
), ),
......
...@@ -2,6 +2,7 @@ library routes; ...@@ -2,6 +2,7 @@ library routes;
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter_book/pages/about/index.dart';
import 'package:flutter_book/pages/ad/index.dart'; import 'package:flutter_book/pages/ad/index.dart';
import 'package:flutter_book/pages/login/index.dart'; import 'package:flutter_book/pages/login/index.dart';
import 'package:flutter_book/pages/main/index.dart'; import 'package:flutter_book/pages/main/index.dart';
......
...@@ -9,6 +9,8 @@ abstract class Routes { ...@@ -9,6 +9,8 @@ abstract class Routes {
static const ad = 'ad'; static const ad = 'ad';
static const login = 'login'; static const login = 'login';
static const web = 'web'; static const web = 'web';
static const about = 'about';
static final GoRouter config = GoRouter( static final GoRouter config = GoRouter(
// initialLocation: '/$splash', // initialLocation: '/$splash',
...@@ -59,6 +61,15 @@ abstract class Routes { ...@@ -59,6 +61,15 @@ abstract class Routes {
key: state.pageKey, key: state.pageKey,
child: const WebPage() child: const WebPage()
) )
),
GoRoute(
path: '/$about',
name: about,
pageBuilder: (context, state) =>CupertinoPage(
name: state.uri.toString(),
key: state.pageKey,
child: const AboutPage()
)
) )
] ]
); );
......
...@@ -7,10 +7,10 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; ...@@ -7,10 +7,10 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
abstract class AppTheme { abstract class AppTheme {
// 应用程序默认边距 // 应用程序默认边距
static const margin = 16.0; static const margin = 10.0;
// 主要/主题颜色的常量 // 主要/主题颜色的常量
static const primary = Color(0xFF2972FE); static const primary = Color(0xFFAB1941);
// 成功状态的颜色 // 成功状态的颜色
static const success = Color(0xFF23A757); static const success = Color(0xFF23A757);
// 警告状态的颜色 // 警告状态的颜色
...@@ -71,7 +71,7 @@ abstract class AppTheme { ...@@ -71,7 +71,7 @@ abstract class AppTheme {
static ThemeData get light { static ThemeData get light {
var scheme = ColorScheme.light( var scheme = ColorScheme.light(
background: Colors.white, background: const Color(0xFFF9F9F9),
onBackground: const Color(0xFF333333), onBackground: const Color(0xFF333333),
surface: Colors.white, surface: Colors.white,
onSurface: const Color(0xFF333333), onSurface: const Color(0xFF333333),
...@@ -81,7 +81,7 @@ abstract class AppTheme { ...@@ -81,7 +81,7 @@ abstract class AppTheme {
onSecondary: Colors.white, onSecondary: Colors.white,
tertiary: const Color(0xFFF4F6F9), tertiary: const Color(0xFFF4F6F9),
outline: const Color(0xFFF4F6F9), outline: const Color(0xFFF4F6F9),
shadow: const Color(0xFF5A6CEA).withOpacity(0.08), shadow: const Color(0xFFAB1941).withOpacity(0.08),
error: error, error: error,
onError: Colors.white, onError: Colors.white,
); );
...@@ -140,8 +140,8 @@ abstract class AppTheme { ...@@ -140,8 +140,8 @@ abstract class AppTheme {
), ),
), ),
appBarTheme: AppBarTheme( appBarTheme: AppBarTheme(
systemOverlayStyle: SystemUiOverlayStyle.light, systemOverlayStyle: SystemUiOverlayStyle.dark,
backgroundColor: scheme.background, backgroundColor: const Color(0x05AB1941),
scrolledUnderElevation: 0, scrolledUnderElevation: 0,
elevation: 0, elevation: 0,
centerTitle: true, centerTitle: true,
...@@ -150,9 +150,10 @@ abstract class AppTheme { ...@@ -150,9 +150,10 @@ abstract class AppTheme {
color: scheme.onBackground, color: scheme.onBackground,
size: 22.w, size: 22.w,
), ),
titleTextStyle: TextStyle( titleTextStyle: TextStyle(
color: scheme.onBackground, color: scheme.onBackground,
fontSize: 24.w, fontSize: 17.w,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
height: 1.2, height: 1.2,
), ),
...@@ -185,14 +186,14 @@ abstract class AppTheme { ...@@ -185,14 +186,14 @@ abstract class AppTheme {
backgroundColor: scheme.background, backgroundColor: scheme.background,
unselectedItemColor: scheme.onBackground.withOpacity(0.5), unselectedItemColor: scheme.onBackground.withOpacity(0.5),
selectedItemColor: scheme.primary, selectedItemColor: scheme.primary,
unselectedLabelStyle: TextStyle(fontSize: 13.w, height: 1.6), unselectedLabelStyle: TextStyle(fontSize: 10.w, height: 1.6),
selectedLabelStyle: TextStyle(fontSize: 13.w, height: 1.6), selectedLabelStyle: TextStyle(fontSize: 10.w, height: 1.6),
unselectedIconTheme: IconThemeData( unselectedIconTheme: IconThemeData(
size: 24.w, size: 15.w,
color: scheme.onBackground.withOpacity(0.5), color: scheme.onBackground.withOpacity(0.5),
), ),
selectedIconTheme: IconThemeData( selectedIconTheme: IconThemeData(
size: 24.w, size: 15.w,
color: scheme.primary, color: scheme.primary,
), ),
), ),
......
...@@ -17,4 +17,5 @@ part 'console.dart'; ...@@ -17,4 +17,5 @@ part 'console.dart';
part 'app_config.dart'; part 'app_config.dart';
part 'sign.dart'; part 'sign.dart';
part 'encrypt_util.dart'; part 'encrypt_util.dart';
part 'tools.dart'; part 'tools.dart';
\ No newline at end of file part 'styles.dart';
\ No newline at end of file
part of utils;
class TextStyles {
static const TextStyle c3F13M = TextStyle(
fontSize: 13,
color: Color(0xFF333333),
fontWeight: FontWeight.w500
);
static const TextStyle c9F11 = TextStyle(
fontSize: 11,
color: Color(0xFF999999),
fontWeight: FontWeight.w400
);
}
part of widgets; part of widgets;
enum CustomImageType { asset, network, file } enum CustomImageType { asset, network, file, base64 }
class CustomImage extends StatelessWidget { class CustomImage extends StatelessWidget {
final String url; final String url;
final Widget? placeholder;
final Widget? error;
final CustomImageType type; final CustomImageType type;
final double? width; final double? width;
final double? height; final double? height;
final double? radius; final double? radius;
final BoxFit fit; final BoxFit fit;
final Color? backgroundColor;
final ExtendedImageMode mode; final ExtendedImageMode mode;
final bool enableSlideOutPage; final bool enableSlideOutPage;
final InitGestureConfigHandler? initGestureConfig; final InitGestureConfigHandler? initGestureConfig;
...@@ -31,6 +34,9 @@ class CustomImage extends StatelessWidget { ...@@ -31,6 +34,9 @@ class CustomImage extends StatelessWidget {
this.mode = ExtendedImageMode.none, this.mode = ExtendedImageMode.none,
this.enableSlideOutPage = false, this.enableSlideOutPage = false,
this.initGestureConfig, this.initGestureConfig,
this.backgroundColor,
this.placeholder,
this.error,
}) : super(key: key); }) : super(key: key);
const CustomImage.network({ const CustomImage.network({
...@@ -40,6 +46,9 @@ class CustomImage extends StatelessWidget { ...@@ -40,6 +46,9 @@ class CustomImage extends StatelessWidget {
this.height, this.height,
this.radius, this.radius,
this.fit = BoxFit.cover, this.fit = BoxFit.cover,
this.backgroundColor,
this.placeholder,
this.error,
this.builder, this.builder,
}) : type = CustomImageType.network, }) : type = CustomImageType.network,
mode = ExtendedImageMode.none, mode = ExtendedImageMode.none,
...@@ -54,6 +63,9 @@ class CustomImage extends StatelessWidget { ...@@ -54,6 +63,9 @@ class CustomImage extends StatelessWidget {
this.height, this.height,
this.radius, this.radius,
this.fit = BoxFit.cover, this.fit = BoxFit.cover,
this.backgroundColor,
this.placeholder,
this.error,
this.builder, this.builder,
}) : type = CustomImageType.asset, }) : type = CustomImageType.asset,
mode = ExtendedImageMode.none, mode = ExtendedImageMode.none,
...@@ -68,6 +80,9 @@ class CustomImage extends StatelessWidget { ...@@ -68,6 +80,9 @@ class CustomImage extends StatelessWidget {
this.height, this.height,
this.radius, this.radius,
this.fit = BoxFit.cover, this.fit = BoxFit.cover,
this.backgroundColor,
this.placeholder,
this.error,
this.builder, this.builder,
}) : type = CustomImageType.file, }) : type = CustomImageType.file,
mode = ExtendedImageMode.none, mode = ExtendedImageMode.none,
...@@ -75,61 +90,158 @@ class CustomImage extends StatelessWidget { ...@@ -75,61 +90,158 @@ class CustomImage extends StatelessWidget {
initGestureConfig = null, initGestureConfig = null,
super(key: key); super(key: key);
const CustomImage.base64({
Key? key,
required this.url,
this.width,
this.height,
this.radius,
this.fit = BoxFit.cover,
this.backgroundColor,
this.placeholder,
this.error,
this.builder,
}) : type = CustomImageType.base64,
mode = ExtendedImageMode.none,
enableSlideOutPage = false,
initGestureConfig = null,
super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final borderRadius = BorderRadius.all(Radius.circular(radius ?? 8.w)); final borderRadius = BorderRadius.all(Radius.circular(radius ?? 10));
final Widget errorChild =
error ?? const Icon(Icons.image_not_supported_outlined);
final Widget placeholderChild =
placeholder ?? const CupertinoActivityIndicator(radius: 12);
Widget? image;
switch (type) { switch (type) {
case CustomImageType.asset: case CustomImageType.asset:
return ExtendedImage.asset( if (!url.startsWith('assets/')) {
url, image = errorChild;
width: width, } else {
height: height, image = ExtendedImage.asset(
fit: fit, url,
shape: BoxShape.rectangle, key: ValueKey(url),
borderRadius: borderRadius, width: width,
mode: mode, height: height,
enableSlideOutPage: enableSlideOutPage, fit: fit,
initGestureConfigHandler: initGestureConfig, gaplessPlayback: true,
loadStateChanged: (state) => _buildLoadState(context, state), shape: BoxShape.rectangle,
); borderRadius: borderRadius,
mode: mode,
enableSlideOutPage: enableSlideOutPage,
initGestureConfigHandler: initGestureConfig,
loadStateChanged: (state) => _buildLoadState(
context: context,
state: state,
placeholder: placeholderChild,
error: errorChild,
),
);
}
break;
case CustomImageType.network: case CustomImageType.network:
return ExtendedImage.network( if (!url.startsWith('http')) {
url, image = errorChild;
width: width, } else {
height: height, image = ExtendedImage.network(
fit: fit, url,
shape: BoxShape.rectangle, key: ValueKey(url),
borderRadius: borderRadius, width: width,
mode: mode, height: height,
enableSlideOutPage: enableSlideOutPage, fit: fit,
initGestureConfigHandler: initGestureConfig, shape: BoxShape.rectangle,
loadStateChanged: (state) => _buildLoadState(context, state), borderRadius: borderRadius,
); mode: mode,
gaplessPlayback: true,
enableSlideOutPage: enableSlideOutPage,
initGestureConfigHandler: initGestureConfig,
loadStateChanged: (state) => _buildLoadState(
context: context,
state: state,
placeholder: placeholderChild,
error: errorChild,
),
);
}
break;
case CustomImageType.file: case CustomImageType.file:
return ExtendedImage.file( if (!url.startsWith('/')) {
File(url), image = errorChild;
width: width, } else {
height: height, image = ExtendedImage.file(
fit: fit, File(url),
shape: BoxShape.rectangle, key: ValueKey(url),
borderRadius: borderRadius, width: width,
mode: mode, height: height,
enableSlideOutPage: enableSlideOutPage, fit: fit,
initGestureConfigHandler: initGestureConfig, shape: BoxShape.rectangle,
loadStateChanged: (state) => _buildLoadState(context, state), borderRadius: borderRadius,
); mode: mode,
gaplessPlayback: true,
enableSlideOutPage: enableSlideOutPage,
initGestureConfigHandler: initGestureConfig,
loadStateChanged: (state) => _buildLoadState(
context: context,
state: state,
placeholder: placeholderChild,
error: errorChild,
),
);
}
break;
case CustomImageType.base64:
/*if (!url.startsWith('data:image') &&
(placeholder != null || error != null)) {
image = error ?? placeholder;
} else {
final base64 = url.split(',')[1];
final bytes = const Base64Decoder().convert(base64);
image = ExtendedImage.memory(
bytes,
width: width,
height: height,
fit: fit,
shape: BoxShape.rectangle,
borderRadius: borderRadius,
mode: mode,
gaplessPlayback: true,
enableSlideOutPage: enableSlideOutPage,
initGestureConfigHandler: initGestureConfig,
loadStateChanged: (state) => _buildLoadState(context, state),
);
}*/
break;
} }
return Container(
clipBehavior: Clip.hardEdge,
width: width,
height: height,
decoration: BoxDecoration(
color: backgroundColor ?? Theme.of(context).colorScheme.tertiary,
borderRadius: borderRadius,
),
child: IconTheme(
data: IconThemeData(
size: 24,
color: Theme.of(context).colorScheme.onTertiary,
),
child: image ?? const SizedBox.shrink(),
),
);
} }
Widget _buildLoadState(BuildContext context, ExtendedImageState state) { Widget _buildLoadState({
required BuildContext context,
required ExtendedImageState state,
required Widget placeholder,
required Widget error,
}) {
switch (state.extendedImageLoadState) { switch (state.extendedImageLoadState) {
case LoadState.loading: case LoadState.loading:
return Center( return Center(child: placeholder);
child: CustomLoadingIndicator(
size: 30.w,
strokeWidth: 3.w,
),
);
case LoadState.completed: case LoadState.completed:
Size? size; Size? size;
if (state.extendedImageInfo != null) { if (state.extendedImageInfo != null) {
...@@ -142,13 +254,7 @@ class CustomImage extends StatelessWidget { ...@@ -142,13 +254,7 @@ class CustomImage extends StatelessWidget {
final completed = state.completedWidget; final completed = state.completedWidget;
return builder?.call(context, provider, completed, size) ?? completed; return builder?.call(context, provider, completed, size) ?? completed;
case LoadState.failed: case LoadState.failed:
return Center( return Center(child: error);
child: Icon(
Icons.image_not_supported_outlined,
size: 24.w,
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7),
),
);
} }
} }
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论