Parissi lets you find the perfect event without spending too much time! Explore events by category to get notified when new ones are added. Find your favorite themes and easily share them with your friends. Get all of the incredibly useful information like address, schedule, transportation options; Parissi is here to make planning easy!
Event page’s example code
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_html/style.dart';
import 'package:flutter_icons/flutter_icons.dart';
import 'package:intl/intl.dart';
import 'package:line_awesome_icons/line_awesome_icons.dart';
import 'package:size_me_v2/models/POI.dart';
import 'package:size_me_v2/models/MySettings.dart';
import 'package:size_me_v2/ui/poidetail/PoiDetailScreenBloc.dart';
import 'package:size_me_v2/utils/Constants.dart';
import 'package:size_me_v2/utils/Ext.dart';
import 'package:size_me_v2/utils/Style.dart';
import 'package:size_me_v2/utils/WidgetUtils.dart';
import 'package:maps_launcher/maps_launcher.dart';
import 'package:sprintf/sprintf.dart';
import 'package:url_launcher/url_launcher.dart';
import 'dart:io' show Platform;
import 'package:numberpicker/numberpicker.dart';
import 'package:add_2_calendar/add_2_calendar.dart';
class PoiDetailScreen extends StatefulWidget {
PoiDetailScreen({Key key, this.poiId, this.settings}) : super(key: key);
final String poiId;
final MySettings settings;
final PoiDetailScreenBloc poiDetailScreenBloc = PoiDetailScreenBloc();
@override
_PoiDetailScreenState createState() => _PoiDetailScreenState();
}
class _PoiDetailScreenState extends State<PoiDetailScreen> {
List<Widget> _poiDetailWidgetList = List();
final _key = new GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
widget.poiDetailScreenBloc.listenToData(widget.settings, widget.poiId, context);
return Container(
color: widget.settings.parsedMainColor,
child: StreamBuilder(
stream: widget.poiDetailScreenBloc.homeScreenItem,
builder: (context, AsyncSnapshot<PoiDetailScreenItem> snapshot) {
return Center(child: _buildResults(snapshot));
}),
);
}
Widget _buildResults(AsyncSnapshot<PoiDetailScreenItem> snapshot) {
if (snapshot.data == null || snapshot.data.isLoading()) {
return getDefaultPurpleLoader();
}
POI poi = snapshot.data.poi;
_fillPoiDetailWidgetList(poi, snapshot.data.isUserAdmin);
return Container(
color: widget.settings.parsedMainColor,
child: Scaffold(
key: _key,
backgroundColor: widget.settings.parsedMainColor,
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
expandedHeight: 200,
pinned: false,
actions: <Widget>[
getClickableIconButton(Platform.isIOS ? Entypo.share_alternative : Icons.share, () {
widget.poiDetailScreenBloc.createDynamicLink(poi, context);
}),
if (snapshot.data.isUserAdmin)
getClickableIconButton(Entypo.instagram, () {
widget.poiDetailScreenBloc.shouldBeInstagramPushed();
}),
if (snapshot.data.isUserAdmin)
getClickableIconButton(Icons.fiber_new, () {
_showDialog();
}),
],
backgroundColor: widget.settings.parsedMainColor,
flexibleSpace: FlexibleSpaceBar(
centerTitle: false,
background: InkWell(
onTap: () {
context.openPhotoViewScreen(widget.settings, [poi.cover]);
},
child: Stack(
children: <Widget>[
CachedNetworkImage(
placeholder: (context, url) => Image.asset(
widget.settings.getResourcePath('place_holder_image.png'),
height: double.infinity,
width: double.infinity,
fit: BoxFit.cover,
),
imageUrl: poi.cover,
fit: BoxFit.cover,
height: double.infinity,
width: double.infinity,
fadeInDuration: Duration(milliseconds: 300),
),
Container(
decoration: new BoxDecoration(
gradient: new LinearGradient(
colors: [Colors.black45, Colors.transparent, Colors.black45],
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
tileMode: TileMode.repeated),
),
height: double.infinity,
width: double.infinity,
),
],
),
),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => Container(
color: widget.settings.parsedMainColor,
child: _poiDetailWidgetList[index],
),
childCount: _poiDetailWidgetList.length),
),
],
),
floatingActionButton: FloatingActionButton(
backgroundColor: widget.settings.parsedSecondColor,
child: Icon(poi.isFavorite ? Icons.favorite : Icons.favorite_border),
onPressed: () {
widget.poiDetailScreenBloc.onFavoriteClicked();
},
),
),
);
}
void _fillPoiDetailWidgetList(POI poi, bool isAdmin) {
_poiDetailWidgetList.clear();
_poiDetailWidgetList.add(_getHeaderWidget(poi));
_poiDetailWidgetList.add(_getSeparator());
_poiDetailWidgetList.add(_createActionTab(poi));
print("debug weather : ${poi.weatherIconUrl}");
if (poi.weatherDescription.isNotEmpty && poi.weatherIconUrl.isNotEmpty) {
_poiDetailWidgetList.add(_getWeatherBloc(poi));
}
String poiWarning = widget.settings.displayPoiWarning.getLocalizedString(context);
if (poi.displayDescription != null && poi.displayDescription.isNotEmpty) {
String description = poi.displayDescription.getLocalizedString(context);
if (isAdmin) {
description = poi.id + " " + description;
}
if (description.isNotEmpty) {
_poiDetailWidgetList.add(_getDetailItemWidget(null, description, showDivider: poiWarning.isEmpty));
}
}
if (poiWarning != null && poiWarning.isNotEmpty) {
_poiDetailWidgetList.add(_getSeparator());
_poiDetailWidgetList.add(_createPoiWarning(poiWarning));
}
if (poi.address != null && poi.address.isNotEmpty) {
_poiDetailWidgetList.add(_getSeparator());
_poiDetailWidgetList.add(_getDetailItemWidget(Icons.place, poi.address, callBack: () {
MapsLauncher.launchCoordinates(poi.latitude, poi.longitude);
}));
}
DateFormat dfDate = DateFormat.yMMMMd(widget.settings.locale);
DateFormat dfHour = DateFormat.Hm(widget.settings.locale);
if (poi.displaySchedule != null && poi.displaySchedule.isNotEmpty) {
String schedule = poi.displaySchedule.getLocalizedString(context);
if (schedule.endsWith("<br />")) {
schedule = schedule.substring(0, schedule.length - "<br />".length);
}
if (schedule.isNotEmpty) {
_poiDetailWidgetList.add(_getSeparator());
_poiDetailWidgetList.add(_getDetailItemWidget(Icons.schedule, schedule, callBack: () {
_showCalendarDialog(poi, dfDate, dfHour);
}));
}
}
if (poi.occurrences != null && poi.occurrences.isNotEmpty) {
String title;
if (poi.occurrences.length == 1) {
title = context.getString('occurrence_action');
} else {
title = "${context.getString('occurrence_action')}<br>${poi.occurrences.length} ${context.getString('occurrence_action_dates')}";
}
_poiDetailWidgetList.add(_getSeparator());
_poiDetailWidgetList.add(_getDetailItemWidget(Icons.calendar_today_outlined, title, callBack: () {
_showCalendarDialog(poi, dfDate, dfHour);
}));
}
if (poi.displayPrice != null && poi.displayPrice.isNotEmpty) {
String price = poi.displayPrice.getLocalizedString(context);
if (price.isNotEmpty) {
_poiDetailWidgetList.add(_getSeparator());
_poiDetailWidgetList.add(_getDetailItemWidget(Icons.attach_money, price));
}
} else if (poi.priceType != null && poi.priceType.isNotEmpty) {
String price = poi.getDescForPriceType(context);
if (price != null) {
_poiDetailWidgetList.add(_getSeparator());
_poiDetailWidgetList.add(_getDetailItemWidget(Icons.attach_money, price));
}
}
if (poi.displayTransport != null && poi.displayTransport.isNotEmpty) {
String transport = poi.displayTransport.getLocalizedString(context);
if (transport.isNotEmpty) {
_poiDetailWidgetList.add(_getSeparator());
_poiDetailWidgetList.add(_getDetailItemWidget(Icons.directions_transit, transport, callBack: () {
MapsLauncher.launchCoordinates(poi.latitude, poi.longitude);
}));
}
}
if (poi.coverCredit != null && poi.coverCredit.isNotEmpty) {
_poiDetailWidgetList.add(_getSeparator());
_poiDetailWidgetList
.add(_getDetailItemWidget(LineAwesomeIcons.creative_commons, "Photo Credit : " + poi.coverCredit));
}
if (poi.latitude != 0 && poi.longitude != 0) {
String mapImageUrl = sprintf(STATIC_MAP_URL,
[poi.latitude.toString(), poi.longitude.toString(), poi.latitude.toString(), poi.longitude.toString()]);
_poiDetailWidgetList.add(InkWell(
onTap: () {
MapsLauncher.launchCoordinates(poi.latitude, poi.longitude);
},
child: Container(
height: 200,
child: FadeInImage.assetNetwork(
placeholder: widget.settings.getResourcePath('place_holder_image.png'),
fit: BoxFit.cover,
image: mapImageUrl,
height: double.infinity,
width: double.infinity,
fadeInDuration: Duration(milliseconds: 300),
),
),
));
}
}
Widget _getSeparator() {
return Container(height: 1, color: Colors.black38.withAlpha(20));
}
Widget _getHeaderWidget(POI poi) {
return Container(
color: widget.settings.parsedMainColor,
child: Align(
alignment: Alignment.topLeft,
child: Column(
children: <Widget>[
Container(
width: double.infinity,
child: Padding(
padding: const EdgeInsets.only(left: 16, right: 16, top: 16),
child: InkWell(
onLongPress: () {
Clipboard.setData(new ClipboardData(text: poi.displayName.getLocalizedString(context)));
_key.currentState.showSnackBar(new SnackBar(
content: new Text(context.getString('poi_detail_copy')),
));
},
child: Text(
poi.displayName.getLocalizedString(context),
style: getPoiDetailNameStyle(),
),
),
)),
Container(
width: double.infinity,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Padding(
padding: const EdgeInsets.only(left: 16, top: 8),
child: Row(
children: <Widget>[
for (var tag in poi.tagsObjList)
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: getTagListItem(context, widget.settings, tag),
),
],
),
),
),
)
],
),
),
);
}
Widget _getWeatherBloc(POI poi) {
return Container(
color: widget.settings.parsedMainColor,
child: Padding(
padding: const EdgeInsets.fromLTRB(32, 32, 32, 0),
child: Container(
decoration: BoxDecoration(color: Colors.white10, borderRadius: BorderRadius.all(Radius.circular(20))),
child: Padding(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 8),
child: Column(
children: [
Text(context.getString('weather_update'),
style: TextStyle(color: Colors.white),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CachedNetworkImage(
fit: BoxFit.cover,
imageUrl: poi.weatherIconUrl,
height: 45,
width: 45,
fadeInDuration: Duration(milliseconds: 300),
),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Column(
children: [
Text(
poi.weatherDescription.capitalize() + " " + poi.weatherTemperature.toInt().toString() + "°C",
style: TextStyle(color: Colors.white, fontSize: 18),
),
],
),
)
],
)
],
),
),
),
),
);
}
Widget _createPoiWarning(String poiWarning) {
return Container(
color: widget.settings.parsedMainColor,
child: Padding(
padding: const EdgeInsets.fromLTRB(32, 32, 32, 32),
child: Container(
decoration: BoxDecoration(color: Colors.white10, borderRadius: BorderRadius.all(Radius.circular(20))),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
poiWarning,
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white),
),
),
),
),
);
}
Widget _createActionTab(POI poi) {
return Container(
color: widget.settings.parsedMainColor,
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 16, bottom: 16),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Padding(
padding: const EdgeInsets.only(left: 8, right: 8),
child: Row(
children: <Widget>[
if (poi.latitude != null && poi.latitude != 0 && poi.longitude != null && poi.longitude != 0)
_getActionItemWidget(Icons.directions, () {
MapsLauncher.launchCoordinates(poi.latitude, poi.longitude);
}),
if (poi.phoneNumber != null && poi.phoneNumber.isNotEmpty)
_getActionItemWidget(Icons.phone, () {
launch("tel://" + poi.phoneNumber);
// Add to fav
}),
if (_getBestUrl(poi) != null)
_getActionItemWidget(Icons.link, () {
launch(_getBestUrl(poi));
}),
if (poi.twitter != null && poi.twitter.isNotEmpty)
_getActionItemWidget(LineAwesomeIcons.twitter, () {
launch("https://twitter.com/${poi.twitter}");
}),
if (poi.facebook != null && poi.facebook.isNotEmpty)
_getActionItemWidget(LineAwesomeIcons.facebook_f, () {
launch("https://www.facebook.com/${poi.facebook}");
}),
],
),
),
),
)
],
),
);
}
String _getBestUrl(POI poi) {
if ((poi.website != null && poi.website.isNotEmpty) || (poi.link != null && poi.link.isNotEmpty)) {
if (poi.link != null && poi.link.isNotEmpty) {
return poi.link;
} else {
return poi.website;
}
}
return null;
}
Widget _getActionItemWidget(IconData icon, Function actionCallback) {
return Padding(
padding: const EdgeInsets.only(left: 8, right: 8),
child: Container(
decoration: BoxDecoration(color: widget.settings.parsedSecondColor, shape: BoxShape.circle),
child: Material(
type: MaterialType.transparency,
child: InkWell(
customBorder: new CircleBorder(),
onTap: () {
actionCallback();
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
icon,
size: 35,
color: Colors.white,
),
),
),
)),
);
}
Widget _getDetailItemWidget(IconData icon, String content, {bool showDivider = true, Function callBack}) {
return Container(
color: widget.settings.parsedMainColor,
child: Material(
type: MaterialType.transparency,
child: InkWell(
onLongPress: () {
print("Content : ");
print(content);
Clipboard.setData(new ClipboardData(text: content));
_key.currentState.showSnackBar(SnackBar(
content: new Text(context.getString('poi_detail_copy')),
));
},
onTap: () {
if (callBack != null) {
callBack();
}
},
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: <Widget>[
if (icon != null)
Icon(
icon,
color: widget.settings.parsedSecondColor,
),
Flexible(
child: Padding(
padding: EdgeInsets.only(left: icon != null ? 16 : 0),
child: Html(
data: "<p>${content.replaceAll("style=", "stylee=")}</p>",
style: getHtmlPoiDetailTextStyle(),
onLinkTap: (link) {
launch(link);
},
),
),
)
],
),
),
],
),
),
),
);
}
Widget setupAlertDialogContainer(POI poi, DateFormat dfDate, DateFormat dfHour) {
List<Occurrence> occurrences = poi.occurrences;
return Container(
width: double.maxFinite, // Change as per your requirement
child: ListView.builder(
shrinkWrap: true,
itemCount: occurrences.length,
itemBuilder: (BuildContext context, int index) {
DateTime startDate = occurrences[index].start.toDate();
DateTime endDate = occurrences[index].end.toDate();
String startTime = dfDate.format(startDate) + " - " + dfHour.format(startDate);
String endTime = dfDate.format(endDate) + " - " + dfHour.format(endDate);
int offset = DateTime.now().timeZoneOffset.inHours;
String timeZone = offset > 0 ? '+' + offset.toString() : offset.toString();
return ListTile(
title: Column(
children: [
if (index == 0) Padding(
padding: const EdgeInsets.only(bottom: 16.0),
child: Text(context.getString('occurrence_dialog_description')),
),
InkWell(
onTap: () {
final Event event = Event(
title: poi.displayName.getLocalizedString(context),
description: poi.displayShortDescription.getLocalizedString(context) + " " + widget.poiDetailScreenBloc.dynamicLink ?? "",
location: poi.address,
startDate: startDate,
endDate: endDate,
timeZone: "GMT$timeZone"
);
Add2Calendar.addEvent2Cal(event);
widget.poiDetailScreenBloc.createGoingEntry(context, occurrences[index]);
},
child: Padding(
padding: const EdgeInsets.fromLTRB(8.0,8.0,8.0,14.0),
child: Column(
children: [
Text('$startTime'),
Text('$endTime'),
],
),
),
),
Container(
width: double.maxFinite,
height: 1,
color: Colors.black12,
)
],
),
);
},
),
);
}
void _showCalendarDialog(POI poi, DateFormat dfDate, DateFormat dfHour) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(context.getString('occurrence_dialog_title')),
content: setupAlertDialogContainer(poi, dfDate, dfHour),
);
});
}
void _showDialog() {
showDialog<int>(
context: context,
builder: (BuildContext context) {
return NumberPickerDialog.integer(minValue: 0, maxValue: 1000, initialIntegerValue: 1);
}).then((value) => {widget.poiDetailScreenBloc.onHightlightUpdate(value)});
}
@override
void dispose() {
widget.poiDetailScreenBloc.dispose();
super.dispose();
}
}