diff --git a/wien_talks/wien_talks_flutter/lib/helper/funmap_mgr.dart b/wien_talks/wien_talks_flutter/lib/helper/funmap_mgr.dart new file mode 100644 index 0000000..31a211c --- /dev/null +++ b/wien_talks/wien_talks_flutter/lib/helper/funmap_mgr.dart @@ -0,0 +1,30 @@ +import 'package:serverpod_flutter/serverpod_flutter.dart'; +import 'package:wien_talks_client/wien_talks_client.dart'; + +class FunmapMgr { + static FunmapMgr? _instance; + + FunmapMgr._() { + configure(); + } + + late Client client; + + factory FunmapMgr() { + if (_instance != null) return _instance!; + _instance = FunmapMgr._(); + return _instance!; + } + + void configure() { + // When you are running the app on a physical device, you need to set the + // server URL to the IP address of your computer. You can find the IP + // address by running `ipconfig` on Windows or `ifconfig` on Mac/Linux. + // You can set the variable when running or building your app like this: + // E.g. `flutter run --dart-define=SERVER_URL=https://api.example.com/` + const serverUrlFromEnv = String.fromEnvironment('SERVER_URL'); + final serverUrl = serverUrlFromEnv.isEmpty ? 'http://localhost:8080/' : serverUrlFromEnv; + + client = Client(serverUrl, connectionTimeout: const Duration(seconds: 5))..connectivityMonitor = FlutterConnectivityMonitor(); + } +} diff --git a/wien_talks/wien_talks_flutter/lib/main.dart b/wien_talks/wien_talks_flutter/lib/main.dart index 2611534..4438c2a 100644 --- a/wien_talks/wien_talks_flutter/lib/main.dart +++ b/wien_talks/wien_talks_flutter/lib/main.dart @@ -1,34 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:serverpod_flutter/serverpod_flutter.dart'; -import 'package:wien_talks_client/wien_talks_client.dart'; import 'package:wien_talks_flutter/helper/go_router.dart'; -/// Sets up a global client object that can be used to talk to the server from -/// anywhere in our app. The client is generated from your server code -/// and is set up to connect to a Serverpod running on a local server on -/// the default port. You will need to modify this to connect to staging or -/// production servers. -/// In a larger app, you may want to use the dependency injection of your choice -/// instead of using a global client object. This is just a simple example. -late final Client client; - -late String serverUrl; - void main() { - // When you are running the app on a physical device, you need to set the - // server URL to the IP address of your computer. You can find the IP - // address by running `ipconfig` on Windows or `ifconfig` on Mac/Linux. - // You can set the variable when running or building your app like this: - // E.g. `flutter run --dart-define=SERVER_URL=https://api.example.com/` - const serverUrlFromEnv = String.fromEnvironment('SERVER_URL'); - final serverUrl = - serverUrlFromEnv.isEmpty ? 'http://$localhost:8080/' : serverUrlFromEnv; - - client = Client(serverUrl, connectionTimeout: const Duration(seconds: 5)) - ..connectivityMonitor = FlutterConnectivityMonitor(); - - client.openStreamingConnection(); - runApp(const MyApp()); } @@ -38,44 +11,9 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp.router( - title: 'Wien Talks', + title: 'Wien Talks FunMap', theme: ThemeData(primarySwatch: Colors.blue), routerConfig: router, - //home: NewsScreen(), - //home: const MyHomePage(title: 'Serverpod Example'), - ); - } -} - -/// ResultDisplays shows the result of the call. Either the returned result -/// from the `example.greeting` endpoint method or an error message. -class ResultDisplay extends StatelessWidget { - final String? resultMessage; - final String? errorMessage; - - const ResultDisplay({super.key, this.resultMessage, this.errorMessage}); - - @override - Widget build(BuildContext context) { - String text; - Color backgroundColor; - if (errorMessage != null) { - backgroundColor = Colors.red[300]!; - text = errorMessage!; - } else if (resultMessage != null) { - backgroundColor = Colors.green[300]!; - text = resultMessage!; - } else { - backgroundColor = Colors.grey[300]!; - text = 'No server response yet.'; - } - - return ConstrainedBox( - constraints: const BoxConstraints(minHeight: 50), - child: Container( - color: backgroundColor, - child: Center(child: Text(text)), - ), ); } } diff --git a/wien_talks/wien_talks_flutter/lib/news_input_form.dart b/wien_talks/wien_talks_flutter/lib/news_input_form.dart index ed48bb7..50d6dd9 100644 --- a/wien_talks/wien_talks_flutter/lib/news_input_form.dart +++ b/wien_talks/wien_talks_flutter/lib/news_input_form.dart @@ -2,8 +2,8 @@ import 'package:flutter/material.dart'; import 'package:loader_overlay/loader_overlay.dart'; import 'package:location/location.dart'; import 'package:wien_talks_client/wien_talks_client.dart'; +import 'package:wien_talks_flutter/helper/funmap_mgr.dart'; import 'package:wien_talks_flutter/location_mgr.dart'; -import 'package:wien_talks_flutter/main.dart'; import 'package:wien_talks_flutter/widgets/error_snackbar.dart'; class NewsInputForm extends StatefulWidget { @@ -37,7 +37,7 @@ class _NewsInputFormState extends State { lat: LocationMgr().lastLocation!.latitude!, lng: LocationMgr().lastLocation!.longitude!, ); - await client.quote.createQuote(newsData); + await FunmapMgr().client.quote.createQuote(newsData); _newsController.clear(); } catch (error) { if (mounted) { diff --git a/wien_talks/wien_talks_flutter/lib/news_screen.dart b/wien_talks/wien_talks_flutter/lib/news_screen.dart index 84507cb..75f1dc9 100644 --- a/wien_talks/wien_talks_flutter/lib/news_screen.dart +++ b/wien_talks/wien_talks_flutter/lib/news_screen.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:wien_talks_flutter/show_latest_news_widget.dart'; -import 'package:wien_talks_flutter/widgets/heading_text.dart'; +import 'package:wien_talks_flutter/widgets/intro_text_widget.dart'; import 'package:wien_talks_flutter/widgets/screen_widget.dart'; class NewsScreen extends StatelessWidget { @@ -16,7 +16,7 @@ class NewsScreen extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - HeadingText(text: "Latest news"), + IntroTextWidget(), ShowLatestNewsWidget(), SizedBox( height: 30, diff --git a/wien_talks/wien_talks_flutter/lib/show_latest_news_widget.dart b/wien_talks/wien_talks_flutter/lib/show_latest_news_widget.dart index 1b99ebe..38dd823 100644 --- a/wien_talks/wien_talks_flutter/lib/show_latest_news_widget.dart +++ b/wien_talks/wien_talks_flutter/lib/show_latest_news_widget.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:wien_talks_flutter/main.dart'; +import 'package:wien_talks_flutter/widgets/heading_text.dart'; + +import 'helper/funmap_mgr.dart'; class ShowLatestNewsWidget extends StatelessWidget { const ShowLatestNewsWidget({super.key}); @@ -7,13 +9,16 @@ class ShowLatestNewsWidget extends StatelessWidget { @override Widget build(BuildContext context) { return StreamBuilder( - stream: client.quote.stream, + stream: FunmapMgr().client.quote.stream, builder: (BuildContext context, AsyncSnapshot snapshot) { - if (snapshot.hasError) { - return Text('Error: ${snapshot.error}'); - } - return Text(snapshot.data ?? "Be the first to submit amazing news!", style: TextStyle(fontSize: 20, color: Theme.of(context).colorScheme.error)); - return Placeholder(); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + HeadingText(text: "Latest news"), + if (snapshot.hasError) Text('Error: ${snapshot.error}'), + Text(snapshot.data ?? "Be the first to submit amazing news!", style: TextStyle(fontSize: 20, color: Theme.of(context).colorScheme.error)), + ], + ); }); } } diff --git a/wien_talks/wien_talks_flutter/lib/widgets/add-quote-fab.dart b/wien_talks/wien_talks_flutter/lib/widgets/add-quote-fab.dart index 31750ef..1c58ee1 100644 --- a/wien_talks/wien_talks_flutter/lib/widgets/add-quote-fab.dart +++ b/wien_talks/wien_talks_flutter/lib/widgets/add-quote-fab.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:wien_talks_client/wien_talks_client.dart'; -import 'package:wien_talks_flutter/main.dart'; +import 'package:wien_talks_flutter/helper/funmap_mgr.dart'; class AddQuoteFab extends StatelessWidget { const AddQuoteFab({ @@ -10,8 +10,7 @@ class AddQuoteFab extends StatelessWidget { @override Widget build(BuildContext context) { return FloatingActionButton(onPressed: () { - client.quote.createQuote( - CreateQuoteRequest(text: 'Quote Text', lat: 22, lng: 140)); + FunmapMgr().client.quote.createQuote(CreateQuoteRequest(text: 'Quote Text', lat: 22, lng: 140)); }); } } diff --git a/wien_talks/wien_talks_flutter/lib/widgets/intro_text_widget.dart b/wien_talks/wien_talks_flutter/lib/widgets/intro_text_widget.dart new file mode 100644 index 0000000..5a6bcd6 --- /dev/null +++ b/wien_talks/wien_talks_flutter/lib/widgets/intro_text_widget.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; + +class IntroTextWidget extends StatelessWidget { + const IntroTextWidget({super.key}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Card( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Welcome to FunMap!", + style: GoogleFonts.poppins( + fontSize: 26, + fontWeight: FontWeight.bold, + color: Theme.of(context).primaryColor, + ), + ), + const SizedBox(height: 20), + Text( + "Ever experienced something funny, weird, or just too good not to share? " + "With FunMap, you can pin your funniest moments and strange encounters right on the map! ๐Ÿ—บ๏ธ๐Ÿ˜‚", + style: GoogleFonts.roboto(fontSize: 16, height: 1.5), + ), + const SizedBox(height: 16), + Text( + "Share hilarious events from your daily life, discover what others nearby have spotted, " + "and explore a world full of smiles and surprises. Whether itโ€™s a quirky street performer, " + "an awkward sign, or a random act of comedy โ€” every little story has its place here.", + style: GoogleFonts.roboto(fontSize: 16, height: 1.5), + ), + const SizedBox(height: 16), + Text( + "๐Ÿ‘‰ Add your event, mark the spot, and let the community enjoy the laughter with you.", + style: GoogleFonts.roboto( + fontSize: 16, + fontWeight: FontWeight.w600, + height: 1.5, + ), + ), + const SizedBox(height: 16), + Text( + "Because the worldโ€™s a lot more fun when we laugh together. ๐ŸŒโœจ", + style: GoogleFonts.roboto( + fontSize: 16, + fontStyle: FontStyle.italic, + height: 1.5, + ), + ), + ], + ), + ), + ); + } +} diff --git a/wien_talks/wien_talks_flutter/lib/widgets/screen_widget.dart b/wien_talks/wien_talks_flutter/lib/widgets/screen_widget.dart index 4750baa..49613cd 100644 --- a/wien_talks/wien_talks_flutter/lib/widgets/screen_widget.dart +++ b/wien_talks/wien_talks_flutter/lib/widgets/screen_widget.dart @@ -1,4 +1,7 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:loader_overlay/loader_overlay.dart'; class ScreenWidget extends StatelessWidget { @@ -10,13 +13,42 @@ class ScreenWidget extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('News'), + title: const Text('FunMap'), ), // floatingActionButton: AddQuoteFab(), body: SafeArea( child: Padding( padding: const EdgeInsets.all(8.0), - child: LoaderOverlay(child: child), + child: LoaderOverlay( + overlayWidgetBuilder: (_) { + switch (Random().nextInt(5)) { + case 0: + return Center( + child: CircularProgressIndicator(), + ); + case 1: + return Center( + child: SpinKitCubeGrid(size: 50, color: Theme.of(context).primaryColor), + ); + case 2: + return Center( + child: SpinKitWave(color: Theme.of(context).primaryColor), + ); + case 3: + return Center( + child: SpinKitHourGlass(color: Theme.of(context).primaryColor), + ); + case 4: + return Center( + child: SpinKitFadingCircle(color: Theme.of(context).primaryColor), + ); + default: + return Center( + child: SpinKitPulsingGrid(color: Theme.of(context).primaryColor), + ); + } + }, + child: child), )), ); } diff --git a/wien_talks/wien_talks_flutter/pubspec.yaml b/wien_talks/wien_talks_flutter/pubspec.yaml index 79bdab6..2f75789 100644 --- a/wien_talks/wien_talks_flutter/pubspec.yaml +++ b/wien_talks/wien_talks_flutter/pubspec.yaml @@ -25,6 +25,10 @@ dependencies: flutter: sdk: flutter + flutter_spinkit: ^5.2.2 + + google_fonts: ^6.3.0 + go_router: ^16.1.0 loader_overlay: ^5.0.0