Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import 'dart:async';
- import 'package:expandable/expandable.dart';
- import 'package:flutter/material.dart';
- import 'package:flutter/services.dart';
- import 'package:flutter_svg/flutter_svg.dart';
- import 'package:qr_flutter/qr_flutter.dart';
- import 'package:tireservice/analytics/Analytics.dart';
- import 'package:tireservice/dto/AdsDto.dart';
- import 'package:tireservice/dto/TireserviceComment.dart';
- import 'package:tireservice/dto/TireserviceDto.dart';
- import 'package:tireservice/repository/Database.dart';
- import 'package:tireservice/ui/AdsUI.dart';
- import 'package:tireservice/ui/ImageViewerUI.dart';
- import 'package:tireservice/ui/ReviewSendingScreen.dart';
- import 'package:tireservice/ui/Style.dart';
- import 'package:tireservice/ui/UIComponents.dart';
- import 'package:shimmer/shimmer.dart';
- import 'package:tireservice/utils/Utils.dart';
- import 'package:url_launcher/url_launcher.dart';
- class TireserviceDetailsScreen extends StatefulWidget {
- final TireserviceDto tireservice;
- const TireserviceDetailsScreen({Key key, @required this.tireservice})
- : super(key: key);
- @override
- State<StatefulWidget> createState() => _TireserviceDetailsScreenState();
- }
- class _TireserviceDetailsScreenState extends State<TireserviceDetailsScreen> {
- static const callButtonContainerHeight = 72.0;
- static const adsHeaderHeight = 50.0;
- final _database = Database();
- List<TireserviceComment> _comments = [];
- var commentsLoaded = false;
- StreamSubscription _getCommentsSubscription;
- StreamSubscription _getTireserviceSubscription;
- TireserviceDto _actualTireserviceInfo;
- bool isAdsMustShow = false;
- static const platform = const MethodChannel('maps');
- @override
- void initState() {
- super.initState();
- _actualTireserviceInfo = widget.tireservice;
- _fetchTireservice();
- _fetchComments();
- _fetchAds();
- }
- @override
- void dispose() {
- super.dispose();
- _getCommentsSubscription?.cancel();
- _getTireserviceSubscription?.cancel();
- }
- void redraw() {
- this.setState(() {});
- }
- _fetchAds() {
- _database.streamAdsByCity(widget.tireservice.city).map((docs) {
- return docs.map((doc) {
- return AdsDto.createFromDocument(doc);
- });
- }).listen((ads) {
- isAdsMustShow = ads.isNotEmpty;
- redraw();
- });
- }
- _fetchTireservice() {
- _getTireserviceSubscription = _database
- .streamTireserviceById(_actualTireserviceInfo.tireserviceId)
- .listen((doc) {
- _actualTireserviceInfo = TireserviceDto.createFromDocument(doc);
- redraw();
- });
- }
- _callPhone(String phone) async {
- if (phone == null || phone.isEmpty) return;
- final validPhone =
- phone.length == 11 ? phone.substring(1) : phone.substring(2);
- final url = "tel:+7$validPhone";
- if (await canLaunch(url)) {
- await launch(url);
- } else {
- throw 'Could not launch $url';
- }
- }
- void _fetchComments() {
- _getCommentsSubscription = _database
- .streamTireserviceCommentsById(_actualTireserviceInfo.tireserviceId)
- .asyncMap(
- (documents) {
- return documents.map(
- (document) {
- return TireserviceComment.createFromDocument(document);
- },
- );
- },
- ).listen((comments) {
- this._comments = List.from(comments);
- _comments
- .sort((first, second) => second.timestamp.compareTo(first.timestamp));
- commentsLoaded = true;
- redraw();
- });
- }
- showReviewSending() {
- Analytics.showReviewSending();
- showModalBottomSheet(
- useRootNavigator: true,
- isScrollControlled: true,
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.vertical(top: Radius.circular(8))),
- context: context,
- builder: (BuildContext bc) {
- return DraggableScrollableSheet(
- initialChildSize: 0.85,
- maxChildSize: 0.85,
- minChildSize: 0.8,
- expand: false,
- builder: (BuildContext context, ScrollController scrollController) {
- return Material(
- borderRadius: BorderRadius.vertical(top: Radius.circular(8)),
- child: ReviewSendingUI(_actualTireserviceInfo.tireserviceId),
- );
- },
- );
- },
- );
- }
- _showImageViewer() {
- Navigator.of(context).push(PageRouteBuilder(
- pageBuilder: (context, anim1, anim2) =>
- ImageViewer(_actualTireserviceInfo.picturesURLs),
- settings: RouteSettings(name: 'ImageViewer'),
- )); //;
- }
- _setStatusBarToBlackText() {
- SystemChrome.setSystemUIOverlayStyle(
- SystemUiOverlayStyle(statusBarBrightness: Brightness.light));
- }
- @override
- Widget build(BuildContext context) {
- _setStatusBarToBlackText();
- // adsHeaderElement = adsHeader().createElement();
- return Scaffold(
- resizeToAvoidBottomInset: true,
- body: Stack(
- children: <Widget>[
- Container(
- color: Colors.white,
- child: ListView(
- children: buildContent(),
- )),
- Align(
- alignment: Alignment.bottomCenter,
- child: Container(
- color: Colors.white,
- child: SafeArea(
- top: false,
- child: _showAdsPanel(),
- ),
- ),
- )
- ],
- ),
- );
- }
- List<Widget> buildContent() {
- var listWidgets = <Widget>[];
- listWidgets.add(imageRow());
- listWidgets.add(subtitleRow("О шиномонтаже"));
- listWidgets.add(addressRow());
- if (_actualTireserviceInfo.getAdditionalsString().isNotEmpty)
- listWidgets.add(additionalsRow());
- if (_actualTireserviceInfo.promo != null &&
- _actualTireserviceInfo.promo.isNotEmpty) {
- listWidgets.add(subtitleRow("Акции"));
- listWidgets.add(promoRow());
- listWidgets.add(showThisToWorker());
- }
- listWidgets.add(subtitleRow("Рейтинг и отзывы"));
- listWidgets.add(reviewsRow());
- listWidgets.add(reviewsContainerRow());
- var totalBottomContainerHeight = callButtonContainerHeight;
- if (isAdsMustShow) {
- totalBottomContainerHeight += adsHeaderHeight + 16;
- }
- listWidgets.add(SizedBox.fromSize(
- size: Size.fromHeight(totalBottomContainerHeight),
- ));
- return listWidgets;
- }
- Widget _showAdsPanel() {
- final bottomPanelWidgets = List<Widget>();
- if (isAdsMustShow) {
- bottomPanelWidgets.add(adsHeader());
- }
- bottomPanelWidgets.add(bottomButtonWidget());
- return Column(
- mainAxisSize: MainAxisSize.min,
- children: bottomPanelWidgets,
- );
- }
- Widget adsHeader() {
- return Material(
- elevation: 1,
- child: ExpandablePanel(
- header: Material(
- color: Colors.blue[50],
- borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
- child: Shimmer.fromColors(
- child: Container(
- height: adsHeaderHeight,
- decoration: ShapeDecoration(
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.vertical(top: Radius.circular(8)),
- ),
- ),
- alignment: Alignment.center,
- width: double.infinity,
- child: Padding(
- padding: EdgeInsets.fromLTRB(16, 8, 16, 8),
- child: TextMediumBlack16("Скидки от партнёров!"),
- ),
- ),
- baseColor: Colors.blue,
- highlightColor: Colors.green[200],
- period: const Duration(milliseconds: 3000),
- ),
- ),
- collapsed: Container(),
- expanded: expandedFooter(),
- tapHeaderToExpand: true,
- tapBodyToCollapse: true,
- hasIcon: false,
- ),
- );
- }
- Widget expandedFooter() {
- return Column(
- children: <Widget>[
- AdsUI(widget.tireservice.city, AdCallSource.details),
- ],
- );
- }
- Widget bottomButtonWidget() {
- return Container(
- height: callButtonContainerHeight,
- alignment: Alignment.center,
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceAround,
- mainAxisSize: MainAxisSize.max,
- children: [
- CallButton(
- onPressed: () {
- Analytics.logOnCallBtnTapped(widget.tireservice);
- _callPhone(widget.tireservice.phone);
- },
- ),
- InkWell(
- onTap: ()async{
- await platform.invokeMethod('get2gis',{"lon":_actualTireserviceInfo.longitude, "lat":_actualTireserviceInfo.latitude});
- },
- child: Container(
- height: callButtonContainerHeight*0.6,
- child: Image.asset(
- 'assets/icons/2gis.png',
- ),
- ),
- ),
- InkWell(
- onTap: ()async{
- await platform.invokeMethod('getYandex',{"lon":_actualTireserviceInfo.longitude, "lat":_actualTireserviceInfo.latitude});
- },
- child: Container(
- height: callButtonContainerHeight*0.6,
- child: Image.asset(
- 'assets/icons/yandex_maps.png',
- ),
- ),
- ),
- ],
- ),
- );
- }
- Widget promoRow() {
- return Padding(
- padding: EdgeInsets.fromLTRB(10, 0, 10, 10),
- child: Card(
- elevation: 6,
- color: Colors.yellow[100],
- child: Column(
- children: <Widget>[
- Container(
- padding: EdgeInsets.all(16),
- child: TextBlack14(
- _actualTireserviceInfo.promo,
- useEllipsisOverflow: false,
- ),
- ),
- QrImage(
- padding: EdgeInsets.only(bottom: 16),
- data:
- "$saleUrl?text=${_actualTireserviceInfo.promo}&address=${_actualTireserviceInfo.address}",
- version: QrVersions.auto,
- size: 100.0,
- ),
- ],
- ),
- ),
- );
- }
- Widget showThisToWorker() {
- return Padding(
- padding: EdgeInsets.fromLTRB(20, 0, 20, 0),
- child: Expanded(
- child: Text(
- 'Для получения скидки - покажи данный QR работнику шиномонтажа',
- style: TextStyle(
- color: Colors.black54,
- ),
- textAlign: TextAlign.center,
- ),
- ),
- );
- }
- Widget subtitleRow(String text) {
- return Container(
- color: Colors.white,
- child: Padding(
- padding: EdgeInsets.fromLTRB(16, 16, 16, 8),
- child: Row(
- children: <Widget>[
- Expanded(
- child: Padding(
- padding: EdgeInsets.fromLTRB(0, 0, 0, 0),
- child: TextMediumBlack18(text),
- ),
- ),
- ],
- ),
- ),
- );
- }
- Widget smallSubtitleRow(String text) {
- return Container(
- color: Colors.white,
- child: Padding(
- padding: EdgeInsets.fromLTRB(16, 16, 16, 8),
- child: Row(
- children: <Widget>[
- Expanded(
- child: Padding(
- padding: EdgeInsets.fromLTRB(0, 0, 0, 0),
- child: Text54MediumBlack16(text),
- ),
- ),
- ],
- ),
- ),
- );
- }
- Widget closeButton() {
- return Align(
- alignment: Alignment.topLeft,
- child: InkWell(
- onTap: () {
- Navigator.pop(context);
- },
- child: Padding(
- padding: EdgeInsets.all(16),
- child: Icon(
- Icons.close,
- color: Colors.white,
- size: 20,
- ),
- ),
- ),
- );
- }
- Widget titleRowTransparent() {
- return Container(
- color: Colors.transparent,
- child: Padding(
- padding: EdgeInsets.fromLTRB(16, 8, 16, 8),
- child: Row(
- children: <Widget>[
- Expanded(
- child: Padding(
- padding: EdgeInsets.fromLTRB(0, 0, 0, 0),
- child: TextMediumWhite18(
- "${_actualTireserviceInfo.getTireserviceTypeString()} ${_actualTireserviceInfo.title}"),
- ),
- ),
- ],
- ),
- ),
- );
- }
- Widget addressRow() {
- return Container(
- color: Colors.white,
- child: Padding(
- padding: EdgeInsets.fromLTRB(16, 8, 16, 8),
- child: Row(
- children: <Widget>[
- Text54Black14("Адрес:"),
- Expanded(
- child: Padding(
- padding: EdgeInsets.fromLTRB(8, 0, 16, 0),
- child: TextBlack14(_actualTireserviceInfo.address),
- ),
- ),
- ],
- ),
- ),
- );
- }
- Widget additionalsRow() {
- return Container(
- color: Colors.white,
- child: Padding(
- padding: EdgeInsets.fromLTRB(16, 0, 16, 0),
- child: Row(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: <Widget>[
- Text54Black14("Дополнительно:"),
- Expanded(
- child: Padding(
- padding: EdgeInsets.fromLTRB(8, 0, 16, 0),
- child: TextBlack14(
- _actualTireserviceInfo.getAdditionalsString(),
- useEllipsisOverflow: false,
- ),
- ),
- ),
- ],
- ),
- ),
- );
- }
- Widget timeOpenRow() {
- return Container(
- color: Colors.white,
- child: Padding(
- padding: EdgeInsets.fromLTRB(16, 0, 16, 10),
- child: Row(
- children: <Widget>[
- SvgPicture.asset("assets/icons/clock_grey_16.svg"),
- Expanded(
- child: Padding(
- padding: EdgeInsets.fromLTRB(16, 0, 16, 0),
- child: Text54Black12(_actualTireserviceInfo.getTimeWorking()),
- ),
- ),
- ],
- ),
- ),
- );
- }
- Widget timeOpenRowTransparent() {
- return Container(
- color: Colors.transparent,
- child: Padding(
- padding: EdgeInsets.fromLTRB(16, 0, 16, 10),
- child: Row(
- children: <Widget>[
- Icon(Icons.access_time, color: Colors.white, size: 20),
- Expanded(
- child: Padding(
- padding: EdgeInsets.fromLTRB(16, 0, 16, 0),
- child:
- TextMediumWhite14(_actualTireserviceInfo.getTimeWorking()),
- ),
- ),
- ],
- ),
- ),
- );
- }
- Widget reviewsRow() {
- return Container(
- color: Colors.white,
- child: Padding(
- padding: EdgeInsets.fromLTRB(16, 0, 16, 0),
- child: Row(
- children: <Widget>[
- TextBlack14(_actualTireserviceInfo.getRatingString()),
- RatingBarReadOnly(rating: _actualTireserviceInfo.rating),
- Spacer(),
- FlatButton(
- onPressed: showReviewSending,
- child: TextBlue16("Написать отзыв"),
- ),
- ],
- ),
- ),
- );
- }
- Widget reviewsContainerRow() {
- var emptyText = commentsLoaded
- ? "У этого шиномонтажа ещё нет ни одного отзыва"
- : "Загружаем отзывы...";
- return Stack(
- children: <Widget>[
- Padding(
- padding: EdgeInsets.fromLTRB(16, 30, 16, 30),
- child: Center(
- child: Text54Black12(emptyText),
- ),
- ),
- Container(
- child: ListView.builder(
- itemCount: _comments.length,
- itemBuilder: (context, index) => Padding(
- padding: EdgeInsets.fromLTRB(16, 10, 16, 0),
- child: reviewWidget(_comments[index])),
- shrinkWrap: true,
- physics: const NeverScrollableScrollPhysics(),
- ),
- ),
- ],
- );
- }
- Widget reviewWidget(TireserviceComment comment) {
- return Container(
- child: Material(
- borderRadius: BorderRadius.circular(8),
- color: Color.fromARGB(255, 246, 248, 250),
- elevation: 0,
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: <Widget>[
- Padding(
- padding: EdgeInsets.fromLTRB(16, 16, 16, 16),
- child: Row(
- children: <Widget>[
- Icon(
- Icons.account_circle,
- size: 30,
- color: Colors.grey,
- ),
- Expanded(
- child: Padding(
- padding: EdgeInsets.fromLTRB(16, 0, 16, 0),
- child: TextBlack14(comment.userName),
- ),
- ),
- Text54Black12(comment.getDateString())
- ],
- ),
- ),
- Padding(
- padding: EdgeInsets.fromLTRB(16, 0, 16, 16),
- child: Align(
- alignment: Alignment.centerLeft,
- child: TextBlack14(
- comment.body,
- useEllipsisOverflow: false,
- ),
- ),
- ),
- Container(
- child: Align(
- alignment: Alignment.centerRight,
- child: Padding(
- padding: EdgeInsets.fromLTRB(16, 0, 16, 16),
- child: RatingBarReadOnlySmall(
- rating: comment.rating,
- ),
- ),
- ),
- )
- ],
- ),
- ),
- );
- }
- Widget imageRow() {
- var rowSize = 200.0;
- return InkWell(
- onTap: _showImageViewer,
- child: Stack(
- alignment: Alignment.bottomLeft,
- children: <Widget>[
- Container(
- constraints: BoxConstraints.expand(height: rowSize),
- foregroundDecoration: BoxDecoration(color: Colors.black38),
- child: Hero(
- tag: _actualTireserviceInfo.picturesURLs.first,
- child: Image(
- fit: BoxFit.fitWidth,
- image: NetworkImage(_actualTireserviceInfo.picturesURLs.first),
- loadingBuilder: (BuildContext context, Widget child,
- ImageChunkEvent loadingProgress) {
- if (loadingProgress == null) return child;
- return Shimmer.fromColors(
- child: Container(
- child: Icon(
- Icons.image,
- size: rowSize,
- ),
- ),
- baseColor: Colors.grey[300],
- highlightColor: Colors.white,
- period: const Duration(milliseconds: 500),
- );
- },
- ),
- ),
- ),
- Container(
- constraints: BoxConstraints.expand(height: rowSize),
- alignment: Alignment.bottomLeft,
- child: Column(
- children: <Widget>[
- closeButton(),
- Spacer(),
- titleRowTransparent(),
- timeOpenRowTransparent(),
- ],
- ),
- ),
- ],
- ),
- );
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement