This commit is contained in:
Sai Naw Wun
2020-10-07 02:33:06 +06:30
parent 01a2798a74
commit 65dda16fe6
475 changed files with 1543 additions and 90780 deletions

View File

@@ -0,0 +1,139 @@
import 'package:fcs/domain/entities/faq.dart';
import 'package:fcs/helpers/theme.dart';
import 'package:fcs/pages/faq/faq_edit_page.dart';
import 'package:fcs/pages/faq/model/faq_model.dart';
import 'package:fcs/pages/main/model/language_model.dart';
import 'package:fcs/pages/main/model/main_model.dart';
import 'package:fcs/pages/main/util.dart';
import 'package:fcs/pages/widgets/local_text.dart';
import 'package:fcs/pages/widgets/progress.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class FAQDetailPage extends StatefulWidget {
final FAQ faq;
const FAQDetailPage({this.faq});
@override
_FAQDetailPageState createState() => _FAQDetailPageState();
}
class _FAQDetailPageState extends State<FAQDetailPage> {
bool _isLoading = false;
FAQ faq;
intState() {
super.initState();
}
@override
Widget build(BuildContext context) {
faq = context.select((FAQModel m) => m.getFAQ(widget.faq.id));
if (faq == null) return Text("Deleted");
bool isEditable = context.select((MainModel m) => m.faqEditable());
return LocalProgress(
inAsyncCall: _isLoading,
child: Scaffold(
body: CustomScrollView(slivers: [
SliverAppBar(
leading: IconButton(
icon: Icon(
CupertinoIcons.back,
color: primaryColor,
size: 50,
),
onPressed: () => Navigator.of(context).pop(),
),
backgroundColor: Colors.white,
expandedHeight: 100.0,
floating: false,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
titlePadding: EdgeInsets.symmetric(vertical: 10),
),
actions: isEditable
? [
IconButton(
onPressed: () {
showConfirmDialog(context, "faq.edit.delete.confirm",
() {
_delete();
});
},
icon: Icon(
CupertinoIcons.delete,
color: primaryColor,
size: 30,
)),
IconButton(
onPressed: () =>
Navigator.of(context).push<void>(CupertinoPageRoute(
builder: (context) => FAQEditor(faq: faq),
)),
icon: Icon(
CupertinoIcons.pen,
color: primaryColor,
))
]
: [],
),
SliverList(
delegate: SliverChildListDelegate([
Padding(
padding: const EdgeInsets.all(28.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
getQuestion(context, faq),
SizedBox(
height: 50,
),
getAnwser(context, faq)
],
),
),
]))
]),
),
);
}
Widget getQuestion(BuildContext context, FAQ faq) {
bool isEng = Provider.of<LanguageModel>(context).isEng;
return TextLocalStyle(
context,
faq.question(isEng),
fontSize: 22,
fontWeight: FontWeight.bold,
);
}
Widget getAnwser(BuildContext context, FAQ faq) {
bool isEng = Provider.of<LanguageModel>(context).isEng;
return TextLocalStyle(
context,
faq.answer(isEng),
fontSize: 16,
fontWeight: FontWeight.w200,
);
}
_delete() async {
setState(() {
_isLoading = true;
});
try {
FAQModel faqModel = Provider.of<FAQModel>(context, listen: false);
await faqModel.deleteFAQ(faq);
Navigator.pop(context);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
} finally {
setState(() {
_isLoading = false;
});
}
}
}

View File

@@ -0,0 +1,248 @@
import 'package:fcs/domain/constants.dart';
import 'package:fcs/domain/entities/faq.dart';
import 'package:fcs/helpers/theme.dart';
import 'package:fcs/localization/app_translations.dart';
import 'package:fcs/pages/faq/model/faq_model.dart';
import 'package:fcs/pages/faq/widgets.dart';
import 'package:fcs/pages/main/util.dart';
import 'package:fcs/pages/widgets/input_text.dart';
import 'package:fcs/pages/widgets/local_text.dart';
import 'package:fcs/pages/widgets/progress.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_icons/flutter_icons.dart';
import 'package:provider/provider.dart';
const info = "Select additional page";
class FAQEditor extends StatefulWidget {
final FAQ faq;
const FAQEditor({this.faq});
@override
_FAQEditorState createState() => _FAQEditorState();
}
class _FAQEditorState extends State<FAQEditor> {
TextEditingController _sn = new TextEditingController();
TextEditingController _engQ = new TextEditingController();
TextEditingController _mmQ = new TextEditingController();
TextEditingController _engA = new TextEditingController();
TextEditingController _mmA = new TextEditingController();
TextEditingController _pageLabelEng = new TextEditingController();
TextEditingController _pageLabelMm = new TextEditingController();
final _formKey = GlobalKey<FormState>();
bool _isLoading = false;
bool _isNew = false;
String _pageLink = info;
@override
void initState() {
super.initState();
_isNew = widget.faq == null;
if (widget.faq != null) {
_sn.text = widget.faq.sn.toString();
_engQ.text = widget.faq.questionEng;
_mmQ.text = widget.faq.questionMm;
_engA.text = widget.faq.answerEng;
_mmA.text = widget.faq.answerMm;
_pageLabelEng.text = widget.faq.pageLinkLabelEng;
_pageLabelMm.text = widget.faq.pageLinkLabelMm;
_pageLink = widget.faq.pageLink;
}
}
@override
Widget build(BuildContext context) {
final snBox = InputText(
controller: _sn,
labelTextKey: "faq.edit.sn",
maxLines: 1,
withBorder: false,
textInputType: TextInputType.number,
);
final questionEngBox = InputText(
controller: _engQ,
maxLines: 2,
withBorder: true,
);
final answerEngBox = InputText(
controller: _engA,
maxLines: 5,
withBorder: true,
);
final questionMmBox = InputText(
controller: _mmQ,
maxLines: 2,
withBorder: true,
);
final answerMmBox = InputText(
controller: _mmA,
maxLines: 5,
withBorder: true,
);
final pageLinkBox = DropdownButton<String>(
value: _pageLink,
style: TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: primaryColor,
),
onChanged: (String newValue) {
setState(() {
_pageLink = newValue;
});
},
items: <String>[info, page_buying_instructions, page_payment_methods]
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(
value,
style:
TextStyle(color: value == info ? Colors.black : primaryColor),
),
);
}).toList(),
);
final pageLabelEngBox = InputText(
controller: _pageLabelEng,
labelTextKey: "faq.edit.page.label.eng",
);
final pageLabelMmBox = InputText(
controller: _pageLabelMm,
labelTextKey: "faq.edit.page.label.mm",
);
return LocalProgress(
inAsyncCall: _isLoading,
child: Scaffold(
body: CustomScrollView(slivers: [
SliverAppBar(
leading: IconButton(
icon: Icon(
CupertinoIcons.back,
size: 30,
),
onPressed: () => Navigator.of(context).pop(),
),
backgroundColor: primaryColor,
expandedHeight: 150.0,
floating: true,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
titlePadding: EdgeInsets.symmetric(vertical: 10),
title: LocalText(
context,
_isNew ? 'faq.add.title' : 'faq.edit.title',
fontSize: 20,
color: Colors.white,
)),
actions: [
IconButton(
icon: Icon(Icons.delete),
onPressed: _delete,
)
],
),
SliverList(
delegate: SliverChildListDelegate([
Form(
key: _formKey,
child: Padding(
padding: EdgeInsets.only(left: 24.0, right: 24.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
snBox,
Center(child: itemTitle(context, "faq.edit.eng")),
subItemTitle(context, "faq.edit.question",
iconData: SimpleLineIcons.question),
questionEngBox,
subItemTitle(context, "faq.edit.answer",
iconData: MaterialCommunityIcons.message_reply_text),
answerEngBox,
Divider(),
Center(child: itemTitle(context, "faq.edit.mm")),
subItemTitle(context, "faq.edit.question",
iconData: SimpleLineIcons.question),
questionMmBox,
subItemTitle(context, "faq.edit.answer",
iconData: MaterialCommunityIcons.message_reply_text),
answerMmBox,
Divider(),
Center(child: itemTitle(context, "faq.edit.page")),
pageLinkBox,
pageLabelEngBox,
pageLabelMmBox,
fcsButton(context, getLocalString(context, "btn.save"),
callack: _save),
SizedBox(
height: 20,
)
],
),
),
),
]))
])));
}
_save() async {
setState(() {
_isLoading = true;
});
try {
int sn = int.parse(
_sn.text,
onError: (source) => throw Exception("Invalid number"),
);
FAQModel faqModel = Provider.of<FAQModel>(context, listen: false);
FAQ _faq = FAQ(
sn: sn,
questionEng: _engQ.text,
answerEng: _engA.text,
questionMm: _mmQ.text,
answerMm: _mmA.text,
pageLinkLabelEng: _pageLabelEng.text,
pageLinkLabelMm: _pageLabelMm.text,
pageLink: _pageLink);
if (_isNew) {
await faqModel.addFAQ(_faq);
} else {
_faq.id = widget.faq.id;
await faqModel.updateFAQ(_faq);
}
Navigator.pop(context);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
} finally {
setState(() {
_isLoading = false;
});
}
}
_delete() {
showConfirmDialog(context, "faq.edit.delete.confirm", _deleteFAQ);
}
_deleteFAQ() async {
setState(() {
_isLoading = true;
});
try {
FAQModel faqModel = Provider.of<FAQModel>(context, listen: false);
await faqModel.deleteFAQ(widget.faq);
Navigator.pop(context);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
} finally {
setState(() {
_isLoading = false;
});
}
}
}

View File

@@ -0,0 +1,179 @@
import 'package:fcs/domain/constants.dart';
import 'package:fcs/domain/entities/faq.dart';
import 'package:fcs/helpers/theme.dart';
import 'package:fcs/localization/app_translations.dart';
import 'package:fcs/pages/buying_instruction/buying_online.dart';
import 'package:fcs/pages/faq/faq_edit_page.dart';
import 'package:fcs/pages/main/model/language_model.dart';
import 'package:fcs/pages/main/model/main_model.dart';
import 'package:fcs/pages/payment_methods/payment_method_page.dart';
import 'package:fcs/pages/widgets/bottom_up_page_route.dart';
import 'package:fcs/pages/widgets/fcs_expansion_tile.dart';
import 'package:fcs/pages/widgets/local_text.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'model/faq_model.dart';
const Duration _kExpand = Duration(milliseconds: 200);
class FAQListPage extends StatefulWidget {
@override
_FAQListPageState createState() => _FAQListPageState();
}
class _FAQListPageState extends State<FAQListPage>
with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation<double> _iconTurns;
@override
void initState() {
super.initState();
_controller = AnimationController(duration: _kExpand, vsync: this);
var _halfTween = Tween<double>(begin: 0.0, end: 0.5);
var _easeInTween = CurveTween(curve: Curves.easeIn);
_iconTurns = _controller.drive(_halfTween.chain(_easeInTween));
}
@override
Widget build(BuildContext context) {
FAQModel faqModel = Provider.of<FAQModel>(context);
bool isEditable = context.select((MainModel m) => m.faqEditable());
return Scaffold(
floatingActionButton: isEditable
? FloatingActionButton.extended(
onPressed: () {
Navigator.of(context).push(BottomUpPageRoute(FAQEditor()));
},
icon: Icon(Icons.add),
label: LocalText(context, "faq.add.title", color: Colors.white),
backgroundColor: primaryColor,
)
: Container(),
body: CustomScrollView(
slivers: [
SliverAppBar(
leading: IconButton(
icon: Icon(
CupertinoIcons.back,
size: 30,
),
onPressed: () => Navigator.of(context).pop(),
),
backgroundColor: primaryColor,
expandedHeight: 150.0,
floating: false,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
titlePadding:
EdgeInsets.symmetric(vertical: 10, horizontal: 45),
title: LocalText(
context,
"faq.title",
fontSize: 20,
color: Colors.white,
),
),
actions: isEditable
? [
IconButton(
onPressed: () => setState(() {
isEditMode = !isEditMode;
}),
icon: Icon(
Icons.edit,
color: Colors.white,
))
]
: [],
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return _faqItem(context, faqModel.faqs[index]);
},
childCount: faqModel.faqs.length,
),
)
],
));
}
bool isEditMode = false;
Widget _faqItem(BuildContext context, FAQ faq) {
bool isEng = Provider.of<LanguageModel>(context).isEng;
return Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: FcsExpansionTile(
isEdit: isEditMode,
title: TextLocalStyle(
context,
faq.question(isEng),
fontSize: 16,
fontWeight: FontWeight.w600,
color: primaryColor,
),
onEditPress: () {
Navigator.of(context).push<void>(CupertinoPageRoute(
builder: (context) => FAQEditor(faq: faq),
));
},
children: [getAnwser(context, faq)],
),
),
Divider(
thickness: 2,
),
],
);
}
Widget getAnwser(BuildContext context, FAQ faq) {
bool isEng = Provider.of<LanguageModel>(context).isEng;
return Column(
children: [
TextLocalStyle(
context,
faq.answer(isEng),
fontSize: 16,
fontWeight: FontWeight.w200,
),
_pageLink(
faq.pageLink,
isEng ? faq.pageLinkLabelEng : faq.pageLinkLabelMm,
),
],
);
}
Widget _pageLink(String linkPage, String text) {
return linkPage == null || linkPage == "" || text == null || text == ""
? Container()
: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FlatButton(
color: primaryColor,
onPressed: () => _selectLinkPage(linkPage),
child: LocalText(context, "", text: text, color: Colors.white),
)
],
);
}
_selectLinkPage(String linkPage) {
if (linkPage == page_payment_methods) {
Navigator.of(context).push(BottomUpPageRoute(PaymentMethodPage()));
} else if (linkPage == page_buying_instructions) {
Navigator.of(context).push(BottomUpPageRoute(BuyingOnlinePage()));
}
}
}

View File

@@ -0,0 +1,56 @@
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:fcs/data/services/services.dart';
import 'package:fcs/domain/entities/faq.dart';
import 'package:fcs/pages/main/model/base_model.dart';
import 'package:logging/logging.dart';
class FAQModel extends BaseModel {
final log = Logger('FAQModel');
List<FAQ> faqs = [];
FAQ getFAQ(String id) {
return faqs.firstWhere((e) => e.id == id, orElse: () => null);
}
StreamSubscription<QuerySnapshot> listener;
FAQModel() {
if (listener != null) listener.cancel();
try {
listener = Firestore.instance
.collection("/faqs")
.orderBy("sn", descending: false)
.snapshots()
.listen((snaps) {
faqs.clear();
snaps.documents.forEach((d) {
faqs.add(FAQ.fromMap(d.data, d.documentID));
});
notifyListeners();
});
} catch (e) {
log.warning("error:$e");
}
}
Future<void> addFAQ(FAQ faq) async {
await request("/faqs", "POST",
payload: faq.toMap(),
token: await Services.instance.authService.getToken());
}
Future<void> updateFAQ(FAQ faq) async {
await request("/faqs", "PUT",
payload: faq.toMap(),
token: await Services.instance.authService.getToken());
}
Future<void> deleteFAQ(FAQ faq) async {
await request("/faqs", "DELETE",
payload: faq.toMap(),
token: await Services.instance.authService.getToken());
}
}

103
lib/pages/faq/widgets.dart Normal file
View File

@@ -0,0 +1,103 @@
import 'package:fcs/helpers/theme.dart';
import 'package:fcs/localization/app_translations.dart';
import 'package:fcs/pages/widgets/local_text.dart';
import 'package:flutter/material.dart';
Widget itemTitle(BuildContext context, String textKey) {
return Padding(
padding: const EdgeInsets.only(left: 18.0, top: 15, bottom: 0),
child: Text(
AppTranslations.of(context).text(textKey),
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 18, color: Colors.black),
),
);
}
Widget subItemTitle(BuildContext context, String textKey, {IconData iconData}) {
return Padding(
padding: const EdgeInsets.only(left: 0, top: 0, bottom: 0),
child: Row(
children: [
Icon(
iconData,
color: primaryColor,
),
SizedBox(width: 10),
Text(
AppTranslations.of(context).text(textKey),
style: TextStyle(
fontWeight: FontWeight.w700, fontSize: 15, color: primaryColor),
),
],
),
);
}
Widget contactItem(BuildContext context, String text, IconData iconData,
{Function() onTap, String labelKey}) {
return Material(
child: Padding(
padding: const EdgeInsets.only(left: 18.0, bottom: 10, right: 18),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey, width: 0.8),
borderRadius: BorderRadius.all(
Radius.circular(5.0) // <--- border radius here
),
),
child: InkWell(
onTap: () => onTap != null ? onTap() : null,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
iconData,
color: primaryColor,
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
labelKey == null
? Container()
: Padding(
padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
child: LocalText(context, labelKey,
color: primaryColor,
fontWeight: FontWeight.w500,
fontSize: 18),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
text == null ? "" : text,
overflow: TextOverflow.ellipsis,
maxLines: 5,
style: TextStyle(
fontSize: 14.0,
),
),
),
],
),
SizedBox(
width: 5,
),
onTap == null
? Container()
: Icon(
Icons.open_in_new,
color: Colors.grey,
size: 15,
)
],
),
)),
),
),
);
}