contact us, no data screen ui added & improvements

development
Sikander Saleem 5 years ago
parent f369aa6108
commit ff8c972d12

@ -0,0 +1,21 @@
<svg viewBox="0 0 456 456" xmlns="http://www.w3.org/2000/svg">
<g data-name="Layer 2" id="Layer_2">
<g data-name="Layer 7" id="Layer_7">
<g data-name="1828, Block, Blocked, Website" id="_1828_Block_Blocked_Website">
<g>
<path style="fill: #ccc" d="M446.5,0H9.5A9.5,9.5,0,0,0,0,9.5v437A9.5,9.5,0,0,0,9.5,456h437a9.49,9.49,0,0,0,9.49-9.5V9.5A9.5,9.5,0,0,0,446.5,0ZM437,19V76H19V19ZM19,437V95H437V437Z"/>
<path style="fill: #ccc" d="M47.5,38h19V57h-19Z"/>
<path style="fill: #ccc" d="M380,38H408.5V57H380Z"/>
<path style="fill: #ccc" d="M294.5,313.5h-133a9.5,9.5,0,0,0,0,19h133a9.5,9.5,0,1,0,0-19Z"/>
<path style="fill: #ccc" d="M294.5,351.5h-133a9.5,9.5,0,0,0,0,19h133a9.5,9.5,0,1,0,0-19Z"/>
<path style="fill: #ccc" d="M294.5,389.5h-133a9.5,9.5,0,0,0,0,19h133a9.5,9.5,0,1,0,0-19Z"/>
<g>
<path style="fill: #ccc" d="M243.45,123.44a61.87,61.87,0,1,0,61.87,61.87A61.94,61.94,0,0,0,243.45,123.44Zm0,110a48.13,48.13,0,1,1,48.12-48.12A48.18,48.18,0,0,1,243.45,233.44Z"/>
<path style="fill: #ccc" d="M267.75,161a6.86,6.86,0,0,0-9.72,0l-14.58,14.58L228.87,161a6.88,6.88,0,0,0-9.73,9.72l14.59,14.59L219.14,199.9a6.88,6.88,0,0,0,9.73,9.72L243.45,195,258,209.62a6.87,6.87,0,0,0,9.72-9.72l-14.58-14.58,14.58-14.59a6.86,6.86,0,0,0,0-9.72Z"/>
<line style="fill: none;stroke: #ccc;stroke-linecap: round;stroke-miterlimit: 10;stroke-width: 15.79006290435791px" x1="202" x2="150.68" y1="223.5" y2="266.92"/>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

@ -6,6 +6,7 @@ import 'colors.dart';
class Utils { class Utils {
static bool _isLoadingVisible = false; static bool _isLoadingVisible = false;
static bool get isLoading => _isLoadingVisible;
static void showToast(String message) { static void showToast(String message) {
Fluttertoast.showToast( Fluttertoast.showToast(
msg: message, toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.BOTTOM, timeInSecForIosWeb: 1, backgroundColor: Colors.black54, textColor: Colors.white, fontSize: 16.0); msg: message, toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.BOTTOM, timeInSecForIosWeb: 1, backgroundColor: Colors.black54, textColor: Colors.white, fontSize: 16.0);

@ -2,6 +2,7 @@ import 'dart:io';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tangheem/ui/screens/contact_us_screen.dart';
import 'ui/common_appbar.dart'; import 'ui/common_appbar.dart';
import 'ui/screens/forgot_password_screen.dart'; import 'ui/screens/forgot_password_screen.dart';
import 'ui/screens/home_screen.dart'; import 'ui/screens/home_screen.dart';
@ -39,6 +40,9 @@ class Application extends StatelessWidget {
case HomeScreen.routeName: case HomeScreen.routeName:
className = CommonAppbar(showDrawer: true, child: HomeScreen()); className = CommonAppbar(showDrawer: true, child: HomeScreen());
break; break;
case ContactUsScreen.routeName:
className = CommonAppbar(child: ContactUsScreen());
break;
case TangheemScreen.routeName: case TangheemScreen.routeName:
Map<String, Object> data = settings.arguments; Map<String, Object> data = settings.arguments;
className = CommonAppbar( className = CommonAppbar(

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:tangheem/classes/colors.dart'; import 'package:tangheem/classes/colors.dart';
import 'package:tangheem/ui/screens/contact_us_screen.dart';
import 'package:tangheem/ui/screens/login_screen.dart'; import 'package:tangheem/ui/screens/login_screen.dart';
import 'package:tangheem/ui/screens/quran_screen.dart'; import 'package:tangheem/ui/screens/quran_screen.dart';
@ -217,7 +218,9 @@ class _CommonAppbarState extends State<CommonAppbar> {
await Navigator.pushNamed(context, QuranScreen.routeName, arguments: ""); await Navigator.pushNamed(context, QuranScreen.routeName, arguments: "");
}), }),
SizedBox(height: 2), SizedBox(height: 2),
myListItem("assets/icons/contact.svg", "الاتصال بنا", false), myListItem("assets/icons/contact.svg", "الاتصال بنا", false, onTap: () {
Navigator.pushNamed(context, ContactUsScreen.routeName, arguments: "");
}),
], ],
), ),
), ),

@ -0,0 +1,26 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:tangheem/classes/colors.dart';
class NoDataUI extends StatelessWidget {
NoDataUI({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.only(top: 100),
child: Column(
children: [
SvgPicture.asset("assets/icons/no_data.svg", width: 75, height: 75),
SizedBox(height: 8),
Text(
"آسف! لا تتوافر بيانات",
style: TextStyle(fontSize: 16, color: ColorConsts.primaryBlue.withOpacity(0.7), fontWeight: FontWeight.w600),
),
SizedBox(height: 16),
],
),
);
}
}

@ -0,0 +1,154 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:tangheem/api/tangheem_user_api_client.dart';
import 'package:tangheem/classes/colors.dart';
import 'package:tangheem/classes/utils.dart';
import 'package:tangheem/extensions/email_validator.dart';
import 'package:tangheem/widgets/common_textfield_widget.dart';
class ContactUsScreen extends StatefulWidget {
static const String routeName = "/contact_us";
ContactUsScreen({Key key}) : super(key: key);
@override
_ContactUsScreenState createState() {
return _ContactUsScreenState();
}
}
class _ContactUsScreenState extends State<ContactUsScreen> {
TextEditingController _firstNameController = TextEditingController();
TextEditingController _lastNameController = TextEditingController();
TextEditingController _emailController = TextEditingController();
TextEditingController _mobileNumberController = TextEditingController();
TextEditingController _descriptionController = TextEditingController();
@override
void initState() {
super.initState();
}
void sendFeedback(String _firstName, String _lastName, String _email, String _phone, String _description) async {
Utils.showLoading(context);
try {
await TangheemUserApiClient().contactUs(_firstName, _lastName, _email, _phone, _description);
Utils.showToast("شكرا لك على مراسلتنا ، نحن نقدر كلماتك.");
Utils.hideLoading(context);
Navigator.pop(context);
} catch (ex, tr) {
Utils.handleException(ex, null);
Utils.hideLoading(context);
}
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: ColorConsts.secondaryWhite,
body: SingleChildScrollView(
padding: EdgeInsets.all(32.0),
physics: BouncingScrollPhysics(),
child: Container(
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(borderRadius: BorderRadius.circular(8.0), color: Colors.white),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: EdgeInsets.only(top: 24, bottom: 24),
child: SvgPicture.asset("assets/logos/tangheem_logo.svg", width: 100, height: 100),
),
Text(
"اتصل بنا",
style: TextStyle(fontSize: 22, color: ColorConsts.primaryBlue),
),
Padding(
padding: EdgeInsets.all(8),
child: Text(
"لا تتردد في الاتصال بنا ، يسعدنا أن نسمع منك",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 14, color: ColorConsts.primaryBlue, height: 1),
),
),
Container(
margin: EdgeInsets.only(top: 16),
width: double.infinity,
padding: EdgeInsets.all(32.0),
decoration: BoxDecoration(
color: ColorConsts.primaryBlue,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(8),
bottomRight: Radius.circular(8),
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
CommonTextFieldWidget(hint: "الاسم الاول", controller: _firstNameController),
SizedBox(height: 8),
CommonTextFieldWidget(hint: "اسم النهاية", controller: _lastNameController),
SizedBox(height: 8),
CommonTextFieldWidget(hint: "الايميل", controller: _emailController),
SizedBox(height: 8),
CommonTextFieldWidget(hint: " رقم الجوال${" (" + ("9xx") + " xxxxxxxxx)"}", controller: _mobileNumberController),
SizedBox(height: 8),
CommonTextFieldWidget(hint: "اكتب لنا", controller: _descriptionController, maxLines: 4),
SizedBox(height: 12),
SizedBox(
width: double.infinity,
height: 50,
child: TextButton(
onPressed: () {
if (_firstNameController.text.length < 1) {
Utils.showToast("الاسم الأول فارغ");
return;
}
if (_lastNameController.text.length < 1) {
Utils.showToast("الاسم الأخير فارغ");
return;
}
if (_emailController.text.length < 1) {
Utils.showToast("البريد الإلكتروني فارغ");
return;
}
if (_mobileNumberController.text.length < 1) {
Utils.showToast("رقم الهاتف فارغ");
return;
}
if (_descriptionController.text.length < 1) {
Utils.showToast("يجب أن تكتب لنا كلمات قليلة");
return;
}
if (!_emailController.text.isValidEmail()) {
Utils.showToast("بريد إلكتروني خاطئ");
return;
}
sendFeedback(_firstNameController.text, _lastNameController.text, _emailController.text, _mobileNumberController.text, _descriptionController.text);
},
style: TextButton.styleFrom(
primary: Colors.white,
backgroundColor: ColorConsts.secondaryPink,
textStyle: TextStyle(fontSize: 16, fontFamily: "DroidKufi"),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6.0),
),
),
child: Text("ارسل رأيك"),
),
),
],
),
),
],
),
),
),
);
}
}

@ -30,8 +30,8 @@ class _HomeScreenState extends State<HomeScreen> {
List<String> _surahList = []; List<String> _surahList = [];
List<String> _tangheemList = []; List<String> _tangheemList = [];
int _selectedSurah = 0; int _selectedSurah = -1;
int _selectedTangheemType = 0; int _selectedTangheemType = -1;
SurahModel _surahModel; SurahModel _surahModel;
TangheemType _tangheemType; TangheemType _tangheemType;
@ -92,7 +92,7 @@ class _HomeScreenState extends State<HomeScreen> {
Row( Row(
children: [ children: [
Expanded( Expanded(
child: CommonDropDownButton(_selectedTangheemType, list: _tangheemList, onSelect: (index) { child: CommonDropDownButton(_selectedTangheemType, hintText: "الأسلوب اللغوي", list: _tangheemList, onSelect: (index) {
if (_selectedTangheemType != index) { if (_selectedTangheemType != index) {
setState(() { setState(() {
_selectedTangheemType = index; _selectedTangheemType = index;
@ -102,7 +102,7 @@ class _HomeScreenState extends State<HomeScreen> {
), ),
SizedBox(width: 8), SizedBox(width: 8),
Expanded( Expanded(
child: CommonDropDownButton(_selectedSurah, list: _surahList, onSelect: (index) { child: CommonDropDownButton(_selectedSurah, hintText: "السورة", list: _surahList, onSelect: (index) {
if (_selectedSurah != index) { if (_selectedSurah != index) {
setState(() { setState(() {
_selectedSurah = index; _selectedSurah = index;
@ -117,6 +117,14 @@ class _HomeScreenState extends State<HomeScreen> {
splashColor: Colors.transparent, splashColor: Colors.transparent,
highlightColor: Colors.transparent, highlightColor: Colors.transparent,
onTap: () async { onTap: () async {
if (_selectedTangheemType < 0) {
Utils.showToast("الرجاء اختيار نوع تنغيم");
return;
}
if (_selectedSurah < 0) {
Utils.showToast("الرجاء اختيار السورة");
return;
}
_searchFocusNode.unfocus(); _searchFocusNode.unfocus();
_searchFocusNode.canRequestFocus = false; _searchFocusNode.canRequestFocus = false;
var data = {"tangheemTypeName": _tangheemList[_selectedTangheemType], "surahData": _surahModel.data[_selectedSurah]}; var data = {"tangheemTypeName": _tangheemList[_selectedTangheemType], "surahData": _surahModel.data[_selectedSurah]};

@ -219,32 +219,43 @@ class _QuranScreenState extends State<QuranScreen> {
shrinkWrap: true, shrinkWrap: true,
padding: EdgeInsets.only(top: 16, bottom: 8), padding: EdgeInsets.only(top: 16, bottom: 8),
children: [ children: [
Text( // Text(
"بسم الله الرحمن الرحيم", // "بسم الله الرحمن الرحيم",
textAlign: TextAlign.center, // textAlign: TextAlign.center,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20, color: ColorConsts.primaryBlue, height: 1), // style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20, color: ColorConsts.primaryBlue, height: 1),
), // ),
SizedBox(height: 8), // SizedBox(height: 8),
Container( Container(
padding: EdgeInsets.only(left: 4, right: 4), padding: EdgeInsets.only(left: 4, right: 4),
child: TextHighLightWidget( child: Text(
text: _surahAya, _surahAya,
valueColor: ColorConsts.primaryBlue, textAlign: TextAlign.center,
highlights: _tangheemWords,
onTap: (value) {
List<AyatTangheemTypeMappedData> _ayatList = _ayatTangheemTypeMapped.data?.where((element) => element.highlightText == value)?.toList() ?? [];
if (_ayatList.length > 1) {
_selectTangheemType(_ayatList);
} else {
Navigator.pushNamed(context, TangheemDetailScreen.routeName, arguments: _ayatList.first);
}
},
style: TextStyle( style: TextStyle(
fontFamily: "UthmanicHafs", fontFamily: "UthmanicHafs",
fontSize: 18, fontSize: 18,
color: ColorConsts.primaryBlue,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
// todo "sikander" : lines commented for future
// TextHighLightWidget(
// text: _surahAya,
// valueColor: ColorConsts.primaryBlue,
// highlights: _tangheemWords,
// onTap: (value) {
// List<AyatTangheemTypeMappedData> _ayatList = _ayatTangheemTypeMapped.data?.where((element) => element.highlightText == value)?.toList() ?? [];
// if (_ayatList.length > 1) {
// _selectTangheemType(_ayatList);
// } else {
// Navigator.pushNamed(context, TangheemDetailScreen.routeName, arguments: _ayatList.first);
// }
// },
// style: TextStyle(
// fontFamily: "UthmanicHafs",
// fontSize: 18,
// fontWeight: FontWeight.bold,
// ),
// ),
), ),
], ],
), ),

@ -52,9 +52,9 @@ class _TangheemDetailScreenState extends State<TangheemDetailScreen> {
void filterData() { void filterData() {
_ayatTangheemTypeMappedData = widget.ayatTangheemTypeMappedData; _ayatTangheemTypeMappedData = widget.ayatTangheemTypeMappedData;
_tangheemWords.add(_ayatTangheemTypeMappedData.highlightText ?? ""); _tangheemWords.add(_ayatTangheemTypeMappedData.highlightText ?? "");
_tangheemInsideTableTrueList = _ayatTangheemTypeMappedData?.property?.where((element) => element.isInsideTable)?.toList() ?? []; _tangheemInsideTableTrueList = _ayatTangheemTypeMappedData?.property?.where((element) => (element.isInsideTable) && (element.propertyValue ?? "").isNotEmpty)?.toList() ?? [];
_tangheemInsideTableValueList = _ayatTangheemTypeMappedData?.property?.where((element) => (!element.isInsideTable) && (element.propertyValue ?? "").isNotEmpty)?.toList() ?? []; _tangheemInsideTableValueList = _ayatTangheemTypeMappedData?.property?.where((element) => (!element.isInsideTable) && (element.propertyValue ?? "").isNotEmpty)?.toList() ?? [];
_tangheemInsideTableEmptyList = _ayatTangheemTypeMappedData?.property?.where((element) => (!element.isInsideTable) && (element.propertyValue ?? "").isEmpty)?.toList() ?? []; // _tangheemInsideTableEmptyList = _ayatTangheemTypeMappedData?.property?.where((element) => (!element.isInsideTable) && (element.propertyValue ?? "").isEmpty)?.toList() ?? [];
} }
@override @override

@ -5,6 +5,7 @@ import 'package:tangheem/classes/colors.dart';
import 'package:tangheem/classes/utils.dart'; import 'package:tangheem/classes/utils.dart';
import 'package:tangheem/models/aya_tangheem_type_mapped.dart'; import 'package:tangheem/models/aya_tangheem_type_mapped.dart';
import 'package:tangheem/models/surah_model.dart'; import 'package:tangheem/models/surah_model.dart';
import 'package:tangheem/ui/misc/no_data_ui.dart';
import 'package:tangheem/ui/screens/tangheem_detail_screen.dart'; import 'package:tangheem/ui/screens/tangheem_detail_screen.dart';
import 'package:tangheem/widgets/text_highlight_widget.dart'; import 'package:tangheem/widgets/text_highlight_widget.dart';
@ -33,7 +34,9 @@ class _TangheemScreenState extends State<TangheemScreen> {
Utils.showLoading(context); Utils.showLoading(context);
try { try {
_ayatTangheemTypeMapped = await TangheemUserApiClient().getAyaTangheemTypeMapped(widget.surah.surahID, widget.tangheemTypeName); _ayatTangheemTypeMapped = await TangheemUserApiClient().getAyaTangheemTypeMapped(widget.surah.surahID, widget.tangheemTypeName);
_dataList = _ayatTangheemTypeMapped?.data ?? [];
} catch (ex, tr) { } catch (ex, tr) {
_dataList = [];
Utils.handleException(ex, null); Utils.handleException(ex, null);
} finally { } finally {
Utils.hideLoading(context); Utils.hideLoading(context);
@ -46,11 +49,14 @@ class _TangheemScreenState extends State<TangheemScreen> {
super.dispose(); super.dispose();
} }
List<AyatTangheemTypeMappedData> _dataList;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var _dataList = _ayatTangheemTypeMapped?.data ?? []; return _dataList == null
return _dataList.isEmpty
? SizedBox() ? SizedBox()
: _dataList.isEmpty
? NoDataUI()
: ListView.separated( : ListView.separated(
physics: BouncingScrollPhysics(), physics: BouncingScrollPhysics(),
padding: EdgeInsets.all(16), padding: EdgeInsets.all(16),

@ -128,7 +128,7 @@ class _AyaPlayerWidgetState extends State<AyaPlayerWidget> {
builder: (context, snapshot) { builder: (context, snapshot) {
final state = snapshot.data; final state = snapshot.data;
return Text( return Text(
state == null ? "" : widget.voiceNoteList?.elementAt(state)?.userName ?? "", (state == null || widget.voiceNoteList.isEmpty) ? "" : widget.voiceNoteList?.elementAt(state)?.userName ?? "",
style: TextStyle(fontSize: 10, color: ColorConsts.textGrey1, height: 1), style: TextStyle(fontSize: 10, color: ColorConsts.textGrey1, height: 1),
); );
}, },
@ -151,10 +151,10 @@ class _AyaPlayerWidgetState extends State<AyaPlayerWidget> {
_shareAya(); _shareAya();
}), }),
commonIconButton("assets/icons/bookmark.svg", () {}), commonIconButton("assets/icons/bookmark.svg", () {}),
commonIconButton("assets/icons/audio_level.svg", () async { // commonIconButton("assets/icons/audio_level.svg", () async {
// var vol = await VolumeController.getVolume(); // // var vol = await VolumeController.getVolume();
VolumeController.maxVolume(); // VolumeController.maxVolume();
}), // }),
], ],
), ),
SizedBox(height: 8), SizedBox(height: 8),

@ -4,7 +4,7 @@ import 'package:tangheem/classes/colors.dart';
class CommonDropDownButton extends StatelessWidget { class CommonDropDownButton extends StatelessWidget {
final int index; final int index;
final String text; final String hintText;
final String icon; final String icon;
final Color iconColor; final Color iconColor;
final Color color; final Color color;
@ -14,7 +14,7 @@ class CommonDropDownButton extends StatelessWidget {
final double widthHeight; final double widthHeight;
final List<String> list; final List<String> list;
CommonDropDownButton(this.index, {Key key, this.onPressed, this.isDropDown = true, this.text = "", this.color, this.icon, this.widthHeight, this.iconColor, this.onSelect, this.list}) CommonDropDownButton(this.index, {Key key, this.onPressed, this.isDropDown = true, this.hintText = "", this.color, this.icon, this.widthHeight, this.iconColor, this.onSelect, this.list})
: super(key: key); : super(key: key);
@override @override
@ -41,7 +41,7 @@ class CommonDropDownButton extends StatelessWidget {
color: iconColor ?? ColorConsts.secondaryOrange, color: iconColor ?? ColorConsts.secondaryOrange,
), ),
hint: Text( hint: Text(
list.isNotEmpty ? list[index] : text, (list.isEmpty || index < 0) ? hintText : list[index],
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 12, color: Colors.white), style: TextStyle(fontSize: 12, color: Colors.white),

@ -10,13 +10,14 @@ class CommonTextFieldWidget extends StatelessWidget {
final String prefixIcon; final String prefixIcon;
final Widget suffixWidget; final Widget suffixWidget;
final Function onTap; final Function onTap;
final int maxLines;
CommonTextFieldWidget({Key key, @required this.hint, @required this.controller, this.isPassword = false, this.prefixIcon, this.suffixWidget, this.onTap}) : super(key: key); CommonTextFieldWidget({Key key, @required this.hint, @required this.controller, this.maxLines = 1, this.isPassword = false, this.prefixIcon, this.suffixWidget, this.onTap}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SizedBox( return SizedBox(
height: 50, // height: 50,
child: TextField( child: TextField(
textAlignVertical: TextAlignVertical.center, textAlignVertical: TextAlignVertical.center,
controller: controller, controller: controller,
@ -25,7 +26,9 @@ class CommonTextFieldWidget extends StatelessWidget {
style: TextStyle(color: ColorConsts.primaryBlack, fontSize: 14), style: TextStyle(color: ColorConsts.primaryBlack, fontSize: 14),
cursorColor: ColorConsts.primaryBlue, cursorColor: ColorConsts.primaryBlue,
readOnly: onTap != null, readOnly: onTap != null,
maxLines: maxLines,
onTap: onTap, onTap: onTap,
scrollPhysics: BouncingScrollPhysics(),
decoration: InputDecoration( decoration: InputDecoration(
contentPadding: EdgeInsets.fromLTRB(4, 4, 8, 4), contentPadding: EdgeInsets.fromLTRB(4, 4, 8, 4),
alignLabelWithHint: true, alignLabelWithHint: true,

Loading…
Cancel
Save