initial
This commit is contained in:
31
lib/appflow/view/further_pages/article.dart
Normal file
31
lib/appflow/view/further_pages/article.dart
Normal file
@@ -0,0 +1,31 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:hiddingsel_app/appflow/model/articles.dart';
|
||||
|
||||
import '../widgets/card.dart';
|
||||
import '../navigation_drawer.dart';
|
||||
|
||||
class ArticleThumbnailView extends StatelessWidget with NavigationDrawerItem {
|
||||
|
||||
String get title => _article.title;
|
||||
final ArticleModel _article;
|
||||
final Function(PreferredSizeWidget appBar, Widget body)? _onChange;
|
||||
|
||||
ArticleThumbnailView(this._article, this._onChange);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => ItemWithTitle.fromArticle(_article, _onChange);
|
||||
}
|
||||
|
||||
class ArticleView extends StatelessWidget with NavigationDrawerItem {
|
||||
|
||||
String get title => _article.title;
|
||||
final ArticleModel _article;
|
||||
|
||||
ArticleView(this._article);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => ListView(
|
||||
children: [
|
||||
ItemWithWebView.fromArticle(_article)
|
||||
]);
|
||||
}
|
||||
272
lib/appflow/view/further_pages/geschichte.dart
Normal file
272
lib/appflow/view/further_pages/geschichte.dart
Normal file
@@ -0,0 +1,272 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hiddingsel_app/constants/constant.dart';
|
||||
|
||||
import '../navigation_drawer.dart';
|
||||
|
||||
class GeschichteView extends StatelessWidget with NavigationDrawerItem {
|
||||
|
||||
//TODO Low-Prio: Beim nächsten Anfassen durch RichText ersetzen
|
||||
|
||||
@override
|
||||
String get title => 'Geschichte';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => ListView(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
UIShapes.paddingMax,
|
||||
UIShapes.paddingMax,
|
||||
UIShapes.paddingMax,
|
||||
UIShapes.paddingSimple),
|
||||
child: Text(
|
||||
'Über unser Dorf',
|
||||
style: UITheme.theme.textTheme.headlineSmall,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: UIColors.grey5,
|
||||
),
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
0,
|
||||
UIShapes.paddingSimple,
|
||||
UIShapes.paddingMax,
|
||||
UIShapes.paddingSimple,
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: UIShapes.rightRoundedRectangle,
|
||||
child: Image(
|
||||
image: AssetImage(
|
||||
'assets/images/geschichte/img_geschichte.png',
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(UIShapes.paddingMax),
|
||||
child: Text(
|
||||
'Entstehung und Geschichte unseres Dorfes',
|
||||
style: UITheme.theme.textTheme.headlineSmall,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
UIShapes.paddingMax,
|
||||
0,
|
||||
UIShapes.paddingMax,
|
||||
UIShapes.paddingMax,
|
||||
),
|
||||
child: Text(
|
||||
'Der Name Hiddingsel wurde erstmals im Jahre 1032 erwähnt. Der Name entstammt dem angelsächsischen Männernamen „Hiddo“. Die Endung auf „sel“ deutet auf Saal-Scheune-Sitz hin. Einer zweiten Version zufolge leitet sich die Silbe „Hid“ von dem Eigennamen „Hildi“ her. Zu dieser Zeit gab es verschiedene Haupthöfe mit zugeordneten Unterhöfen. Einer dieser Haupthöfe war der Hof Hiddingsel. Der Hof des Hiddo hat an der westlichen Seite des Dorfes Hiddingsel gelegen. Hier stand bis 1893 noch eine Burg mit einer breiten Schutzmauer. Um die Burg führte eine Gräfte. Eine Senke deutetenoch darauf hin. Die Senke und die alte Umflut des Kleuterbachs wurde durch ein 12 m langes Schemm überbrückt. 1905 wurden die Schemms abgebrochen und dafür der Landweg Hiddingsel-Rödder hergerichtet.\n\nDer Hof Hiddingsel befand sich im Besitz des Domkapitels zu Münster. Auf dem Grund und Boden dieses Hofs ließ das Domkapitel eine kleine Kapelle errichten, die in der Folgezeit Anlass für die Entstehung des Dorfes wurde. Nach 1240 wurde Hiddingsel eine Pfarrei. Jedoch schon Anfang des 16. Jahrhunderts verlor die Pfarrei ihre Selbständigkeit und wurde Rektorat. Erst im Jahre 1861 wurde wieder eine eigene Pfarrei eingerichtet. Der erste Pfarrer war der damalige Rektor Hoffschläger.\n\nDer Hof Hiddingsel wurde im 13. Jahrhundert nach und nach zerstückelt und den sich ansiedelnden Bewohnern überlassen. Als Ersatz kaufte am 18. August 1331 der münsterische Domherr Burkhardt das in der Bauernschaft Rödder gelegene und an Hiddingsel anliegende Lehngut „umso die Rechte der Gutsherrschaft über die Hörigen des Dorfes nach wie vor ausüben zu können.“\n\nDas Kirchdorf Hiddingsel mag im 15. und 16. Jahrhundert etwa 30 bis 40 Häuser gehabt haben. Es blieb in dieser Zeit nicht von Schicksalsschlägen wie Brand, Pest, Krieg und Überflutungen verschont. Innerhalb von 115 Jahren wurde es viermal vollständig vom Feuer zerstört, und zwar in den Jahren 1587 –während des spanisch-niederländischen Krieges (1568 bis 1609) wurde das Dorf „von den Flämischen“ wie von den Holländern in Brand gesteckt –, 1606, 1639 und 1702. Für das Feuer vom 31. Juli 1606 ist folgende Begebenheit übermittelt: Grund des Brandes war diesmal keine kriegerische Auseinandersetzung, sondern ein Ehestreit. Die Frau des Johann Stoberts wollte ihren trunksüchtigen Mann nicht in ihrem Bett dulden, weil sie glaubte, dass er im Wirtshaus zu viel Geld vertrunken hätte. Es gab einen handfesten Krach, der darin gipfelte, dass der Mann –aus seiner Schlafkammer vertrieben –sich mit einer brennenden Kerze in den Hühnerstall setzte und dort einschlief. Die Kerze setzte sein eigenes Haus und in der Folge das ganze Dorf in Brand. Am 8. Dezember 1703 vernichtete ein orkanartiger Sturm die soeben neu erbauten Häuser und den Kirchturm.',
|
||||
style: UITheme.theme.textTheme.bodyLarge,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 200,
|
||||
child: ListView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
children: [
|
||||
Image(
|
||||
image: AssetImage(
|
||||
'assets/images/geschichte/img_geschichte_01.jpg',
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
VerticalDivider(),
|
||||
Image(
|
||||
image: AssetImage(
|
||||
'assets/images/geschichte/img_geschichte_02.jpg',
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
VerticalDivider(),
|
||||
Image(
|
||||
image: AssetImage(
|
||||
'assets/images/geschichte/img_geschichte_03.jpg',
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
VerticalDivider(),
|
||||
Image(
|
||||
image: AssetImage(
|
||||
'assets/images/geschichte/img_geschichte_04.jpg',
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
VerticalDivider(),
|
||||
Image(
|
||||
image: AssetImage(
|
||||
'assets/images/geschichte/img_geschichte_05.jpg',
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
VerticalDivider(),
|
||||
Image(
|
||||
image: AssetImage(
|
||||
'assets/images/geschichte/img_geschichte_06.jpg',
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
VerticalDivider(),
|
||||
Image(
|
||||
image: AssetImage(
|
||||
'assets/images/geschichte/img_geschichte_07.jpg',
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
VerticalDivider(),
|
||||
Image(
|
||||
image: AssetImage(
|
||||
'assets/images/geschichte/img_geschichte_08.jpg',
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
VerticalDivider(),
|
||||
Image(
|
||||
image: AssetImage(
|
||||
'assets/images/geschichte/img_geschichte_09.jpg',
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(UIShapes.paddingMax),
|
||||
child: Text(
|
||||
'Rund 250 Menschen wurden Opfer der Pest von 1636. Nur drei Frauen, die sich zum Schutz gegen die Seuche unter einer kleinen Brücke versteckt hielten, bis die Gefahr vorüber war, sollen von der verheerenden Seuche verschont geblieben sein. Die Brücke heißt noch heute aus dieser Begebenheit „Frauenschemm“. Ein Überbleibsel dieser Zeit ist die noch heute jährlich stattfindende Pestprozession der katholischen Pfarrgemeinde St. Georg zu Hiddingsel. Darüber hinaus erinnert eine im Jahr 2013 errichtete Gedenkstatue an der „Frauenschemm“ Brücke an die vorgenannte Begebenheit.\n\nIm Jahre 1803 fiel das Kirchengut in Hiddingsel der Säkularisation zum Opfer und kam so an die Krone Preußens. Im Jahre 1837 trat die preußische Regierung das Gut an den Herzog von Croÿ ab.\n\In den Jahren 1875, 1881, 1890, 1932, 1945 und 1963 überschwemmte der durch das Dorf fließende Kleuterbach das gesamte Dorf und die Umgebung. Hiddingsel war von der Außenwelt vollkommen abgeschnitten. Die neue Umflut bewahrte das Dorf 1981 vor einer weiteren Hochwasserkatastrophe.\n\nHiddingsel erlebte zwei Gebietsreformen. So wurde das Dorf am 1. Juli 1969 dem Nachbardorf Buldern eingemeindet ehe es im Rahmen einer weiteren Gebietsreform unter Datum vom 1. Januar 1975 ein Ortsteil der Stadt Dülmen wurde.',
|
||||
style: UITheme.theme.textTheme.bodyLarge,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 200,
|
||||
child: ListView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
children: [
|
||||
Image(
|
||||
image: AssetImage(
|
||||
'assets/images/geschichte/img_geschichte_10.jpg',
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
VerticalDivider(),
|
||||
Image(
|
||||
image: AssetImage(
|
||||
'assets/images/geschichte/img_geschichte_11.jpg',
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
VerticalDivider(),
|
||||
Image(
|
||||
image: AssetImage(
|
||||
'assets/images/geschichte/img_geschichte_12.jpg',
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
VerticalDivider(),
|
||||
Image(
|
||||
image: AssetImage(
|
||||
'assets/images/geschichte/img_geschichte_13.jpg',
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
VerticalDivider(),
|
||||
Image(
|
||||
image: AssetImage(
|
||||
'assets/images/geschichte/img_geschichte_14.jpg',
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
VerticalDivider(),
|
||||
Image(
|
||||
image: AssetImage(
|
||||
'assets/images/geschichte/img_geschichte_15.jpg',
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
VerticalDivider(),
|
||||
Image(
|
||||
image: AssetImage(
|
||||
'assets/images/geschichte/img_geschichte_16.jpg',
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
VerticalDivider(),
|
||||
Image(
|
||||
image: AssetImage(
|
||||
'assets/images/geschichte/img_geschichte_17.jpg',
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
VerticalDivider(),
|
||||
Image(
|
||||
image: AssetImage(
|
||||
'assets/images/geschichte/img_geschichte_18.jpg',
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(UIShapes.paddingMax),
|
||||
child: Text(
|
||||
'Seit 1940 verfügt Hiddingsel auch über ein eigenes Ortswappen. „In Silber (Weiß) ein schrägrechter fünflätziger schwarzer Turnierkragen, darüber und darunter je ein schrägrechtes rotes Schwert.“ Der Turnierkragen wurde dem Wappen der Herren „von Tuchdorp“ entnommen. Es handelt sich hier um ein altes Rittergeschlecht. „Bruno von Tuchthorpe“ nennt sich 1330 „Pfarrer von Hiddingsel“, weil er zum Unterhalt der Pfarrstelle verpflichtet war. Die Besitzung der „von Tuchdorp“ ging 1331 durch Kauf auf den Hiddo-Hof über. Die Schwerter im Wappen deuten auf eine alte Gerichtsstätte hin, heute „Dingelke“ genannt. So stehen die im Wappenschild dargestellten Symbole in enger Beziehung zur Gemeinde.',
|
||||
style: UITheme.theme.textTheme.bodyLarge,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Spacer(),
|
||||
Image(
|
||||
image: AssetImage(
|
||||
'assets/images/geschichte/img_geschichte_19.png',
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
Spacer(),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
95
lib/appflow/view/further_pages/vorwort.dart
Normal file
95
lib/appflow/view/further_pages/vorwort.dart
Normal file
@@ -0,0 +1,95 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hiddingsel_app/constants/constant.dart';
|
||||
import 'package:hiddingsel_app/appflow/view/navigation_drawer.dart';
|
||||
|
||||
class VorwortView extends StatelessWidget with NavigationDrawerItem {
|
||||
|
||||
//TODO Low-Prio: Beim nächsten Anfassen durch RichText ersetzen
|
||||
|
||||
@override
|
||||
String get title => 'Vorwort';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => ListView(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(UIShapes.paddingMax, UIShapes.paddingMax, UIShapes.paddingMax, UIShapes.paddingSimple),
|
||||
child: Text(
|
||||
'Ein Gruß des Ortsvorstehers',
|
||||
style: UITheme.theme.textTheme.headlineSmall,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: UIColors.grey5,
|
||||
),
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
0,
|
||||
UIShapes.paddingSimple,
|
||||
UIShapes.paddingMax,
|
||||
UIShapes.paddingSimple,
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: UIShapes.rightRoundedRectangle,
|
||||
child: Image(
|
||||
image: AssetImage(
|
||||
'assets/images/vorwort/img_vorwort.png',
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(UIShapes.paddingMax, UIShapes.paddingMax, UIShapes.paddingMax, 0,),
|
||||
child: Text(
|
||||
'Liebe Gäste,',
|
||||
style: UITheme.theme.textTheme.displayLarge,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(UIShapes.paddingMax),
|
||||
child: Text(
|
||||
'\nals Ortsvorsteher begrüße ich Sie herzlich auf der Internetseite von Hiddingsel. Gerne stellen wir Ihnen unser Heimatdorf, einen Ortsteil der Stadt Dülmen, näher vor.\n\nMit dieser Internetseite wollen wir sowohl den Bewohnern unseres Dorfes als auch Gästen und allen Interessierten möglichst viele Informationen über unser Dorf anbieten. Sie werden auf unserer Internetseite Interessantes und Wissenswertes sowie Beschauliches und Wichtiges aus dem historischen und aktuellen Dorfleben finden.\n\nDie eher ländlich geprägte westfälische Parklandschaft unseres rund 1.700 Einwohner zählenden Dorfes lädt zum Wandern, Rad fahren, Erholen aber auch zum Staunen ein. Das rege und abwechslungsreiche Dorfleben schöpft seine Kraft aus vielen engagierten und kreativen Mitbürgern, die in einer bunten Vereinslandschaft, in bürgerlichen oder kirchlichen Initiativen und Einrichtungen aktiv sind.\n\nNeben einer guten Grundversorgung für das tägliche Leben, besteht das gastronomische Angebot derzeit aus zwei Restaurants. Ein ortsansässiger Kindergarten, eine Grundschule mit Mehrzweckhalle für den Schul-und Vereinssport sowie zahlreiche lebendige Vereine mit unterschiedlichsten Betätigungsfeldern tragen zu einer hervorragenden Wohnqualität bei. Die Hiddingsler verstehen im Übrigen auch zu feiern. Neben zahlreichen Veranstaltungen sind hier besonders das traditionelle jährliche Schützenfest sowie der am 1. Advent stattfindende Weihnachtsmarkt in unserem Dorf zu erwähnen. Selbstverständlich sind zu den verschiedenen Veranstaltungen im Jahresverlauf Gäste aus Nah und Fern immer sehr herzlich eingeladen.\n\nIch bedanke mich für Ihr Interesse und wünsche allen Besuchern viel Spaß beim „Surfen“ durch Hiddingsel. Wenn Sie uns nach Ihrem virtuellen Rundgang durch unser lebenswertes Dorf auch einmal persönlich in Hiddingsel besuchen möchten, würde ich mich darüber sehr freuen. Gerne stehe ich Ihnen für einen Besuch unseres Dorfes mit Rat und Tat zur Seite.\n\nAlso, bis bald bei uns in Hiddingsel', style: UITheme.theme.textTheme.bodyLarge,),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(UIShapes.paddingMax),
|
||||
child: Row(
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius:
|
||||
BorderRadius.circular(UIShapes.paddingDouble),
|
||||
child: Image(
|
||||
image: AssetImage(
|
||||
'assets/images/vorwort/img_vorwort_01.png',
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
width: 110,
|
||||
height: 110,
|
||||
),
|
||||
),
|
||||
VerticalDivider(),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: 'Ihr',
|
||||
style: UITheme.theme.textTheme.bodyLarge,
|
||||
),
|
||||
TextSpan(
|
||||
text: '\nHendrik Clodius\n',
|
||||
style: UITheme.theme.textTheme.headlineSmall?.apply(fontWeightDelta: 1),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'Ortsvorsteher',
|
||||
style: UITheme.theme.textTheme.bodyLarge,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
49
lib/appflow/view/home.dart
Normal file
49
lib/appflow/view/home.dart
Normal file
@@ -0,0 +1,49 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hiddingsel_app/appflow/view/menu_pages/start.dart';
|
||||
import 'package:hiddingsel_app/appflow/view/navigation_drawer.dart' as nd;
|
||||
|
||||
import '../../main.dart';
|
||||
|
||||
class Home extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
PreferredSizeWidget? _appBar;
|
||||
Widget? _body;
|
||||
return StatefulBuilder(
|
||||
builder: (context, setState) {
|
||||
Function(PreferredSizeWidget appBar, Widget body) onChange =
|
||||
(appBar, newBody) => setState(() {
|
||||
_appBar = appBar;
|
||||
_body = newBody;
|
||||
},);
|
||||
if(_appBar == null) {
|
||||
StartView item = StartView(onChange);
|
||||
_appBar = item.getAppBar();
|
||||
_body = item;
|
||||
}
|
||||
return Scaffold(
|
||||
appBar: _appBar,
|
||||
body: _body,
|
||||
drawer: nd.NavigationDrawer(onChange),
|
||||
bottomNavigationBar: nd.NavigationBottomBar(onChange),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
static void openPage(nd.NavigationDrawerItem item, onChange, {String? optionalTitle}) {
|
||||
navigatorKey.currentState?.push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => Scaffold(
|
||||
appBar: item.getAppBar(optionalTitle: optionalTitle),
|
||||
body: item,
|
||||
bottomNavigationBar: nd.NavigationBottomBar((PreferredSizeWidget appBar, Widget body) {
|
||||
Navigator.pop(context);
|
||||
onChange(appBar, body);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
0
lib/appflow/view/interfaces.dart
Normal file
0
lib/appflow/view/interfaces.dart
Normal file
31
lib/appflow/view/menu_pages/article_list.dart
Normal file
31
lib/appflow/view/menu_pages/article_list.dart
Normal file
@@ -0,0 +1,31 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:hiddingsel_app/appflow/controller/articles.dart';
|
||||
import 'package:hiddingsel_app/appflow/model/represented_organisations.dart';
|
||||
import 'package:hiddingsel_app/appflow/view/navigation_drawer.dart';
|
||||
|
||||
import '../../model/articles.dart';
|
||||
import '../further_pages/article.dart';
|
||||
|
||||
class ArticleListView extends StatelessWidget with NavigationDrawerItem{
|
||||
|
||||
final String title;
|
||||
final Stream<List<ArticleModel>> _articleStream;
|
||||
final Function(PreferredSizeWidget appBar, Widget body)? _onChange;
|
||||
|
||||
ArticleListView(this._onChange) : title = 'News', _articleStream = ArticleController.getArticleListStream();
|
||||
ArticleListView.favorites(this._onChange) : title = 'Favoriten', _articleStream = ArticleController.getFavoriteArticleListStream();
|
||||
ArticleListView.search(String searchWord, this._onChange) : title = 'Suche', _articleStream = ArticleController.getSearchResultListStream(searchWord);
|
||||
ArticleListView.organisation(RepresentedOrganisationModel organisation, this._onChange, {scrollController}) : title = 'Organisation', _articleStream = ArticleController.getOrganisationArticleListStream(organisation);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => StreamBuilder(
|
||||
initialData: List<ArticleModel>.empty(),
|
||||
stream: _articleStream,
|
||||
builder: (context, AsyncSnapshot<List<ArticleModel>> snapshot) => buildArticleListView(context, snapshot.data??[])
|
||||
);
|
||||
|
||||
Widget buildArticleListView(BuildContext context, List<ArticleModel> list) => ListView.builder(
|
||||
itemCount: list.length,
|
||||
itemBuilder: (context, index) => ArticleThumbnailView(list[index], _onChange),
|
||||
);
|
||||
}
|
||||
56
lib/appflow/view/menu_pages/buerger_fuer_buerger.dart
Normal file
56
lib/appflow/view/menu_pages/buerger_fuer_buerger.dart
Normal file
@@ -0,0 +1,56 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hiddingsel_app/constants/constant.dart';
|
||||
import 'package:hiddingsel_app/services/environment.dart';
|
||||
|
||||
import '../navigation_drawer.dart';
|
||||
|
||||
class BuergerFuerBuergerView extends StatelessWidget with NavigationDrawerItem {
|
||||
|
||||
//TODO Low-Prio: Beim nächsten Anfassen durch RichText ersetzen
|
||||
|
||||
@override
|
||||
String get title => 'Bürger für Bürger';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Container(
|
||||
padding: EdgeInsets.all(UIShapes.paddingMax),
|
||||
decoration: BoxDecoration(
|
||||
gradient: UIGradiants.red,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Spacer(),
|
||||
Text(
|
||||
'KLICK MICH!',
|
||||
style: UITheme.theme.textTheme.displayMedium,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Spacer(),
|
||||
FloatingActionButton(
|
||||
child: ShaderMask(
|
||||
shaderCallback: (Rect bounds) {
|
||||
return UIGradiants.red.createShader(bounds);
|
||||
},
|
||||
child: Icon(
|
||||
Icons.mail,
|
||||
),
|
||||
),
|
||||
tooltip: 'Mail an Hidd-Box',
|
||||
backgroundColor: UIColors.white,
|
||||
onPressed: (){
|
||||
EnvironmentConnector.openMail('Hidd-Box@hiddingsel.de');
|
||||
},
|
||||
),
|
||||
Spacer(),
|
||||
Text(
|
||||
'HIDD-BOX',
|
||||
style: UITheme.theme.textTheme.titleLarge,
|
||||
),
|
||||
Text(
|
||||
'H\t\tiddingseler\nI\t\tdeen und\nD\t\tdenkanstöße für unser\nD\t\torf\n\nHaben sie Anregungen, Ideen oder Wünsche, die das Dorf betreffen? Dann teilen sie uns diese doch bitte mit! Wir nehmen ihr Anliegen auf und werden es kurzfristig im Vorstand der Dorfgemeinschaft erörtern und ggf. der Delegiertenversammlung als Idee vorstellen. Jeder ernst gemeinte Vorschlag bekommt auch eine entsprechende Rückmeldung.\n\nMit ihrem Vorschlag unterstützen sie uns dabei unser Dorf ein bisschen schöner, attraktiver oder liebenswerter zu machen.\n\nVielen Dank für ihre Unterstützung!\n\nIhr Vorstand der Dorfgemeinschaft Hiddingsel',
|
||||
style: UITheme.theme.textTheme.bodyMedium,
|
||||
),
|
||||
Spacer(),
|
||||
],
|
||||
));
|
||||
}
|
||||
54
lib/appflow/view/menu_pages/companies.dart
Normal file
54
lib/appflow/view/menu_pages/companies.dart
Normal file
@@ -0,0 +1,54 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hiddingsel_app/appflow/model/companies.dart';
|
||||
import 'package:hiddingsel_app/appflow/view/navigation_drawer.dart';
|
||||
|
||||
import '../widgets/string_list.dart';
|
||||
import '../../../constants/constant.dart';
|
||||
import '../widgets/card.dart';
|
||||
|
||||
final List<CompanyModel> _companies = CompanyModel.values;
|
||||
|
||||
class CompanyView extends StatelessWidget {
|
||||
|
||||
final CompanyModel _company;
|
||||
|
||||
CompanyView(this._company);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => ListView(
|
||||
children: [ItemWithPersonAndText.fromCompany(_company),],
|
||||
);
|
||||
}
|
||||
|
||||
class CompanyPagesView extends StatelessWidget with NavigationDrawerItem {
|
||||
|
||||
String get title => 'Dienstleistungen | Firmen';
|
||||
final CompanyModel _company;
|
||||
|
||||
CompanyPagesView(this._company);
|
||||
|
||||
Widget build(BuildContext context) => PageView.builder(
|
||||
controller: PageController(initialPage: _companies.indexOf(_company)),
|
||||
itemCount: _companies.length,
|
||||
itemBuilder: (context, index) => CompanyView(_companies[index]),
|
||||
);
|
||||
}
|
||||
|
||||
class CompanyListView extends StatelessWidget with NavigationDrawerItem {
|
||||
|
||||
@override
|
||||
String get title => 'Dienstleistungen | Firmen';
|
||||
|
||||
final Function(PreferredSizeWidget appBar, Widget body)? _onChange;
|
||||
|
||||
CompanyListView(this._onChange);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => HiddingselMenu(
|
||||
_companies.map((e) => CompanyPagesView(e)).toList(),
|
||||
_onChange,
|
||||
names: _companies.map((e) => e.name).toList(),
|
||||
gradient: UIGradiants.purple
|
||||
);
|
||||
}
|
||||
101
lib/appflow/view/menu_pages/contact.dart
Normal file
101
lib/appflow/view/menu_pages/contact.dart
Normal file
@@ -0,0 +1,101 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hiddingsel_app/constants/constant.dart';
|
||||
|
||||
import '../../../services/environment.dart';
|
||||
import '../navigation_drawer.dart';
|
||||
|
||||
class ContactView extends StatelessWidget with NavigationDrawerItem {
|
||||
|
||||
//TODO Low-Prio: Beim nächsten Anfassen durch RichText ersetzen
|
||||
|
||||
@override
|
||||
String get title => 'Kontakt';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Container(
|
||||
padding: EdgeInsets.all(UIShapes.paddingMax),
|
||||
decoration: BoxDecoration(
|
||||
gradient: UIGradiants.black,
|
||||
),
|
||||
child: ListView(
|
||||
children: <Widget>[
|
||||
Divider(),
|
||||
Text(
|
||||
'Ihr Verein möchte auch in der Hiddingsel-App sichtbar sein? Ein Termin ihres Vereins soll im Dorfkalender erscheinen? Oder sie haben eine generelle Anmerkung zur App?\nDann melden sie sich gerne mit ihrem Anliegen bei uns unter den foldenen E-Mail-Adressen.',
|
||||
textAlign: TextAlign.justify,
|
||||
style: UITheme.theme.textTheme.bodyMedium,
|
||||
),
|
||||
Divider(height: UIShapes.paddingMax),
|
||||
Divider(height: UIShapes.paddingMax),
|
||||
FloatingActionButton(
|
||||
child: Icon(
|
||||
Icons.mail,
|
||||
color: UIColors.white,
|
||||
),
|
||||
tooltip: 'news@hiddingsel.de',
|
||||
backgroundColor: UIColors.black,
|
||||
onPressed: (){
|
||||
EnvironmentConnector.openMail('news@hiddingsel.de');
|
||||
},
|
||||
),
|
||||
Text(
|
||||
'NEWS',
|
||||
textAlign: TextAlign.center,
|
||||
style: UITheme.theme.textTheme.headlineMedium,
|
||||
),
|
||||
Text(
|
||||
'news@hiddingsel.de',
|
||||
textAlign: TextAlign.center,
|
||||
style: UITheme.theme.textTheme.bodyMedium,
|
||||
),
|
||||
Divider(height: UIShapes.paddingMax),
|
||||
Divider(height: UIShapes.paddingMax),
|
||||
FloatingActionButton(
|
||||
child: Icon(
|
||||
Icons.mail,
|
||||
color: UIColors.white,
|
||||
),
|
||||
tooltip: 'termine@hiddingsel.de',
|
||||
backgroundColor: UIColors.black,
|
||||
onPressed: (){
|
||||
EnvironmentConnector.openMail('termine@hiddingsel.de');
|
||||
},
|
||||
),
|
||||
Text(
|
||||
'TERMINE',
|
||||
textAlign: TextAlign.center,
|
||||
style: UITheme.theme.textTheme.headlineMedium,
|
||||
),
|
||||
Text(
|
||||
'termine@hiddingsel.de',
|
||||
textAlign: TextAlign.center,
|
||||
style: UITheme.theme.textTheme.bodyMedium,
|
||||
),
|
||||
Divider(height: UIShapes.paddingMax),
|
||||
Divider(height: UIShapes.paddingMax),
|
||||
FloatingActionButton(
|
||||
child: Icon(
|
||||
Icons.mail,
|
||||
color: UIColors.white,
|
||||
),
|
||||
tooltip: 'app@hiddingsel.de',
|
||||
backgroundColor: UIColors.black,
|
||||
onPressed: (){
|
||||
EnvironmentConnector.openMail('app@hiddingsel.de');
|
||||
},
|
||||
),
|
||||
Text(
|
||||
'APP',
|
||||
textAlign: TextAlign.center,
|
||||
style: UITheme.theme.textTheme.headlineMedium,
|
||||
),
|
||||
Text(
|
||||
'app@hiddingsel.de',
|
||||
textAlign: TextAlign.center,
|
||||
style: UITheme.theme.textTheme.bodyMedium,
|
||||
),
|
||||
Divider(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
42
lib/appflow/view/menu_pages/das_dorf.dart
Normal file
42
lib/appflow/view/menu_pages/das_dorf.dart
Normal file
@@ -0,0 +1,42 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hiddingsel_app/appflow/view/navigation_drawer.dart';
|
||||
import 'package:hiddingsel_app/appflow/view/further_pages/vorwort.dart';
|
||||
|
||||
import '../further_pages/geschichte.dart';
|
||||
import '../widgets/string_list.dart';
|
||||
import '../../../constants/constant.dart';
|
||||
|
||||
List<NavigationDrawerItem> _items = [VorwortView(), GeschichteView()];
|
||||
|
||||
class DasDorfPagesView extends StatelessWidget with NavigationDrawerItem {
|
||||
|
||||
String get title => 'Das Dorf';
|
||||
final NavigationDrawerItem _item;
|
||||
|
||||
DasDorfPagesView(this._item);
|
||||
|
||||
Widget build(BuildContext context) =>
|
||||
PageView.builder(
|
||||
controller: PageController(initialPage: _items.indexOf(_item)),
|
||||
itemCount: _items.length,
|
||||
itemBuilder: (context, index) => _items[index],
|
||||
);
|
||||
}
|
||||
|
||||
class DasDorfListView extends StatelessWidget with NavigationDrawerItem {
|
||||
|
||||
String get title => 'Das Dorf';
|
||||
|
||||
final Function(PreferredSizeWidget appBar, Widget body)? _onChange;
|
||||
|
||||
DasDorfListView(this._onChange);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => HiddingselMenu(
|
||||
_items,
|
||||
_onChange,
|
||||
names: _items.map((e) => e.title).toList(),
|
||||
gradient: UIGradiants.green,
|
||||
);
|
||||
}
|
||||
99
lib/appflow/view/menu_pages/imprint.dart
Normal file
99
lib/appflow/view/menu_pages/imprint.dart
Normal file
@@ -0,0 +1,99 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hiddingsel_app/constants/constant.dart';
|
||||
|
||||
import '../navigation_drawer.dart';
|
||||
|
||||
class ImprintView extends StatelessWidget with NavigationDrawerItem {
|
||||
|
||||
//TODO Low-Prio: Beim nächsten Anfassen durch RichText ersetzen
|
||||
|
||||
@override
|
||||
String get title => 'Impressum';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: UIShapes.paddingMax,),
|
||||
child: ListView(
|
||||
children: <Widget>[
|
||||
Divider(),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AboutDialog(
|
||||
//applicationIcon: ImageIcon(AssetImage(Constants.hiddingselIconAsset)),
|
||||
applicationName: 'Hiddingsel-App: Lizenzen',
|
||||
applicationVersion: 'April 2021',
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
'Klicken Sie hier, um die verwendeten Lizenzen anzuzeigen.',
|
||||
style: UITheme.theme.textTheme.headlineSmall
|
||||
?.apply(color: UIColors.grey4),
|
||||
),
|
||||
),
|
||||
Divider(),
|
||||
Text(
|
||||
'Diese App wurde vom Projektteam "Digitales Hiddingsel" konzipiert, inhaltlich ausgestaltet und umgesetzt.\n\nBei inhaltlichen und technischen Fragen wenden Sie sich bitte an diese Mail:\n\napp@hiddingsel.de\n',
|
||||
textAlign: TextAlign.justify,
|
||||
style: UITheme.theme.textTheme.bodyLarge,
|
||||
),
|
||||
Text(
|
||||
'\nProjektleitung:\nTim Marquardt\nSoftwareentwicklung:\nNils Weber\n',
|
||||
style: UITheme.theme.textTheme.bodyLarge,
|
||||
),
|
||||
Text(
|
||||
'\nUrheberrecht\n',
|
||||
style:
|
||||
UITheme.theme.textTheme.bodyLarge?.apply(fontWeightDelta: 1),
|
||||
),
|
||||
Text(
|
||||
'Diese App ist urheberrechtlich geschützt. Es ist verboten diese App oder Teile von ihr (wie Bilder und Texte) zu kopieren und zu vervielfältigen. Das Urheberrecht für die Gestaltung, Fotos, Grafiken und Texte liegt bei dem Verein, wenn nicht für Teile der App an anderer Stelle ein anderer Urheber genannt wird. Alle Rechte, auch die der fotomechanischen Wiedergabe, der Vervielfältigung und der Verbreitung mittels besonderer Verfahren (zum Beispiel Datenverarbeitung, Datenträger und Datennetze), auch teilweise, behält sich der Urheber vor.\n',
|
||||
textAlign: TextAlign.justify,
|
||||
style: UITheme.theme.textTheme.bodyLarge,
|
||||
),
|
||||
Text(
|
||||
'\nInhalt des Webangebotes\n',
|
||||
style:
|
||||
UITheme.theme.textTheme.bodyLarge?.apply(fontWeightDelta: 1),
|
||||
),
|
||||
Text(
|
||||
'Der Appbetreiber ist bemüht, sein Webangebot stets aktuell und inhaltlich richtig sowie vollständig anzubieten. Dennoch ist das Auftreten von Fehlern nicht völlig auszuschließen. Er übernimmt keine Haftung für die Aktualität, die inhaltliche Richtigkeit sowie für die Vollständigkeit der im Webangebot eingestellten Informationen, es sei denn die Fehler wurden vorsätzlich oder grob fahrlässig aufgenommen. Dies bezieht sich auf eventuelle Schäden materieller oder ideeller Art Dritter, die durch die Nutzung dieses Webangebotes verursacht wurden.\n',
|
||||
textAlign: TextAlign.justify,
|
||||
style: UITheme.theme.textTheme.bodyLarge,
|
||||
),
|
||||
Text(
|
||||
'\nExterne Verweise und Links\n',
|
||||
style:
|
||||
UITheme.theme.textTheme.bodyLarge?.apply(fontWeightDelta: 1),
|
||||
),
|
||||
Text(
|
||||
'Der Appbetreiber hat in seiner App Links zu Seiten im Internet gelegt, deren Inhalt und Aktualisierung nicht seinem Einflussbereich unterliegt. Für alle diese Links gilt:\n„Der Appbetreiber hat keinen Einfluss auf Gestaltung und Inhalte fremder Internetseiten. Er distanziert sich daher von allen fremden Inhalten, auch wenn von Seiten des Betreibers auf diese externen Seiten ein Link gesetzt wurde.“\nDiese Erklärung gilt für alle in dieser App angezeigten Links und für alle Inhalte der Seiten, zu denen Links führen.\n',
|
||||
textAlign: TextAlign.justify,
|
||||
style: UITheme.theme.textTheme.bodyLarge,
|
||||
),
|
||||
Text(
|
||||
'\nDatenschutz\n',
|
||||
style: UITheme.theme.textTheme.bodyLarge,
|
||||
),
|
||||
Text(
|
||||
'Sofern innerhalb des Internetangebotes die Möglichkeit der Eingabe von persönlichen Daten (E-Mailadressen, Namen, Anschriften) besteht, erfolgt diese freiwillig. Der Seitenbetreiber erklärt ausdrücklich, dass er diese Daten nicht an Dritte weitergibt. Sie werden nur für den vom Benutzer bestimmten Zweck erhoben, wie z.B. Zusenden von Infomaterial per Mail oder Post oder zur Beantwortung von Anfragen an den Verein.\n',
|
||||
textAlign: TextAlign.justify,
|
||||
style: UITheme.theme.textTheme.bodyLarge,
|
||||
),
|
||||
Text(
|
||||
'\nRechtswirksamkeit\n',
|
||||
style:
|
||||
UITheme.theme.textTheme.bodyLarge?.apply(fontWeightDelta: 1),
|
||||
),
|
||||
Text(
|
||||
'Dieser Haftungsausschluss ist Teil des Internetangebotes www.hiddingsel.de. Sofern einzelne Formulierungen oder Teile dieses Textes der geltenden Rechtslage nicht mehr oder nicht mehr vollständig entsprechen, bleiben die übrigen Teile dieser Erklärung davon unberührt.',
|
||||
textAlign: TextAlign.justify,
|
||||
style: UITheme.theme.textTheme.bodyLarge,
|
||||
),
|
||||
Divider(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
101
lib/appflow/view/menu_pages/organisations.dart
Normal file
101
lib/appflow/view/menu_pages/organisations.dart
Normal file
@@ -0,0 +1,101 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hiddingsel_app/appflow/model/represented_organisations.dart';
|
||||
import 'package:hiddingsel_app/appflow/view/navigation_drawer.dart';
|
||||
import '../../../constants/constant.dart';
|
||||
import '../../controller/articles.dart';
|
||||
import '../../model/articles.dart';
|
||||
import '../further_pages/article.dart';
|
||||
import '../widgets/card.dart';
|
||||
import '../widgets/string_list.dart';
|
||||
|
||||
final List<RepresentedOrganisationModel> _organisations =
|
||||
RepresentedOrganisationModel.values;
|
||||
|
||||
class OrganisationView extends StatelessWidget {
|
||||
final RepresentedOrganisationModel _organisation;
|
||||
final Function(PreferredSizeWidget appBar, Widget body)? _onChange;
|
||||
|
||||
OrganisationView(this._organisation, this._onChange, {Key? key})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => StreamBuilder(
|
||||
initialData: List<ArticleModel>.empty(),
|
||||
stream:
|
||||
ArticleController.getOrganisationArticleListStream(_organisation),
|
||||
builder: (context, AsyncSnapshot<List<ArticleModel>> snapshot) =>
|
||||
CustomScrollView(
|
||||
slivers: [
|
||||
SliverPersistentHeader(
|
||||
delegate: OrganisationSliver(_organisation),
|
||||
floating: true,
|
||||
),
|
||||
SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) => ArticleThumbnailView(
|
||||
(snapshot.data ?? [])[index], _onChange),
|
||||
childCount: snapshot.data?.length ?? 0,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
class OrganisationSliver extends SliverPersistentHeaderDelegate {
|
||||
|
||||
final RepresentedOrganisationModel _organisation;
|
||||
OrganisationSliver(this._organisation, {Key? key});
|
||||
|
||||
@override
|
||||
double get maxExtent => 550;
|
||||
|
||||
@override
|
||||
double get minExtent => 550;
|
||||
|
||||
@override
|
||||
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) => true;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) =>
|
||||
Container(
|
||||
color: UIColors.white,
|
||||
child: ItemWithPersonAndText.fromOrganisation(_organisation),
|
||||
);
|
||||
}
|
||||
|
||||
class OrganisationPagesView extends StatelessWidget with NavigationDrawerItem {
|
||||
@override
|
||||
String get title => 'Organisationen | Vereine';
|
||||
|
||||
final RepresentedOrganisationModel _organisation;
|
||||
final Function(PreferredSizeWidget appBar, Widget body)? _onChange;
|
||||
|
||||
OrganisationPagesView(this._organisation, this._onChange);
|
||||
|
||||
Widget build(BuildContext context) => PageView.builder(
|
||||
controller:
|
||||
PageController(initialPage: _organisations.indexOf(_organisation)),
|
||||
itemCount: _organisations.length,
|
||||
itemBuilder: (context, index) =>
|
||||
OrganisationView(_organisations[index], _onChange),
|
||||
);
|
||||
}
|
||||
|
||||
class OrganisationListView extends StatelessWidget with NavigationDrawerItem {
|
||||
@override
|
||||
String get title => 'Organisationen | Vereine';
|
||||
|
||||
final Function(PreferredSizeWidget appBar, Widget body)? _onChange;
|
||||
|
||||
OrganisationListView(this._onChange);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => HiddingselMenu(
|
||||
_organisations.map((e) => OrganisationPagesView(e, _onChange)).toList(),
|
||||
_onChange,
|
||||
names: _organisations.map((e) => e.name).toList(),
|
||||
gradient: UIGradiants.yellow,
|
||||
);
|
||||
}
|
||||
60
lib/appflow/view/menu_pages/pois.dart
Normal file
60
lib/appflow/view/menu_pages/pois.dart
Normal file
@@ -0,0 +1,60 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hiddingsel_app/appflow/model/pois.dart';
|
||||
import 'package:hiddingsel_app/appflow/view/widgets/gallery.dart';
|
||||
import 'package:hiddingsel_app/appflow/view/widgets/string_list.dart';
|
||||
import 'package:hiddingsel_app/appflow/view/navigation_drawer.dart';
|
||||
|
||||
import '../../../constants/constant.dart';
|
||||
import '../widgets/card.dart';
|
||||
|
||||
final List<PointOfInterestModel> _pois = PointOfInterestModel.values;
|
||||
|
||||
class PoiView extends StatelessWidget {
|
||||
final PointOfInterestModel _poi;
|
||||
|
||||
const PoiView(this._poi, {Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => ListView(
|
||||
children: [
|
||||
ItemWithText.fromPoi(_poi),
|
||||
SizedBox(
|
||||
height: 200,
|
||||
child: HiddingselGallery(
|
||||
_poi.otherImages.map((e) => e.image).toList()),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
class PoiPagesView extends StatelessWidget with NavigationDrawerItem {
|
||||
final PointOfInterestModel _poi;
|
||||
|
||||
PoiPagesView(this._poi);
|
||||
|
||||
@override
|
||||
String get title => 'Sehenswertes';
|
||||
|
||||
Widget build(BuildContext context) => PageView.builder(
|
||||
controller: PageController(initialPage: _pois.indexOf(_poi)),
|
||||
itemCount: _pois.length,
|
||||
itemBuilder: (context, index) => PoiView(_pois[index]),
|
||||
);
|
||||
}
|
||||
|
||||
class PoiListView extends StatelessWidget with NavigationDrawerItem {
|
||||
|
||||
@override
|
||||
String get title => 'Sehenswertes';
|
||||
|
||||
final Function(PreferredSizeWidget appBar, Widget body)? _onChange;
|
||||
|
||||
PoiListView(this._onChange);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => HiddingselMenu(
|
||||
_pois.map((e) => PoiPagesView(e)).toList(),
|
||||
_onChange,
|
||||
names: _pois.map((e) => e.name).toList(),
|
||||
gradient: UIGradiants.blue);
|
||||
}
|
||||
283
lib/appflow/view/menu_pages/search.dart
Normal file
283
lib/appflow/view/menu_pages/search.dart
Normal file
@@ -0,0 +1,283 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hiddingsel_app/appflow/controller/articles.dart';
|
||||
import 'package:hiddingsel_app/appflow/model/companies.dart' as enu;
|
||||
import 'package:hiddingsel_app/appflow/view/further_pages/article.dart';
|
||||
import 'package:hiddingsel_app/constants/constant.dart';
|
||||
import 'package:hiddingsel_app/appflow/model/represented_organisations.dart' as enu2;
|
||||
import 'package:hiddingsel_app/appflow/model/articles.dart';
|
||||
import 'package:hiddingsel_app/appflow/view/menu_pages/companies.dart';
|
||||
import 'package:hiddingsel_app/appflow/view/menu_pages/organisations.dart';
|
||||
import 'package:hiddingsel_app/appflow/view/menu_pages/das_dorf.dart';
|
||||
import 'package:hiddingsel_app/appflow/view/menu_pages/pois.dart';
|
||||
|
||||
import '../../model/pois.dart';
|
||||
import '../home.dart';
|
||||
import 'article_list.dart';
|
||||
import '../navigation_drawer.dart';
|
||||
|
||||
class Search extends StatelessWidget with NavigationDrawerItem {
|
||||
|
||||
String get title => 'Suche';
|
||||
final Function(PreferredSizeWidget appBar, Widget body) _onChange;
|
||||
|
||||
const Search(this._onChange);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
TextEditingController controller = new TextEditingController();
|
||||
return StatefulBuilder(
|
||||
builder: (context, setState) {
|
||||
if (controller.value.text.isEmpty) {
|
||||
return buildSearch(controller, setState, context);
|
||||
} else {
|
||||
return buildResults(controller, setState, context);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildSearch(
|
||||
TextEditingController controller, setState, BuildContext context) =>
|
||||
LayoutBuilder(
|
||||
builder: (context, constraints) => Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(gradient: UIGradiants.red),
|
||||
width: constraints.maxWidth,
|
||||
height: constraints.maxHeight,
|
||||
),
|
||||
Positioned(
|
||||
top: constraints.maxHeight * 0.6,
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: constraints.maxWidth * 0.8,
|
||||
height: UIShapes.paddingMax,
|
||||
child: TextField(
|
||||
onSubmitted: (s) {
|
||||
setState(() {
|
||||
controller = controller;
|
||||
});
|
||||
},
|
||||
textInputAction: TextInputAction.search,
|
||||
controller: controller,
|
||||
autofocus: true,
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
hintText: 'SUCHEN',
|
||||
hintStyle: UITheme.theme.textTheme.displayMedium?.apply(
|
||||
color: UIColors.white.withAlpha(100),
|
||||
),
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: UIColors.white,
|
||||
fontSize: UIShapes.paddingMax,
|
||||
),
|
||||
),
|
||||
),
|
||||
Divider(),
|
||||
FloatingActionButton(
|
||||
backgroundColor: UIColors.white,
|
||||
child: Icon(
|
||||
Icons.search,
|
||||
color: UIColors.grey5,
|
||||
),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
controller = controller;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Widget buildResults(
|
||||
TextEditingController controller, setState, BuildContext context) {
|
||||
String searchWord = controller.value.text;
|
||||
|
||||
List<enu2.RepresentedOrganisationModel> orgas = enu2.RepresentedOrganisationModel.values
|
||||
.where((element) =>
|
||||
element.tags.any((alias) => alias.toLowerCase().contains(searchWord.toLowerCase())))
|
||||
.toList();
|
||||
List<enu.CompanyModel> comps = enu.CompanyModel.values
|
||||
.where((element) =>
|
||||
element.name.toLowerCase().contains(searchWord.toLowerCase()))
|
||||
.toList();
|
||||
List<PointOfInterestModel> pois = PointOfInterestModel.values
|
||||
.where((element) =>
|
||||
element.name.toLowerCase().contains(searchWord.toLowerCase()))
|
||||
.toList();
|
||||
List others = ['Vorwort', 'Geschichte']
|
||||
.where((element) =>
|
||||
element.toLowerCase().contains(searchWord.toLowerCase()))
|
||||
.toList();
|
||||
|
||||
List<Widget> children = [];
|
||||
if (orgas.isNotEmpty) {
|
||||
children.addAll([
|
||||
Text(
|
||||
OrganisationListView(null).title.toUpperCase(),
|
||||
style: UITheme.theme.textTheme.headlineMedium,
|
||||
),
|
||||
Divider(),
|
||||
]);
|
||||
for (enu2.RepresentedOrganisationModel o in orgas) {
|
||||
children.addAll([
|
||||
GestureDetector(
|
||||
child: Text(
|
||||
'... ' + o.name.toUpperCase(),
|
||||
style: UITheme.theme.textTheme.titleLarge,
|
||||
),
|
||||
onTap: () {
|
||||
Home.openPage(OrganisationPagesView(o, _onChange), _onChange);
|
||||
},
|
||||
),
|
||||
Divider()
|
||||
]);
|
||||
}
|
||||
}
|
||||
if (comps.isNotEmpty) {
|
||||
children.addAll([
|
||||
Text(
|
||||
CompanyListView(null).title.toUpperCase(),
|
||||
style: UITheme.theme.textTheme.headlineMedium,
|
||||
),
|
||||
Divider(),
|
||||
]);
|
||||
for (enu.CompanyModel o in comps) {
|
||||
children.addAll([
|
||||
GestureDetector(
|
||||
child: Text(
|
||||
'... ' + o.name.toUpperCase(),
|
||||
style: UITheme.theme.textTheme.titleLarge,
|
||||
),
|
||||
onTap: () {
|
||||
Home.openPage(CompanyPagesView(o), _onChange);
|
||||
},
|
||||
),
|
||||
Divider()
|
||||
]);
|
||||
}
|
||||
}
|
||||
if (pois.isNotEmpty) {
|
||||
children.addAll([
|
||||
Text(
|
||||
PoiListView(null).title.toUpperCase(),
|
||||
style: UITheme.theme.textTheme.headlineMedium,
|
||||
),
|
||||
Divider(),
|
||||
]);
|
||||
for (PointOfInterestModel o in pois) {
|
||||
children.addAll([
|
||||
GestureDetector(
|
||||
child: Text(
|
||||
'... ' + o.name.toUpperCase(),
|
||||
style: UITheme.theme.textTheme.titleLarge,
|
||||
),
|
||||
onTap: () {
|
||||
Home.openPage(PoiPagesView(o), _onChange);
|
||||
},
|
||||
),
|
||||
Divider()
|
||||
]);
|
||||
}
|
||||
}
|
||||
if (others.isNotEmpty) {
|
||||
children.addAll([
|
||||
Text(
|
||||
DasDorfListView(null).title.toUpperCase(),
|
||||
style: UITheme.theme.textTheme.headlineMedium,
|
||||
),
|
||||
Divider(),
|
||||
]);
|
||||
for (String o in others) {
|
||||
children.addAll([
|
||||
GestureDetector(
|
||||
child: Text(
|
||||
'... ' + o.toUpperCase(),
|
||||
style: UITheme.theme.textTheme.titleLarge,
|
||||
),
|
||||
onTap: () {
|
||||
Home.openPage(DasDorfListView(_onChange), _onChange);
|
||||
},
|
||||
),
|
||||
Divider()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return FutureBuilder(
|
||||
future: ArticleController.getSearchResultListStream(
|
||||
searchWord).first,
|
||||
builder: (context, AsyncSnapshot snapshot) {
|
||||
if (snapshot.data != null) {
|
||||
List<ArticleModel> arts = snapshot.data;
|
||||
if (arts.isNotEmpty) {
|
||||
List<Widget> news = [
|
||||
Text(
|
||||
ArticleListView(null).title.toUpperCase(),
|
||||
style: UITheme.theme.textTheme.headlineMedium,
|
||||
),
|
||||
Divider(),
|
||||
];
|
||||
for (ArticleModel o in arts) {
|
||||
news.addAll([
|
||||
GestureDetector(
|
||||
child: Text(
|
||||
'... ' + o.title.toUpperCase(),
|
||||
style: UITheme.theme.textTheme.titleLarge,
|
||||
),
|
||||
onTap: () {
|
||||
Home.openPage(ArticleView(o), _onChange);
|
||||
},
|
||||
),
|
||||
Divider(),
|
||||
]);
|
||||
}
|
||||
news.addAll(children);
|
||||
children = news;
|
||||
}
|
||||
}
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.all(UIShapes.paddingMax),
|
||||
decoration: BoxDecoration(gradient: UIGradiants.red),
|
||||
child: ListView(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: UIShapes.paddingMax,
|
||||
child: Text(searchWord.toUpperCase(),
|
||||
textAlign: TextAlign.center,
|
||||
style: UITheme.theme.textTheme.displayMedium),
|
||||
),
|
||||
Divider(),
|
||||
FloatingActionButton(
|
||||
backgroundColor: UIColors.white,
|
||||
child: Icon(
|
||||
Icons.cancel_outlined,
|
||||
color: UIColors.grey5,
|
||||
),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
controller.clear();
|
||||
});
|
||||
},
|
||||
),
|
||||
Divider(),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: children,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
135
lib/appflow/view/menu_pages/settings.dart
Normal file
135
lib/appflow/view/menu_pages/settings.dart
Normal file
@@ -0,0 +1,135 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hiddingsel_app/appflow/controller/events.dart';
|
||||
import 'package:hiddingsel_app/constants/constant.dart';
|
||||
import 'package:hiddingsel_app/appflow/model/event_organisations.dart';
|
||||
import 'package:hiddingsel_app/appflow/model/represented_organisations.dart';
|
||||
import 'package:hiddingsel_app/packages/list_view_extension/colum_extension.dart';
|
||||
import 'package:hiddingsel_app/services/storage.dart';
|
||||
import 'package:hiddingsel_app/packages/icon_switch/icon_switch.dart';
|
||||
|
||||
import '../navigation_drawer.dart';
|
||||
import '../../model/topics.dart';
|
||||
import '../widgets/time_picker.dart';
|
||||
|
||||
class SettingsView extends StatelessWidget with NavigationDrawerItem {
|
||||
|
||||
@override
|
||||
String get title => 'Einstellungen';
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView(
|
||||
padding: EdgeInsets.all(UIShapes.paddingDouble),
|
||||
children: [
|
||||
buildNewsNotificationTile(RepresentedOrganisationModel.values),
|
||||
//buildFavorizationTile(RepresentedOrganisationModel.values),
|
||||
buildEventNotificationTile(EventOrganisationModel.values),
|
||||
buildNotificationTimeTile(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
ExpansionTile buildNewsNotificationTile(List<PushNotificationTopicModel> topics) {
|
||||
return ExpansionTile(
|
||||
title: Text(
|
||||
'News-Benachrichtigungen'.toUpperCase(),
|
||||
style: UITheme.theme.textTheme.headlineSmall,
|
||||
),
|
||||
children: [
|
||||
ColumnExtension.builder(
|
||||
itemBuilder: (context, index) => ListTile(
|
||||
leading: IconSwitch(
|
||||
topics[index].subscribe,
|
||||
initFavorite: topics[index].subscribed,
|
||||
gradientColor:UIGradiants.yellow,
|
||||
iconFavorite: Icons.notifications_active,
|
||||
iconDefavorite: Icons.notifications_outlined,
|
||||
),
|
||||
title: Text(
|
||||
topics[index].name.toUpperCase(),
|
||||
style: UITheme.theme.textTheme.headlineSmall,
|
||||
),
|
||||
),
|
||||
itemCount: topics.length,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
ExpansionTile buildFavorizationTile(
|
||||
List<RepresentedOrganisationModel> organisations) {
|
||||
return ExpansionTile(
|
||||
title: Text(
|
||||
'Favoriten bearbeiten'.toUpperCase(),
|
||||
style: UITheme.theme.textTheme.headline5,
|
||||
),
|
||||
children: [
|
||||
ColumnExtension.builder(
|
||||
itemBuilder: (context, index) => ListTile(
|
||||
leading: IconSwitch(
|
||||
organisations[index].favorize,
|
||||
initFavorite: organisations[index].favorized,
|
||||
gradientColor: UIGradiants.yellow,
|
||||
),
|
||||
title: Text(
|
||||
organisations[index].name.toUpperCase(),
|
||||
style: UITheme.theme.textTheme.headline5,
|
||||
),
|
||||
),
|
||||
itemCount: organisations.length,
|
||||
),
|
||||
],
|
||||
);
|
||||
}*/
|
||||
|
||||
ExpansionTile buildEventNotificationTile(
|
||||
List<EventOrganisationModel> organisations) {
|
||||
return ExpansionTile(
|
||||
title: Text(
|
||||
'Termin-Benachrichtigungen'.toUpperCase(),
|
||||
style: UITheme.theme.textTheme.headlineSmall,
|
||||
),
|
||||
children: [
|
||||
ColumnExtension.builder(
|
||||
itemBuilder: (context, index) => ListTile(
|
||||
leading: IconSwitch(
|
||||
(b) => organisations[index].allowEventNotification(b),
|
||||
initFavorite: organisations[index].eventNotificationAllowed,
|
||||
gradientColor: UIGradiants.yellow,
|
||||
iconFavorite: Icons.notifications_active,
|
||||
iconDefavorite: Icons.calendar_today,
|
||||
),
|
||||
title: Text(
|
||||
organisations[index].name.toUpperCase(),
|
||||
style: UITheme.theme.textTheme.headlineSmall,
|
||||
),
|
||||
),
|
||||
itemCount: organisations.length,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildNotificationTimeTile() {
|
||||
return ExpansionTile(
|
||||
title: Text(
|
||||
'Benachrichtungszeit Termine'.toUpperCase(),
|
||||
style: UITheme.theme.textTheme.headlineSmall,
|
||||
),
|
||||
children: [
|
||||
LayoutBuilder(builder: (context, constraints) => FutureBuilder(
|
||||
future: SettingsConnector.getInt(SystemStrings.keyAlertTime, 1*60*60*1000),
|
||||
builder: (context, AsyncSnapshot snapshot) => HiddingselTimePicker(
|
||||
Duration(milliseconds: snapshot.data??1*60*60*1000), (duration) async {
|
||||
await SettingsConnector.setInt(SystemStrings.keyAlertTime, duration.inMilliseconds);
|
||||
await EventController.scheduleNotificationsBySettings();
|
||||
}, width: constraints.maxWidth, key: UniqueKey())
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
59
lib/appflow/view/menu_pages/start.dart
Normal file
59
lib/appflow/view/menu_pages/start.dart
Normal file
@@ -0,0 +1,59 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hiddingsel_app/constants/constant.dart';
|
||||
import 'package:hiddingsel_app/appflow/view/menu_pages/search.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import '../navigation_drawer.dart';
|
||||
|
||||
class StartView extends StatelessWidget with NavigationDrawerItem {
|
||||
|
||||
String get title => 'Start';
|
||||
|
||||
final Function(PreferredSizeWidget appBar, Widget body) _onChange;
|
||||
|
||||
const StartView(onChange) : _onChange = onChange;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => LayoutBuilder(
|
||||
builder: (context, constraints) => Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: constraints.maxWidth,
|
||||
height: constraints.maxHeight,
|
||||
child: Image(
|
||||
image: AssetImage('assets/images/start/img_start_${NumberFormat("00", "en_US").format(Random().nextInt(12)+1)}.png'),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: constraints.maxHeight * 0.6,
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
'WILLKOMMEN!',
|
||||
style: UITheme.theme.textTheme.displayMedium,
|
||||
),
|
||||
Divider(),
|
||||
FloatingActionButton(
|
||||
backgroundColor: UIColors.white,
|
||||
child: Icon(
|
||||
Icons.search,
|
||||
color: UIColors.grey5,
|
||||
),
|
||||
onPressed: () {
|
||||
_onChange(
|
||||
Search(_onChange).getAppBar(),
|
||||
Search(_onChange),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
157
lib/appflow/view/navigation_drawer.dart
Normal file
157
lib/appflow/view/navigation_drawer.dart
Normal file
@@ -0,0 +1,157 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hiddingsel_app/appflow/view/menu_pages/article_list.dart';
|
||||
import 'package:hiddingsel_app/appflow/view/menu_pages/pois.dart';
|
||||
import 'package:hiddingsel_app/appflow/view/menu_pages/companies.dart';
|
||||
import 'package:hiddingsel_app/appflow/view/menu_pages/das_dorf.dart';
|
||||
import 'package:hiddingsel_app/todo/calendar.dart';
|
||||
import 'package:hiddingsel_app/constants/constant.dart';
|
||||
|
||||
import 'menu_pages/contact.dart';
|
||||
import 'menu_pages/search.dart';
|
||||
import 'menu_pages/buerger_fuer_buerger.dart';
|
||||
import 'menu_pages/organisations.dart';
|
||||
import 'menu_pages/settings.dart';
|
||||
import 'widgets/app_bar.dart';
|
||||
import 'menu_pages/imprint.dart';
|
||||
|
||||
class NavigationDrawer extends StatelessWidget with NavigationDrawerItem {
|
||||
final Function(PreferredSizeWidget appBar, Widget body) _onChange;
|
||||
|
||||
const NavigationDrawer(this._onChange);
|
||||
|
||||
@override
|
||||
String get title => 'Menü';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Scaffold(
|
||||
appBar: this.getAppBar(),
|
||||
body: Container(
|
||||
padding: EdgeInsets.all(UIShapes.paddingMax),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
_getListTile(Search(_onChange), null, context),
|
||||
Spacer(
|
||||
flex: 1,
|
||||
),
|
||||
_getListTile(ArticleListView(_onChange), null, context),
|
||||
Spacer(
|
||||
flex: 1,
|
||||
),
|
||||
_getListTile(CalendarListPage(), null, context),
|
||||
Spacer(
|
||||
flex: 3,
|
||||
),
|
||||
_getListTile(DasDorfListView(_onChange), Icons.arrow_forward_ios, context),
|
||||
Spacer(
|
||||
flex: 1,
|
||||
),
|
||||
_getListTile(PoiListView(_onChange), Icons.arrow_forward_ios, context),
|
||||
Spacer(
|
||||
flex: 1,
|
||||
),
|
||||
_getListTile(OrganisationListView(_onChange), Icons.arrow_forward_ios, context),
|
||||
Spacer(
|
||||
flex: 1,
|
||||
),
|
||||
_getListTile(CompanyListView(_onChange), Icons.arrow_forward_ios, context),
|
||||
Spacer(
|
||||
flex: 1,
|
||||
),
|
||||
_getListTile(BuergerFuerBuergerView(), null, context),
|
||||
Spacer(
|
||||
flex: 3,
|
||||
),
|
||||
_getListTile(SettingsView(), null, context),
|
||||
Spacer(
|
||||
flex: 1,
|
||||
),
|
||||
_getListTile(ImprintView(), null, context),
|
||||
Spacer(
|
||||
flex: 1,
|
||||
),
|
||||
_getListTile(ContactView(), null, context),
|
||||
Spacer(
|
||||
flex: 7,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Widget _getListTile(NavigationDrawerItem item, IconData? icon, BuildContext context) =>
|
||||
GestureDetector(
|
||||
child: Row(children:
|
||||
[
|
||||
Expanded(
|
||||
child:Text(
|
||||
item.title.toUpperCase(),
|
||||
style:
|
||||
UITheme.theme.textTheme.headlineSmall?.apply(color: UIColors.grey4),
|
||||
),),
|
||||
Icon(icon, color: UIColors.grey4,),
|
||||
]
|
||||
),
|
||||
onTap: () {
|
||||
_onChange(
|
||||
item.getAppBar(),
|
||||
item,
|
||||
);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
class NavigationBottomBar extends StatelessWidget {
|
||||
final Function(PreferredSizeWidget appBar, Widget body) _onChange;
|
||||
|
||||
const NavigationBottomBar(onChange) : _onChange = onChange;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Container(
|
||||
padding: EdgeInsets.fromLTRB(UIShapes.paddingMax, UIShapes.paddingMax,
|
||||
UIShapes.paddingMax, UIShapes.paddingMax),
|
||||
color: UIColors.grey6,
|
||||
child: SafeArea( child: Row(
|
||||
children: [
|
||||
Spacer(),
|
||||
_getListTile(ArticleListView(_onChange)),
|
||||
Spacer(),
|
||||
Text(
|
||||
'|',
|
||||
style: UITheme.theme.textTheme.titleLarge,
|
||||
),
|
||||
Spacer(),
|
||||
_getListTile(CalendarListPage()),
|
||||
Spacer(),
|
||||
Text(
|
||||
'|',
|
||||
style: UITheme.theme.textTheme.titleLarge,
|
||||
),
|
||||
Spacer(),
|
||||
_getListTile(ContactView()),
|
||||
Spacer(),
|
||||
],
|
||||
),
|
||||
),);
|
||||
|
||||
Widget _getListTile(NavigationDrawerItem item) =>
|
||||
GestureDetector(
|
||||
child: Text(
|
||||
item.title.toUpperCase(),
|
||||
style: UITheme.theme.textTheme.titleLarge,
|
||||
),
|
||||
onTap: () {
|
||||
_onChange(
|
||||
item.getAppBar(),
|
||||
item,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
mixin NavigationDrawerItem on Widget {
|
||||
String get title;
|
||||
|
||||
PreferredSizeWidget getAppBar({String? optionalTitle}) => HiddingselAppBar(Text(optionalTitle??title.toUpperCase()));
|
||||
}
|
||||
46
lib/appflow/view/widgets/app_bar.dart
Normal file
46
lib/appflow/view/widgets/app_bar.dart
Normal file
@@ -0,0 +1,46 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hiddingsel_app/constants/constant.dart';
|
||||
|
||||
import '../home.dart';
|
||||
|
||||
class HiddingselAppBar extends PreferredSize {
|
||||
final Widget title;
|
||||
|
||||
HiddingselAppBar(this.title)
|
||||
: super(child: title, preferredSize: Size.fromHeight(kToolbarHeight));
|
||||
|
||||
@override
|
||||
Size get preferredSize => Size.fromHeight(88);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => SafeArea(
|
||||
child: Container(
|
||||
height: preferredSize.height,
|
||||
color: UIColors.white,
|
||||
child: Column(
|
||||
children: [
|
||||
Flexible(
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => Home()),
|
||||
);
|
||||
},
|
||||
child: Image(
|
||||
image: AssetImage(
|
||||
'assets/other/appbar.png',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Divider(),
|
||||
AppBar(
|
||||
title: title,
|
||||
backgroundColor: UIColors.grey6,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
19
lib/appflow/view/widgets/button.dart
Normal file
19
lib/appflow/view/widgets/button.dart
Normal file
@@ -0,0 +1,19 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
import '../../../constants/constant.dart';
|
||||
|
||||
class HiddingselButton extends StatelessWidget {
|
||||
final String text;
|
||||
final VoidCallback onPressed;
|
||||
|
||||
HiddingselButton(this.text, this.onPressed, {Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => GestureDetector(
|
||||
child: Text(
|
||||
text.toUpperCase(),
|
||||
style: UITheme.theme.textTheme.headlineSmall,
|
||||
),
|
||||
onTap: onPressed,
|
||||
);
|
||||
}
|
||||
673
lib/appflow/view/widgets/card.dart
Normal file
673
lib/appflow/view/widgets/card.dart
Normal file
@@ -0,0 +1,673 @@
|
||||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:hiddingsel_app/appflow/model/location.dart';
|
||||
import 'package:hiddingsel_app/appflow/view/widgets/gallery.dart';
|
||||
import 'package:hiddingsel_app/packages/html_view/html_view.dart';
|
||||
import 'package:hiddingsel_app/constants/constant.dart';
|
||||
|
||||
import '../further_pages/article.dart';
|
||||
import '../../../services/environment.dart';
|
||||
import '../home.dart';
|
||||
import '../../model/articles.dart';
|
||||
import '../../model/companies.dart';
|
||||
import '../../model/pois.dart';
|
||||
import '../../model/represented_organisations.dart';
|
||||
import '../../../packages/icon_switch/icon_switch.dart';
|
||||
|
||||
class ItemCard extends StatelessWidget {
|
||||
final Widget _title;
|
||||
final ImageProvider? _imageProvider;
|
||||
final Widget _child;
|
||||
final Function()? _onShare;
|
||||
final Function(bool favorite) _onFavorite;
|
||||
final Future<bool> _initFavorite;
|
||||
final Function(bool notify) _onNotify;
|
||||
final Future<bool> _initNotify;
|
||||
final Gradient _gradientColor;
|
||||
final bool _right;
|
||||
|
||||
ItemCard(this._title, this._imageProvider, this._child, this._onShare,
|
||||
{onFavorite, initFavorite, onNotify, initNotify, gradientColor, right = true})
|
||||
: _onFavorite = onFavorite,
|
||||
_initFavorite = initFavorite ?? Future.value(false),
|
||||
_onNotify = onNotify,
|
||||
_initNotify = initNotify ?? Future.value(false),
|
||||
_gradientColor = gradientColor ??
|
||||
LinearGradient(
|
||||
colors: [
|
||||
UIColors.white,
|
||||
UIColors.white,
|
||||
],
|
||||
),
|
||||
_right = right;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
int space = 20;
|
||||
List<Widget> buttons = [
|
||||
IconButton(
|
||||
icon: Icon(Icons.share, color: UIColors.white),
|
||||
tooltip: 'Share',
|
||||
onPressed: _onShare,
|
||||
),
|
||||
];
|
||||
buttons.add(Spacer());
|
||||
/*buttons.add(
|
||||
IconSwitch(
|
||||
_onFavorite,
|
||||
initFavorite: _initFavorite,
|
||||
gradientColor: _gradientColor,
|
||||
defaultColor: UIColors.white,
|
||||
),
|
||||
);
|
||||
buttons.add(Spacer());*/
|
||||
buttons.add(
|
||||
IconSwitch(
|
||||
_onNotify,
|
||||
initFavorite: _initNotify,
|
||||
gradientColor: _gradientColor,
|
||||
defaultColor: UIColors.white,
|
||||
iconFavorite: Icons.notifications_active,
|
||||
iconDefavorite: Icons.notifications_outlined,
|
||||
),
|
||||
);
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
Widget image;
|
||||
if (_imageProvider != null) {
|
||||
image = Image(
|
||||
image: _imageProvider,
|
||||
fit: BoxFit.cover,
|
||||
width: constraints.maxWidth - 48 - space,
|
||||
);
|
||||
} else {
|
||||
image = Container(
|
||||
width: constraints.maxWidth - 48 - space,
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
);
|
||||
}
|
||||
RoundedRectangleBorder border;
|
||||
double paddingLeft = 0;
|
||||
double paddingRight = 0;
|
||||
if (_right) {
|
||||
border = UIShapes.leftRoundedRectangleWithBorder;
|
||||
paddingLeft = UIShapes.paddingSimple + space / 2;
|
||||
} else {
|
||||
border = UIShapes.rightRoundedRectangleWithBorder;
|
||||
paddingRight = UIShapes.paddingSimple + space / 2;
|
||||
}
|
||||
return Container(
|
||||
margin: EdgeInsets.symmetric(vertical: UIShapes.paddingSimple),
|
||||
child: Stack(
|
||||
alignment: Alignment.topRight,
|
||||
children: [
|
||||
Positioned.fill(
|
||||
left: paddingLeft,
|
||||
right: paddingRight,
|
||||
child: Container(
|
||||
decoration: ShapeDecoration(shape: border),
|
||||
width: constraints.maxWidth - UIShapes.paddingDouble,
|
||||
),
|
||||
),
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
_right? UIShapes.paddingMax + UIShapes.paddingDouble : UIShapes.paddingMax,
|
||||
UIShapes.paddingDouble,
|
||||
UIShapes.paddingSimple,
|
||||
UIShapes.paddingSimple),
|
||||
child: _title,
|
||||
),
|
||||
Container(
|
||||
height: constraints.maxWidth * 0.6,
|
||||
decoration: BoxDecoration(
|
||||
color: UIColors.grey5,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
0,
|
||||
UIShapes.paddingSimple,
|
||||
0,
|
||||
UIShapes.paddingSimple,
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: UIShapes.rightRoundedRectangle,
|
||||
child: image,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
0,
|
||||
UIShapes.paddingSimple,
|
||||
0,
|
||||
UIShapes.paddingSimple,
|
||||
),
|
||||
child: Column(children: buttons),
|
||||
),
|
||||
VerticalDivider(
|
||||
color: _right ? Colors.transparent : UIColors.white,
|
||||
width: 2,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
UIShapes.paddingMax + paddingLeft,
|
||||
UIShapes.paddingSimple,
|
||||
UIShapes.paddingSimple + paddingRight,
|
||||
UIShapes.paddingDouble),
|
||||
child: _child,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ItemWithPersonAndText extends StatelessWidget {
|
||||
final String _title;
|
||||
final String _assetLogo;
|
||||
final String _assetPerson;
|
||||
final String _personName;
|
||||
final String? _personText;
|
||||
final InlineSpan _text;
|
||||
final String? _mail;
|
||||
final String? _phone;
|
||||
final Uri? _website;
|
||||
final LocationModel? _location;
|
||||
final String? _facebook;
|
||||
final String? _instagram;
|
||||
final Function() _onShare;
|
||||
final Function(bool favorite) _onFavorite;
|
||||
final Future<bool> _initFavorite;
|
||||
final Function(bool notify) _onNotify;
|
||||
final Future<bool> _initNotify;
|
||||
final Gradient _gradientColor;
|
||||
|
||||
ItemWithPersonAndText.fromOrganisation(RepresentedOrganisationModel _organisation)
|
||||
: _title = _organisation.name,
|
||||
_assetLogo = _organisation.image.resource,
|
||||
_assetPerson = _organisation.person.image.resource,
|
||||
_personName = _organisation.person.name,
|
||||
_personText = _organisation.person.position,
|
||||
_mail = _organisation.contact.mail,
|
||||
_phone = _organisation.contact.phone,
|
||||
_website = _organisation.contact.website,
|
||||
_location = _organisation.contact.location,
|
||||
_facebook = _organisation.contact.facebook,
|
||||
_instagram = _organisation.contact.instagram,
|
||||
_text = _organisation.text,
|
||||
_onShare = shareOrganisation(_organisation),
|
||||
_onFavorite = _organisation.favorize,
|
||||
_initFavorite = _organisation.favorized,
|
||||
_onNotify = _organisation.subscribe,
|
||||
_initNotify = _organisation.subscribed,
|
||||
_gradientColor = UIGradiants.yellow;
|
||||
|
||||
ItemWithPersonAndText.fromCompany(CompanyModel _company)
|
||||
: _title = _company.name,
|
||||
_assetLogo = _company.image.resource,
|
||||
_assetPerson = _company.person.image.resource,
|
||||
_personName = _company.person.name,
|
||||
_personText = _company.person.position,
|
||||
_text = _company.text,
|
||||
_mail = _company.contact.mail,
|
||||
_phone = _company.contact.phone,
|
||||
_website = _company.contact.website,
|
||||
_location = _company.contact.location,
|
||||
_facebook = _company.contact.facebook,
|
||||
_instagram = _company.contact.instagram,
|
||||
_onShare = shareCompany(_company),
|
||||
_onFavorite = doNothing,
|
||||
_initFavorite = Future(() => false),
|
||||
_onNotify = _company.subscribe,
|
||||
_initNotify = _company.subscribed,
|
||||
_gradientColor = UIGradiants.purple;
|
||||
|
||||
static doNothing(s) {}
|
||||
|
||||
@override
|
||||
Widget build(
|
||||
BuildContext context) {
|
||||
Text title = Text(
|
||||
_title,
|
||||
style: UITheme.theme.textTheme.displaySmall,
|
||||
);
|
||||
ImageProvider image = AssetImage(_assetLogo);
|
||||
List<Widget> iconButtons = [];
|
||||
if (_mail != null) {
|
||||
iconButtons.add(
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.mail,
|
||||
color: UIColors.grey5,
|
||||
),
|
||||
tooltip: 'Mail',
|
||||
onPressed: () {
|
||||
EnvironmentConnector.openMail(_mail);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
if (_phone != null) {
|
||||
iconButtons.add(
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.phone,
|
||||
color: UIColors.grey5,
|
||||
),
|
||||
tooltip: 'Phone',
|
||||
onPressed: () {
|
||||
EnvironmentConnector.openPhone(_phone);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
if (_website != null) {
|
||||
iconButtons.add(
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.web,
|
||||
color: UIColors.grey5,
|
||||
),
|
||||
tooltip: 'Website',
|
||||
onPressed: () {
|
||||
EnvironmentConnector.openBrowser(_website);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
if (_location != null) {
|
||||
iconButtons.add(
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.place,
|
||||
color: UIColors.grey5,
|
||||
),
|
||||
tooltip: 'Location',
|
||||
onPressed: () {EnvironmentConnector.openMaps(_location);},
|
||||
),
|
||||
);
|
||||
}
|
||||
if (_facebook != null) {
|
||||
iconButtons.add(
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.facebook,
|
||||
color: UIColors.grey5,
|
||||
),
|
||||
tooltip: 'Facebook',
|
||||
onPressed: () {EnvironmentConnector.openFacebook(_facebook);},
|
||||
),
|
||||
);
|
||||
}
|
||||
if (_instagram != null) {
|
||||
iconButtons.add(
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
FontAwesomeIcons.instagram,
|
||||
color: UIColors.grey5,
|
||||
),
|
||||
tooltip: 'Instagram',
|
||||
onPressed: () {EnvironmentConnector.openInstagram(_instagram);},
|
||||
),
|
||||
);
|
||||
}
|
||||
Widget child = Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.baseline,
|
||||
textBaseline: TextBaseline.alphabetic,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(UIShapes.paddingDouble),
|
||||
child: Image(
|
||||
image: AssetImage(_assetPerson),
|
||||
fit: BoxFit.cover,
|
||||
width: 100,
|
||||
height: 100,
|
||||
),
|
||||
),
|
||||
VerticalDivider(width: UIShapes.paddingSimple),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
_personName,
|
||||
style: UITheme.theme.textTheme.displaySmall,
|
||||
),
|
||||
Text(
|
||||
_personText??'',
|
||||
style: UITheme.theme.textTheme.bodyLarge,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Column(
|
||||
children: iconButtons,
|
||||
),
|
||||
],
|
||||
),
|
||||
RichText(text: _text,),
|
||||
],
|
||||
);
|
||||
|
||||
return ItemCard(
|
||||
title,
|
||||
image,
|
||||
child,
|
||||
_onShare,
|
||||
onFavorite: _onFavorite,
|
||||
initFavorite: _initFavorite,
|
||||
onNotify: _onNotify,
|
||||
initNotify: _initNotify,
|
||||
gradientColor: _gradientColor,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ItemWithText extends StatelessWidget {
|
||||
final String _title;
|
||||
final String _assetTitle;
|
||||
final String? _subtitle;
|
||||
final String _text;
|
||||
final Function() _onShare;
|
||||
final Function()? _onFavorite;
|
||||
final Function()? _onNotify;
|
||||
|
||||
ItemWithText.fromPoi(PointOfInterestModel _poi)
|
||||
: _title = _poi.name,
|
||||
_assetTitle = _poi.image.resource,
|
||||
_subtitle = _poi.subtitle,
|
||||
_text = _poi.text,
|
||||
_onShare = sharePoi(_poi),
|
||||
_onFavorite = null,
|
||||
_onNotify = null;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Text title = Text(
|
||||
_title,
|
||||
style: UITheme.theme.textTheme.headlineSmall,
|
||||
);
|
||||
ImageProvider image = AssetImage(_assetTitle);
|
||||
Column child = Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
_subtitle ?? '',
|
||||
style: UITheme.theme.textTheme.displaySmall,
|
||||
),
|
||||
Text(
|
||||
_text,
|
||||
style: UITheme.theme.textTheme.bodyLarge,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
return ItemCard(
|
||||
title,
|
||||
image,
|
||||
child,
|
||||
_onShare,
|
||||
onFavorite: _onFavorite,
|
||||
onNotify: _onNotify,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ItemWithTitle extends StatelessWidget {
|
||||
final ArticleModel _article;
|
||||
final String _title;
|
||||
final String? _thumbnailPictureUrl;
|
||||
final String _subtitle;
|
||||
final Function()? _onShare;
|
||||
final Function(bool favorite)? _onFavorite;
|
||||
final Future<bool>? _initFavorite;
|
||||
final Function(bool notify)? _onNotify;
|
||||
final Future<bool>? _initNotify;
|
||||
final bool _right;
|
||||
final Function(PreferredSizeWidget appBar, Widget body)? _onChange;
|
||||
|
||||
ItemWithTitle.fromNull()
|
||||
: _title = '',
|
||||
_thumbnailPictureUrl = null,
|
||||
_subtitle = '',
|
||||
_onShare = null,
|
||||
_onFavorite = null,
|
||||
_initFavorite = null,
|
||||
_onNotify = null,
|
||||
_initNotify = null,
|
||||
_right = false,
|
||||
_onChange = null,
|
||||
_article = ArticleModel(-1, '', '', DateTime.now(), '', Uri());
|
||||
|
||||
ItemWithTitle.fromArticle(this._article, this._onChange)
|
||||
: _title =
|
||||
'${_article.publishedAt.year}-${_article.publishedAt.month}-${_article.publishedAt.day}',
|
||||
_thumbnailPictureUrl = _article.image.resource,
|
||||
_subtitle = _article.title,
|
||||
_onShare = shareArticle(_article),
|
||||
_onFavorite = favorizeAll(_article.categories),
|
||||
_initFavorite = allFavorized(_article.categories),
|
||||
_onNotify = subscribeAll(_article.categories),
|
||||
_initNotify = allSubscribed(_article.categories),
|
||||
_right = false;
|
||||
|
||||
static favorizeAll(List<RepresentedOrganisationModel> list) {
|
||||
return (fav) => list.forEach((e) => e.favorize(fav));
|
||||
}
|
||||
static Future<bool> allFavorized(List<RepresentedOrganisationModel> list) async {
|
||||
bool favorized = false;
|
||||
for(RepresentedOrganisationModel e in list) {
|
||||
favorized = favorized || await e.favorized;
|
||||
}
|
||||
return favorized;
|
||||
}
|
||||
static subscribeAll(List<RepresentedOrganisationModel> list) {
|
||||
return (sub) => list.forEach((e) => e.subscribe(sub));
|
||||
}
|
||||
static Future<bool> allSubscribed(List<RepresentedOrganisationModel> list) async {
|
||||
bool subscribed = false;
|
||||
for(RepresentedOrganisationModel e in list) {
|
||||
subscribed = subscribed || await e.subscribed;
|
||||
}
|
||||
return subscribed;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Text title = Text(
|
||||
_title,
|
||||
style: UITheme.theme.textTheme.headlineSmall,
|
||||
);
|
||||
ImageProvider? image = _thumbnailPictureUrl != null ? CachedNetworkImageProvider(_thumbnailPictureUrl) : null;
|
||||
|
||||
Widget child = Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
_subtitle,
|
||||
style: UITheme.theme.textTheme.displaySmall,
|
||||
),
|
||||
),
|
||||
Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
color: UIColors.grey4,
|
||||
),
|
||||
],
|
||||
);
|
||||
var onTap;
|
||||
if (_article.id != -1) {
|
||||
onTap = () {
|
||||
Home.openPage(ArticleView(_article), _onChange);
|
||||
};
|
||||
}
|
||||
return GestureDetector(
|
||||
child: ItemCard(
|
||||
title,
|
||||
image,
|
||||
child,
|
||||
_onShare,
|
||||
onFavorite: _onFavorite,
|
||||
initFavorite: _initFavorite,
|
||||
onNotify: _onNotify,
|
||||
initNotify: _initNotify,
|
||||
right: _right,
|
||||
gradientColor: UIGradiants.yellow,
|
||||
),
|
||||
onTap: onTap,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ItemWithWebView extends StatelessWidget {
|
||||
final ArticleModel _article;
|
||||
final String _title;
|
||||
final String _thumbnailPictureUrl;
|
||||
final String _subtitle;
|
||||
final Function() _onShare;
|
||||
final Function(bool favorite) _onFavorite;
|
||||
final Future<bool> _initFavorite;
|
||||
final Function(bool notify) _onNotify;
|
||||
final Future<bool> _initNotify;
|
||||
final bool _right;
|
||||
|
||||
ItemWithWebView.fromArticle(this._article)
|
||||
: _title =
|
||||
'${_article.publishedAt.year}-${_article.publishedAt.month}-${_article.publishedAt.day}',
|
||||
_thumbnailPictureUrl = _article.image.resource,
|
||||
_subtitle = _article.title,
|
||||
_onShare = shareArticle(_article),
|
||||
_onFavorite = favorizeAll(_article.categories),
|
||||
_initFavorite = allFavorized(_article.categories),
|
||||
_onNotify = subscribeAll(_article.categories),
|
||||
_initNotify = allSubscribed(_article.categories),
|
||||
_right = true;
|
||||
|
||||
static favorizeAll(List<RepresentedOrganisationModel> list) {
|
||||
return (fav) => list.forEach((e) => e.favorize(fav));
|
||||
}
|
||||
static Future<bool> allFavorized(List<RepresentedOrganisationModel> list) async {
|
||||
bool favorized = false;
|
||||
for(RepresentedOrganisationModel e in list) {
|
||||
favorized = favorized || await e.favorized;
|
||||
}
|
||||
return favorized;
|
||||
}
|
||||
static subscribeAll(List<RepresentedOrganisationModel> list) {
|
||||
return (sub) => list.forEach((e) => e.subscribe(sub));
|
||||
}
|
||||
static Future<bool> allSubscribed(List<RepresentedOrganisationModel> list) async {
|
||||
bool subscribed = false;
|
||||
for(RepresentedOrganisationModel e in list) {
|
||||
subscribed = subscribed || await e.subscribed;
|
||||
}
|
||||
return subscribed;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Text title = Text(
|
||||
_title,
|
||||
style: UITheme.theme.textTheme.headlineSmall,
|
||||
);
|
||||
ImageProvider image = CachedNetworkImageProvider(_thumbnailPictureUrl);
|
||||
|
||||
Widget child = Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
_subtitle,
|
||||
style: UITheme.theme.textTheme.displaySmall,
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
HtmlView(
|
||||
_article.content,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
SizedBox otherImages = SizedBox(
|
||||
height: 200,
|
||||
child: HiddingselGallery(_article.otherImages.map((e) => e.image).toList()),
|
||||
);
|
||||
|
||||
return ListView(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
children: [
|
||||
ItemCard(
|
||||
title,
|
||||
image,
|
||||
child,
|
||||
_onShare,
|
||||
onFavorite: _onFavorite,
|
||||
initFavorite: _initFavorite,
|
||||
onNotify: _onNotify,
|
||||
initNotify: _initNotify,
|
||||
right: _right,
|
||||
gradientColor: UIGradiants.yellow,
|
||||
),
|
||||
otherImages
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Function() sharePoi(PointOfInterestModel poi) => () {
|
||||
EnvironmentConnector.share(
|
||||
'Ich habe eine interessante Sehenswürdigkeit auf hiddingsel.de gefunden:\n${poi.name}');
|
||||
};
|
||||
|
||||
Function() shareOrganisation(RepresentedOrganisationModel organisation) => () {
|
||||
EnvironmentConnector.share(
|
||||
'Ich habe einen interessanten Verein auf hiddingsel.de gefunden:\n${organisation.name}');
|
||||
};
|
||||
|
||||
Function() shareCompany(CompanyModel company) => () {
|
||||
String text = 'Ich habe ein interessantes Unternehmen auf hiddingsel.de gefunden:\n${company.name}';
|
||||
if(company.contact.mail != null) {
|
||||
text = text + '\nE-Mail: ${company.contact.mail}';
|
||||
}
|
||||
if(company.contact.phone != null) {
|
||||
text = text + '\nTelefon: ${company.contact.phone}';
|
||||
}
|
||||
if(company.contact.website != null) {
|
||||
text = text + '\nWebseite: ${company.contact.website}';
|
||||
}
|
||||
if(company.contact.instagram != null) {
|
||||
text = text + '\nInstagram: ${company.contact.instagram}';
|
||||
}
|
||||
if(company.contact.facebook != null) {
|
||||
text = text + '\nFacebook: ${company.contact.facebook}';
|
||||
}
|
||||
if(company.contact.twitter != null) {
|
||||
text = text + '\nTwitter: ${company.contact.twitter}';
|
||||
}
|
||||
if(company.contact.location?.address != null) {
|
||||
text = text + '\nAdresse: ${company.contact.location?.address}';
|
||||
}
|
||||
EnvironmentConnector.share(text);
|
||||
};
|
||||
|
||||
Function() shareArticle(ArticleModel article) => () {
|
||||
EnvironmentConnector.share(
|
||||
'Ich habe einen interessanten Artikel auf hiddingsel.de gefunden:\n${article.url}');
|
||||
};
|
||||
36
lib/appflow/view/widgets/gallery.dart
Normal file
36
lib/appflow/view/widgets/gallery.dart
Normal file
@@ -0,0 +1,36 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../packages/image/zoomable_image.dart';
|
||||
|
||||
class HiddingselGallery extends StatelessWidget {
|
||||
|
||||
final int _itemCount; //_poi.otherImages.length
|
||||
final IndexedWidgetBuilder _itemBuilder;
|
||||
|
||||
static IndexedWidgetBuilder getItemBuilder(List<ImageProvider> images) => (context, index) => ZoomableImage(
|
||||
images[index],
|
||||
fit: BoxFit.cover,
|
||||
width: 200,
|
||||
height: 200,
|
||||
);
|
||||
|
||||
HiddingselGallery(List<ImageProvider> images) : _itemCount = images.length, _itemBuilder = getItemBuilder(images);
|
||||
|
||||
HiddingselGallery.builder(this._itemCount, this._itemBuilder);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: max(0, 2 * _itemCount - 1),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
if (index % 2 == 0) {
|
||||
return _itemBuilder(context, index ~/ 2);
|
||||
} else {
|
||||
return VerticalDivider();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
}
|
||||
52
lib/appflow/view/widgets/string_list.dart
Normal file
52
lib/appflow/view/widgets/string_list.dart
Normal file
@@ -0,0 +1,52 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hiddingsel_app/appflow/view/widgets/button.dart';
|
||||
|
||||
import '../../../constants/constant.dart';
|
||||
import '../home.dart';
|
||||
import '../navigation_drawer.dart';
|
||||
|
||||
class HiddingselDecoratedList extends StatelessWidget {
|
||||
|
||||
final int _itemCount;
|
||||
final IndexedWidgetBuilder _itemBuilder;
|
||||
final Gradient? _gradient;
|
||||
|
||||
HiddingselDecoratedList(int itemCount, IndexedWidgetBuilder itemBuilder, {Gradient? gradient, Key? key})
|
||||
: _itemCount = itemCount,
|
||||
_itemBuilder = itemBuilder,
|
||||
_gradient = gradient, super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Container(
|
||||
decoration: BoxDecoration(gradient: _gradient),
|
||||
child: ListView.separated(
|
||||
padding: EdgeInsets.all(UIShapes.paddingMax),
|
||||
itemBuilder: _itemBuilder,
|
||||
separatorBuilder: (context, i) => Divider(),
|
||||
itemCount: _itemCount,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
class HiddingselMenu extends StatelessWidget {
|
||||
|
||||
final List<NavigationDrawerItem> _items;
|
||||
final List<String> _names;
|
||||
final Function(NavigationDrawerItem) onPressed;
|
||||
final Gradient? _gradient;
|
||||
|
||||
HiddingselMenu(List<NavigationDrawerItem> items, Function(PreferredSizeWidget appBar, Widget body)? _onChange, {List<String>? names, Function(NavigationDrawerItem)? onPressed, Gradient? gradient, Key? key})
|
||||
: _items = items,
|
||||
onPressed = onPressed??((NavigationDrawerItem item) => Home.openPage(
|
||||
item,
|
||||
_onChange,
|
||||
)),
|
||||
_names = names??items.map((e) => e.title).toList(),
|
||||
_gradient = gradient, super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => HiddingselDecoratedList(
|
||||
_items.length,
|
||||
(context, index) => HiddingselButton(_names[index], () => onPressed(_items[index])),
|
||||
gradient: _gradient,);
|
||||
}
|
||||
123
lib/appflow/view/widgets/time_picker.dart
Normal file
123
lib/appflow/view/widgets/time_picker.dart
Normal file
@@ -0,0 +1,123 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hiddingsel_app/constants/constant.dart';
|
||||
|
||||
class HiddingselTimePicker extends StatelessWidget {
|
||||
final int _height;
|
||||
final double _width;
|
||||
final Duration _initTime;
|
||||
final Function(Duration dateTime) _onSelected;
|
||||
|
||||
HiddingselTimePicker(this._initTime, this._onSelected,
|
||||
{width = 300, height = 100, key})
|
||||
: _width = width,
|
||||
_height = height,
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
int days = _initTime.inDays % (365);
|
||||
int hours = _initTime.inHours % 24;
|
||||
int minutes = _initTime.inMinutes % 60;
|
||||
|
||||
var daysWheel = _buildWheel(7, days, (d) {
|
||||
days = d;
|
||||
_onSelected(Duration(days: days, hours: hours, minutes: minutes));
|
||||
}, UITheme.theme.textTheme.bodyLarge);
|
||||
var hoursWheel = _buildWheel(24, hours, (h) {
|
||||
hours = h;
|
||||
_onSelected(Duration(days: days, hours: hours, minutes: minutes));
|
||||
}, UITheme.theme.textTheme.bodyLarge);
|
||||
var minutesWheel = _buildWheel(60, minutes, (m) {
|
||||
minutes = m;
|
||||
_onSelected(Duration(days: days, hours: hours, minutes: minutes));
|
||||
}, UITheme.theme.textTheme.bodyLarge);
|
||||
return Container(
|
||||
height: _height.toDouble(),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Spacer(flex: 5),
|
||||
_stackWheelWithText(daysWheel, 'Tage'),
|
||||
Spacer(flex: 1),
|
||||
_stackWheelWithText(hoursWheel, 'Stunden'),
|
||||
Spacer(flex: 1),
|
||||
_stackWheelWithText(minutesWheel, 'Minuten'),
|
||||
Spacer(flex: 5),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_buildWheel(int maxValue, initValue, onSelected, textStyle) {
|
||||
double width = textStyle.fontSize;
|
||||
FixedExtentScrollController controller =
|
||||
FixedExtentScrollController(initialItem: initValue);
|
||||
var valList = List<Widget>.generate(
|
||||
maxValue,
|
||||
(int index) => Text(index.toString(), style: textStyle),
|
||||
);
|
||||
bool autoScroll = false;
|
||||
return NotificationListener<ScrollNotification>(
|
||||
onNotification: (scrollNotification) {
|
||||
if (!autoScroll && scrollNotification is ScrollEndNotification) {
|
||||
autoScroll = true;
|
||||
int index;
|
||||
if (scrollNotification.metrics.pixels % width > width / 2) {
|
||||
index = scrollNotification.metrics.pixels ~/ width + 1;
|
||||
} else {
|
||||
index = scrollNotification.metrics.pixels ~/ width;
|
||||
}
|
||||
controller.jumpToItem(index);
|
||||
onSelected(index % maxValue);
|
||||
autoScroll = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
child: ListWheelScrollView.useDelegate(
|
||||
controller: controller,
|
||||
itemExtent: width,
|
||||
diameterRatio: 1,
|
||||
childDelegate: ListWheelChildLoopingListDelegate(
|
||||
children: valList,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_stackWheelWithText(wheel, String unit) {
|
||||
return Container(
|
||||
width: _width / 3,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Spacer(flex: 1),
|
||||
Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: 40,
|
||||
child: wheel,
|
||||
),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: UIColors.grey5, width: 1),
|
||||
borderRadius: BorderRadius.circular(UIShapes.paddingSimple),
|
||||
),
|
||||
child: SizedBox(
|
||||
width: 30,
|
||||
height: UITheme.theme.textTheme.bodyLarge?.fontSize),
|
||||
),
|
||||
],
|
||||
),
|
||||
//Spacer(flex: 1),
|
||||
Text(
|
||||
unit,
|
||||
style: UITheme.theme.textTheme.bodyLarge,
|
||||
),
|
||||
Spacer(flex: 1)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user