Browse Source

Merge branch 'master' into dev

null_safety
w-R 3 years ago
parent
commit
50cd1afe15
  1. BIN
      android/app/libs/BaiduLBS_Android.jar
  2. BIN
      assets/image/2x/brand_store_bg.png
  3. BIN
      assets/image/2x/brand_store_cj.png
  4. BIN
      assets/image/2x/brand_store_hx.png
  5. BIN
      assets/image/2x/ic_splash_bg.png
  6. BIN
      assets/image/3x/brand_store_bg.png
  7. BIN
      assets/image/3x/brand_store_cj.png
  8. BIN
      assets/image/3x/brand_store_hx.png
  9. BIN
      assets/image/3x/ic_splash_bg.png
  10. BIN
      assets/image/brand_store_bg.png
  11. BIN
      assets/image/brand_store_cj.png
  12. BIN
      assets/image/brand_store_hx.png
  13. BIN
      assets/image/ic_splash_bg.png
  14. 3
      ios/Runner.xcodeproj/project.pbxproj
  15. 14
      ios/Runner/Base.lproj/LaunchScreen.storyboard
  16. 1
      ios/Runner/Info.plist
  17. 12
      lib/home/home_page.dart
  18. 2
      lib/home/points_mall_page.dart
  19. 22
      lib/integral/integral_page.dart
  20. 425
      lib/login/login_page.dart
  21. 2
      lib/mine/mine_vip_level_page.dart
  22. 12
      lib/setting/setting_page.dart
  23. 11
      lib/union/store_details_page.dart
  24. 9
      lib/union/union_details_page.dart

BIN
android/app/libs/BaiduLBS_Android.jar

Binary file not shown.

BIN
assets/image/2x/brand_store_bg.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

BIN
assets/image/2x/brand_store_cj.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

BIN
assets/image/2x/brand_store_hx.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

BIN
assets/image/2x/ic_splash_bg.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

BIN
assets/image/3x/brand_store_bg.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

BIN
assets/image/3x/brand_store_cj.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 KiB

BIN
assets/image/3x/brand_store_hx.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 KiB

BIN
assets/image/3x/ic_splash_bg.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

BIN
assets/image/brand_store_bg.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

BIN
assets/image/brand_store_cj.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

BIN
assets/image/brand_store_hx.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

BIN
assets/image/ic_splash_bg.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

3
ios/Runner.xcodeproj/project.pbxproj

@ -872,6 +872,7 @@
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = "";
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
@ -1098,6 +1099,7 @@
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = "";
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
@ -1217,6 +1219,7 @@
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = "";
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;

14
ios/Runner/Base.lproj/LaunchScreen.storyboard

@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
@ -14,9 +16,11 @@
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
<rect key="frame" x="19.5" y="73" width="375" height="750"/>
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@ -28,10 +32,10 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
<point key="canvasLocation" x="76.811594202898561" y="251.11607142857142"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
<image name="LaunchImage" width="375" height="750"/>
</resources>
</document>

1
ios/Runner/Info.plist

@ -151,6 +151,5 @@
<string>https://hx.lotus-wallet.com/app/</string>
<key>io.flutter.embedded_views_preview</key>
<string>YES</string>
</dict>
</plist>

12
lib/home/home_page.dart

@ -181,7 +181,7 @@ class _HomePage extends State<HomePage> with AutomaticKeepAliveClientMixin {
moreText: S.of(context).renwuzhongxin,
onTap: () {
SharedPreferences.getInstance().then((value) {
if (value.getString('token') == null) {
if (value.getString('token') == null || value.getString('token') == "") {
loginTips();
} else {
Navigator.of(context).pushNamed('/router/integral_page');
@ -192,7 +192,7 @@ class _HomePage extends State<HomePage> with AutomaticKeepAliveClientMixin {
InkWell(
onTap: () {
SharedPreferences.getInstance().then((value) {
if (value.getString('token') == null) {
if (value.getString('token') == null || value.getString('token') == "") {
loginTips();
} else {
Navigator.of(context).pushNamed('/router/integral_page');
@ -213,10 +213,10 @@ class _HomePage extends State<HomePage> with AutomaticKeepAliveClientMixin {
},
),
hotList(),
// ItemTitle(
// text: S.of(context).chuangshirendegushi1,
// imgPath: "assets/image/icon_founder.png",
// ),
ItemTitle(
text: S.of(context).chuangshirendegushi1,
imgPath: "assets/image/icon_founder.png",
),
GestureDetector(
onTap: () {
Navigator.of(context).pushNamed('/router/founder_story_page');

2
lib/home/points_mall_page.dart

@ -292,7 +292,7 @@ class _PointsMallPage extends State<PointsMallPage>
arguments: {"goodsId": goods[index].id});
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
String token = sharedPreferences.getString("token");
if (token != null) queryUser();
if (token != null && token != "") queryUser();
}
_sortChange(item) {

22
lib/integral/integral_page.dart

@ -322,7 +322,7 @@ class _IntegralPage extends State<IntegralPage> {
style: TextStyle(
color: Color(0xFF353535),
fontSize: 14.sp,
fontWeight: FontWeight.w500),
fontWeight: FontWeight.w500,),
),
SizedBox(
height: 10.h,
@ -442,7 +442,7 @@ class _IntegralPage extends State<IntegralPage> {
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16.sp,
color: Color(0xFF353535)),
color: Color(0xFF353535),),
),
SizedBox(
height: 10.h,
@ -465,7 +465,7 @@ class _IntegralPage extends State<IntegralPage> {
mainAxisSpacing: 8.h,
crossAxisSpacing: 18.w,
padding: EdgeInsets.only(bottom: 32.h),
physics: new NeverScrollableScrollPhysics(),
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, position) {
return signInItem(position);
},
@ -557,13 +557,19 @@ class _IntegralPage extends State<IntegralPage> {
flex: 1,
child: InkWell(
onTap: () {
Navigator.of(context)
.pushNamed('/router/mine_vip_level_page', arguments: {
"rankLevel": rankLevel,
"createTime":
SharedPreferences.getInstance().then((value) {
if (value.getString("token") != null && value.getString("token") != "") {
Navigator.of(context)
.pushNamed('/router/mine_vip_level_page', arguments: {
"rankLevel": rankLevel,
"createTime":
(userinfo != null) ? "${userinfo.createTime}" : "",
"points":
"points":
(userinfo != null) ? int.tryParse(userinfo.points) : 0,
});
} else {
}
});
},
child: Column(

425
lib/login/login_page.dart

@ -289,7 +289,8 @@ class _MyLoginPageState extends State<LoginPage> with TickerProviderStateMixin {
xgFlutterPlugin.bindWithIdentifier(
identify: mobile, bindType: XGBindType.account);
Navigator.of(context).pushNamedAndRemoveUntil('/router/main_page', (route) => false);
Navigator.of(context)
.pushNamedAndRemoveUntil('/router/main_page', (route) => false);
} else {
SmartDialog.showToast("${value.msg}", alignment: Alignment.center);
}
@ -365,11 +366,10 @@ class _MyLoginPageState extends State<LoginPage> with TickerProviderStateMixin {
return AnimatedCrossFade(
firstChild: Container(
color: Colors.white,
child: Platform.isAndroid
? Container()
: Container(
// child: Image.asset("name"),
),
child: Image.asset(
"assets/image/ic_splash_bg.png",
fit: BoxFit.fill,
),
),
layoutBuilder: (widgetFirst, keyFirst, widgetSecond, keySecond) {
return Stack(
@ -394,246 +394,245 @@ class _MyLoginPageState extends State<LoginPage> with TickerProviderStateMixin {
],
);
},
secondChild: Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: Colors.white,
body: GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
child: Stack(
children: [
Container(
height: MediaQuery.of(context).size.height * 0.78,
child: Stack(
alignment: Alignment.center,
children: [
PhotoView(
imageProvider: AssetImage("assets/image/laoban.png"),
initialScale: Platform.isAndroid ? 1.02 : 1.2,
basePosition: alignmentProgress,
),
Positioned(
top: 54.h,
left: 28.w,
child: Image.asset(
"assets/image/icon_founder_text.png",
width: 20.w,
height: 200.h,
),
secondChild: uiPage(),
firstCurve: Curves.easeInQuart,
secondCurve: Curves.easeInQuart,
crossFadeState: isShowLogin ? CrossFadeState.showSecond : CrossFadeState.showFirst,
duration: Duration(milliseconds: Platform.isIOS ? 1000 : 1000),
);
}
Widget uiPage() {
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: Colors.white,
body: GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
child: Stack(
children: [
Container(
height: MediaQuery.of(context).size.height * 0.78,
child: Stack(
alignment: Alignment.center,
children: [
PhotoView(
imageProvider: AssetImage("assets/image/laoban.png"),
initialScale: Platform.isAndroid ? 1.02 : 1.15,
basePosition: alignmentProgress,
),
Positioned(
top: 54.h,
left: 28.w,
child: Image.asset(
"assets/image/icon_founder_text.png",
width: 20.w,
height: 200.h,
),
Container(
decoration: BoxDecoration(
color: Color(0xFF32A060).withAlpha(changeAlpha),
),
),
Container(
decoration: BoxDecoration(
color: Color(0xFF32A060).withAlpha(changeAlpha),
),
Container(
height: MediaQuery.of(context).size.height * 0.78,
margin: EdgeInsets.only(top: 56.h),
alignment: Alignment.topCenter,
child: AspectRatio(
aspectRatio: 1.1,
child: Opacity(
opacity: (changeAlpha) / 255,
child: Container(
child: Image.asset(
"assets/image/icon_login_hide_bg.png",
fit: BoxFit.cover,
),
),
Container(
height: MediaQuery.of(context).size.height * 0.78,
margin: EdgeInsets.only(top: 56.h),
alignment: Alignment.topCenter,
child: AspectRatio(
aspectRatio: 1.1,
child: Opacity(
opacity: (changeAlpha) / 255,
child: Container(
child: Image.asset(
"assets/image/icon_login_hide_bg.png",
fit: BoxFit.cover,
),
),
),
),
Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.asset(
"assets/image/icon_login_logo.png",
width: 91.w,
height: 91.h,
),
SizedBox(
height: 0.596.sh,
),
],
),
],
),
),
SingleChildScrollView(
controller: scrollController,
physics: PageScrollPhysics().applyTo(ClampingScrollPhysics()),
child: SizedBox(
height: MediaQuery.of(context).size.height * 1.47,
child: Column(
),
Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.asset(
"assets/image/icon_login_logo.png",
width: 91.w,
height: 91.h,
),
SizedBox(
height: MediaQuery.of(context).size.height * 0.6244,
height: 0.596.sh,
),
Expanded(
child: Container(
key: loginKey,
child: Stack(
children: [
Positioned(
child: Container(
child: Image.asset(
"assets/image/icon_login_bg_webp.webp",
width: MediaQuery.of(context).size.width,
fit: BoxFit.cover,
),
],
),
],
),
),
SingleChildScrollView(
controller: scrollController,
physics: PageScrollPhysics().applyTo(ClampingScrollPhysics()),
child: SizedBox(
height: MediaQuery.of(context).size.height * 1.47,
child: Column(
children: [
SizedBox(
height: MediaQuery.of(context).size.height * 0.6244,
),
Expanded(
child: Container(
key: loginKey,
child: Stack(
children: [
Positioned(
child: Container(
child: Image.asset(
"assets/image/icon_login_bg_webp.webp",
width: MediaQuery.of(context).size.width,
fit: BoxFit.cover,
),
left: 0,
right: 0,
top: 0,
),
Positioned(
top:
MediaQuery.of(context).size.height * 0.1039,
bottom: 0,
child: Container(
padding:
EdgeInsets.symmetric(horizontal: 40.w),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Opacity(
opacity: (255 - changeAlpha) / 255,
child: Text(
"Hello,",
style: TextStyle(
fontSize: 23.sp,
color: Color(0xFF32A060),
),
left: 0,
right: 0,
top: 0,
),
Positioned(
top: MediaQuery.of(context).size.height * 0.1039,
bottom: 0,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 40.w),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Opacity(
opacity: (255 - changeAlpha) / 255,
child: Text(
"Hello,",
style: TextStyle(
fontSize: 23.sp,
color: Color(0xFF32A060),
),
),
SizedBox(
height: 8,
),
Opacity(
opacity: (255 - changeAlpha) / 255,
child: Text(
S.of(context).login_splash,
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.w400,
color: Color(0xFF32A060),
),
),
SizedBox(
height: 8,
),
Opacity(
opacity: (255 - changeAlpha) / 255,
child: Text(
S.of(context).login_splash,
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.w400,
color: Color(0xFF32A060),
),
),
SizedBox(
height: 20.h,
),
Expanded(
child: inputWidgets(),
flex: 1,
),
],
),
),
SizedBox(
height: 20.h,
),
Expanded(
child: inputWidgets(),
flex: 1,
),
],
),
)
],
),
),
)
],
),
),
],
),
),
],
),
),
Positioned(
child: InkWell(
onTap: _login,
child: Container(
alignment: Alignment.center,
padding: EdgeInsets.all(10.h),
decoration: BoxDecoration(
color: Color(0xFF32A060),
borderRadius: BorderRadius.circular(2),
),
child: Text(
S.of(context).login,
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.w400,
color: Colors.white),
),
),
Positioned(
child: InkWell(
onTap: _login,
child: Container(
alignment: Alignment.center,
padding: EdgeInsets.all(10.h),
decoration: BoxDecoration(
color: Color(0xFF32A060),
borderRadius: BorderRadius.circular(2),
),
child: Text(
S.of(context).login,
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.w400,
color: Colors.white),
),
),
bottom: 140.h -
(50.h -
(offsetBtn > 50.h
? 50.h
: offsetBtn < 0
? 0
: offsetBtn)),
left: 40.w,
right: 40.w,
),
Positioned(
child: InkWell(
onTap: () {
print("11111");
if (widget.arguments != null) {
Navigator.of(context).pop();
} else {
Navigator.of(context)
.popAndPushNamed('/router/main_page');
}
},
child: Visibility(
visible: (changeAlpha / 255) > 0,
child: Opacity(
opacity: changeAlpha / 255,
child: BorderText(
padding: EdgeInsets.all(9.h),
text: S.of(context).youkedenglu,
fontSize: 18.sp,
textColor: Color(0xFF32A060),
borderColor: Color(0xFF32A060),
borderWidth: 1.w,
radius: 2,
),
bottom: 140.h -
(50.h -
(offsetBtn > 50.h
? 50.h
: offsetBtn < 0
? 0
: offsetBtn)),
left: 40.w,
right: 40.w,
),
Positioned(
child: InkWell(
onTap: () {
print("11111");
if (widget.arguments != null) {
Navigator.of(context).pop();
} else {
Navigator.of(context).popAndPushNamed('/router/main_page');
}
},
child: Visibility(
visible: (changeAlpha / 255) > 0,
child: Opacity(
opacity: changeAlpha / 255,
child: BorderText(
padding: EdgeInsets.all(9.h),
text: S.of(context).youkedenglu,
fontSize: 18.sp,
textColor: Color(0xFF32A060),
borderColor: Color(0xFF32A060),
borderWidth: 1.w,
radius: 2,
),
),
),
bottom: 88.h,
left: 40.w,
right: 40.w,
),
Positioned(
child: InkWell(
onTap: scrollToTop,
child: Container(
alignment: Alignment.center,
child: Opacity(
opacity: (255 - changeAlpha) / 255,
child: RotatedBox(
quarterTurns: 3,
child: Icon(
Icons.keyboard_arrow_right,
size: 44,
color: Color(0xFF32A060),
),
bottom: 88.h,
left: 40.w,
right: 40.w,
),
Positioned(
child: InkWell(
onTap: scrollToTop,
child: Container(
alignment: Alignment.center,
child: Opacity(
opacity: (255 - changeAlpha) / 255,
child: RotatedBox(
quarterTurns: 3,
child: Icon(
Icons.keyboard_arrow_right,
size: 44,
color: Color(0xFF32A060),
),
),
),
),
bottom: 33.h,
left: 0,
right: 0,
)
],
),
),
bottom: 33.h,
left: 0,
right: 0,
)
],
),
),
firstCurve: Curves.easeInOut,
secondCurve: Curves.easeInOut,
crossFadeState:
isShowLogin ? CrossFadeState.showSecond : CrossFadeState.showFirst,
duration: Duration(milliseconds: 1200),
);
}

2
lib/mine/mine_vip_level_page.dart

@ -70,7 +70,7 @@ class _MineVipLevelPage extends State<MineVipLevelPage> {
child: Column(
children: [
AspectRatio(
aspectRatio: 1.8,
aspectRatio: 1.7,
child: Swiper(
viewportFraction: 0.95,
loop: false,

12
lib/setting/setting_page.dart

@ -236,14 +236,10 @@ class _SettingPage extends State<SettingPage> {
sharedPreferences.setString("mobile", "");
sharedPreferences.setString("nick", "");
Navigator.pushAndRemoveUntil(context, new MaterialPageRoute(
builder: (BuildContext context) {
if (xgFlutterPlugin != null) {
xgFlutterPlugin.stopXg();
}
return LoginPage();
},
), (route) => route == null);
Navigator.of(context).pushNamedAndRemoveUntil('/router/login_page', (route) => false);
if (xgFlutterPlugin != null) {
xgFlutterPlugin.stopXg();
}
}
Widget settingItem(left, right) {

11
lib/union/store_details_page.dart

@ -187,9 +187,14 @@ class _StoreDetailsPage extends State<StoreDetailsPage> {
),
onTap: () {
if (activity != null) {
Navigator.of(context).pushNamed(
'/router/union_detail_page',
arguments: {"id": activity.storeId});
if (widget.arguments["source"] != null
&& widget.arguments["source"] == activity.storeId) {
Navigator.of(context).pop();
} else {
Navigator.of(context).pushNamed(
'/router/union_detail_page',
arguments: {"id": activity.storeId, "source": widget.arguments["activityId"]});
}
}
},
),

9
lib/union/union_details_page.dart

@ -743,8 +743,13 @@ class _UnionDetailsPage extends State<UnionDetailsPage> {
itemBuilder: (context, position) {
return InkWell(
onTap: () {
Navigator.of(context).pushNamed('/router/store_detail_page',
arguments: {"activityId": activitys[position].id});
if (widget.arguments["source"] != null
&& widget.arguments["source"] == activitys[position].id) {
Navigator.of(context).pop();
} else {
Navigator.of(context).pushNamed('/router/store_detail_page',
arguments: {"activityId": activitys[position].id, "source": widget.arguments["id"]});
}
},
child: Container(
margin: EdgeInsets.symmetric(horizontal: 5.w),

Loading…
Cancel
Save