Stub for creating and queriing from server implemented

This commit is contained in:
mikes222 2025-08-16 15:54:36 +02:00
parent b427b44e4c
commit c36081eddf
10 changed files with 86 additions and 29 deletions

View file

@ -15,7 +15,7 @@ class CreateEventScreen extends StatelessWidget {
return ScreenWidget( return ScreenWidget(
child: Column( child: Column(
children: [ children: [
NewsInputForm(onSubmit: (newsEventModel) {}), NewsInputForm(),
StreamBuilder(stream: LocationMgr().stream, builder: (BuildContext context, AsyncSnapshot<LocationData> snapshot) => Text(snapshot.data.toString())), StreamBuilder(stream: LocationMgr().stream, builder: (BuildContext context, AsyncSnapshot<LocationData> snapshot) => Text(snapshot.data.toString())),
Expanded( Expanded(
child: GetLocationWidget( child: GetLocationWidget(

View file

@ -93,6 +93,7 @@ class LocationMgr {
iconMarker = null; iconMarker = null;
viewModel?.dispose(); viewModel?.dispose();
viewModel = null; viewModel = null;
_lastLocationData = null;
} }
Stream<LocationData> get stream => _subject.stream; Stream<LocationData> get stream => _subject.stream;

View file

@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:serverpod_flutter/serverpod_flutter.dart'; import 'package:serverpod_flutter/serverpod_flutter.dart';
import 'package:wien_talks_client/wien_talks_client.dart'; import 'package:wien_talks_client/wien_talks_client.dart';
import 'package:wien_talks_flutter/go_router.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 /// 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 /// anywhere in our app. The client is generated from your server code
@ -38,7 +38,7 @@ class MyApp extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp.router( return MaterialApp.router(
title: 'Serverpod Demo', title: 'Wien Talks',
theme: ThemeData(primarySwatch: Colors.blue), theme: ThemeData(primarySwatch: Colors.blue),
routerConfig: router, routerConfig: router,
//home: NewsScreen(), //home: NewsScreen(),

View file

@ -1,10 +1,13 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:wien_talks_flutter/models/news_event_model.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/location_mgr.dart';
import 'package:wien_talks_flutter/main.dart';
import 'package:wien_talks_flutter/widgets/error_snackbar.dart';
class NewsInputForm extends StatefulWidget { class NewsInputForm extends StatefulWidget {
final Function(NewsEventModel) onSubmit; const NewsInputForm({super.key});
const NewsInputForm({Key? key, required this.onSubmit}) : super(key: key);
@override @override
_NewsInputFormState createState() => _NewsInputFormState(); _NewsInputFormState createState() => _NewsInputFormState();
@ -20,16 +23,29 @@ class _NewsInputFormState extends State<NewsInputForm> {
super.dispose(); super.dispose();
} }
void _submitForm() { void _submitForm() async {
LocationData? locationData = LocationMgr().lastLocation;
if (locationData == null || locationData.latitude == null || locationData.longitude == null) {
ErrorSnackbar().show(context, "No location available, please retry later");
return;
}
if (_formKey.currentState!.validate()) { if (_formKey.currentState!.validate()) {
final newsData = NewsEventModel( var handler = context.loaderOverlay..show();
content: _newsController.text.trim(), try {
timestamp: DateTime.now(), final newsData = CreateQuoteRequest(
latitude: 0.0, text: _newsController.text.trim(),
longitude: 0.0, lat: LocationMgr().lastLocation!.latitude!,
); lng: LocationMgr().lastLocation!.longitude!,
widget.onSubmit(newsData); );
_newsController.clear(); await client.quote.createQuote(newsData);
_newsController.clear();
} catch (error) {
if (mounted) {
ErrorSnackbar().show(context, error.toString());
}
} finally {
handler.hide();
}
} }
} }

View file

@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:wien_talks_flutter/main.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/heading_text.dart';
import 'package:wien_talks_flutter/widgets/screen_widget.dart'; import 'package:wien_talks_flutter/widgets/screen_widget.dart';
@ -28,15 +28,22 @@ class NewsScreen extends StatelessWidget {
); );
return ScreenWidget( return ScreenWidget(
child: SingleChildScrollView( child: SingleChildScrollView(
child: StreamBuilder( child: Column(
stream: client.quote.quoteUpdates(), crossAxisAlignment: CrossAxisAlignment.start,
builder: (context, snapshot) { children: [
if (snapshot.connectionState == ConnectionState.active) { HeadingText(text: "Latest news"),
return Text(snapshot.data?.text ?? 'Empty Text'); ShowLatestNewsWidget(),
} SizedBox(
height: 30,
return Text('Empty or Error'); ),
})), ElevatedButton(
onPressed: () {
context.pushNamed("create_event");
},
child: Text("Submit your own event")),
],
),
),
); );
} }
} }

View file

@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
import 'package:wien_talks_flutter/main.dart';
class ShowLatestNewsWidget extends StatelessWidget {
const ShowLatestNewsWidget({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: 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();
});
}
}

View file

@ -0,0 +1,12 @@
import 'package:flutter/material.dart';
class ErrorSnackbar {
void show(BuildContext context, String message) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(message, style: TextStyle(color: Theme.of(context).colorScheme.onError)),
showCloseIcon: true,
duration: Duration(seconds: 30),
backgroundColor: Theme.of(context).colorScheme.error,
));
}
}

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:wien_talks_flutter/widgets/add-quote-fab.dart'; import 'package:loader_overlay/loader_overlay.dart';
class ScreenWidget extends StatelessWidget { class ScreenWidget extends StatelessWidget {
final Widget child; final Widget child;
@ -12,11 +12,11 @@ class ScreenWidget extends StatelessWidget {
appBar: AppBar( appBar: AppBar(
title: const Text('News'), title: const Text('News'),
), ),
floatingActionButton: AddQuoteFab(), // floatingActionButton: AddQuoteFab(),
body: SafeArea( body: SafeArea(
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: child, child: LoaderOverlay(child: child),
)), )),
); );
} }

View file

@ -27,6 +27,8 @@ dependencies:
go_router: ^16.1.0 go_router: ^16.1.0
loader_overlay: ^5.0.0
location: ^8.0.1 location: ^8.0.1
mapsforge_flutter: ^3.0.2 mapsforge_flutter: ^3.0.2