Skip to main content

Parissi - Events and activities in Paris

An app that helps to find events in Paris using an open-source database of events.

Android | iOS

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, and 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 { List _poiDetailWidgetList = List();

final _key = new GlobalKey();

@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 snapshot) { return Center(child: _buildResults(snapshot)); }), ); }

Widget _buildResults(AsyncSnapshot 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: [ SliverAppBar( expandedHeight: 200, pinned: false, actions: [ 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: [ 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("
")) { schedule = schedule.substring(0, schedule.length - "
".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')}
${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: [ 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: [ 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: [ 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: [ 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: [ Padding( padding: const EdgeInsets.all(16.0), child: Row( children: [ if (icon != null) Icon( icon, color: widget.settings.parsedSecondColor, ), Flexible( child: Padding( padding: EdgeInsets.only(left: icon != null ? 16 : 0), child: Html( data: "

${content.replaceAll("style=", "stylee=")}

", style: getHtmlPoiDetailTextStyle(), onLinkTap: (link) { launch(link); }, ), ), ) ], ), ), ], ), ), ), ); }

Widget setupAlertDialogContainer(POI poi, DateFormat dfDate, DateFormat dfHour) { List 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( 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(); } }

By continuing to use the site, you agree to the use of cookies.