mirror of
https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
synced 2025-04-27 16:24:07 +02:00
refactor controllers
This commit is contained in:
parent
ec520c330a
commit
9603651e05
7
git-authors.toml
Normal file
7
git-authors.toml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[authors.mtk]
|
||||||
|
name = "Mikkel Troels Kongsted"
|
||||||
|
email = "mtkongsted@gmail.com"
|
||||||
|
|
||||||
|
[authors.sfj]
|
||||||
|
name = "SFJ"
|
||||||
|
email = "simonfromjakobsen@gmail.com"
|
@ -119,9 +119,9 @@ class CartControllerMemory extends CartController {
|
|||||||
Future<Result<Null, String>> purchase(String token) async {
|
Future<Result<Null, String>> purchase(String token) async {
|
||||||
final res = await server.purchaseCart(token, cart);
|
final res = await server.purchaseCart(token, cart);
|
||||||
switch (res) {
|
switch (res) {
|
||||||
case Success<Null>():
|
case Ok<Null, String>():
|
||||||
return const Ok(null);
|
return const Ok(null);
|
||||||
case Error<Null>(message: final message):
|
case Err<Null, String>(value: final message):
|
||||||
return Err(message);
|
return Err(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,10 @@ class ProductController extends ChangeNotifier {
|
|||||||
Future<void> fetchProductsFromServer() async {
|
Future<void> fetchProductsFromServer() async {
|
||||||
final res = await server.allProducts();
|
final res = await server.allProducts();
|
||||||
switch (res) {
|
switch (res) {
|
||||||
case Success<List<Product>>(data: final data):
|
case Ok<List<Product>, String>(value: final data):
|
||||||
products = data;
|
products = data;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
case Error<List<Product>>():
|
case Err<List<Product>, String>():
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
163
mobile/lib/controllers/session.dart
Normal file
163
mobile/lib/controllers/session.dart
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mobile/models/user.dart';
|
||||||
|
import 'package:mobile/results.dart';
|
||||||
|
import 'package:mobile/server/server.dart';
|
||||||
|
|
||||||
|
class SessionController {
|
||||||
|
final Server server;
|
||||||
|
|
||||||
|
String? _sessionToken;
|
||||||
|
User? _sessionUser;
|
||||||
|
|
||||||
|
final List<_ChangeListener> _sessionChangeListeners = [];
|
||||||
|
final List<_ChangeListener> _userChangeListeners = [];
|
||||||
|
|
||||||
|
SessionController({required this.server});
|
||||||
|
|
||||||
|
Future<Result<Null, String>> loginUser(String email, String password) async {
|
||||||
|
final loginResult = await server.login(email, password);
|
||||||
|
switch (loginResult) {
|
||||||
|
case Ok<String, String>(value: final sessionToken):
|
||||||
|
_sessionToken = sessionToken;
|
||||||
|
notifySessionChangeListeners();
|
||||||
|
return const Ok(null);
|
||||||
|
case Err<String, String>(value: final message):
|
||||||
|
return Err(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Result<Null, Null>> loadUser() async {
|
||||||
|
// TODO: retrieve session from cache, if exists
|
||||||
|
return _loadCurrentUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Result<Null, Null>> _loadCurrentUser() async {
|
||||||
|
final sessionUserResult = await _requestWithSession<User>(
|
||||||
|
(server, sessionToken) => server.sessionUser(sessionToken));
|
||||||
|
switch (sessionUserResult) {
|
||||||
|
case Ok<User, String>(value: final sessionUser):
|
||||||
|
_sessionUser = sessionUser;
|
||||||
|
notifyUserChangeListeners();
|
||||||
|
|
||||||
|
// The mechanism for checking that a user is logged in, only listens on
|
||||||
|
// the session provider. There we also notify sessions listeners, to
|
||||||
|
// account for this one specific case. Is this smart? idk.
|
||||||
|
notifySessionChangeListeners();
|
||||||
|
|
||||||
|
return const Ok(null);
|
||||||
|
case Err<User, String>():
|
||||||
|
return const Err(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Null> logout() async {
|
||||||
|
final sessionToken = _sessionToken;
|
||||||
|
if (sessionToken == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await server.logout(sessionToken);
|
||||||
|
_sessionToken = null;
|
||||||
|
notifySessionChangeListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
User get user {
|
||||||
|
final user = _sessionUser;
|
||||||
|
if (user == null) {
|
||||||
|
throw NoUser();
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get hasUser {
|
||||||
|
return _sessionUser != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Result<Null, String>> addBalance() async {
|
||||||
|
final addBalanceResult = await _requestWithSession(
|
||||||
|
(server, sessionToken) => server.addBalance(sessionToken));
|
||||||
|
if (addBalanceResult case Err<Null, String>(value: final message)) {
|
||||||
|
return Err(message);
|
||||||
|
}
|
||||||
|
if (await _loadCurrentUser() case Err<Null, Null>()) {
|
||||||
|
return const Err("could not fetch user");
|
||||||
|
}
|
||||||
|
return const Ok(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Package private.
|
||||||
|
Future<Result<T, String>> _requestWithSession<T>(
|
||||||
|
Future<Result<T, String>> Function(Server server, String sessionToken)
|
||||||
|
func) async {
|
||||||
|
final sessionToken = _sessionToken;
|
||||||
|
if (sessionToken == null) {
|
||||||
|
return const Err("unathorized");
|
||||||
|
}
|
||||||
|
final result = await func(server, sessionToken);
|
||||||
|
if (result case Err<T, String>(value: final message)) {
|
||||||
|
if (message == "unauthorized") {
|
||||||
|
_sessionToken = null;
|
||||||
|
_sessionUser = null;
|
||||||
|
notifySessionChangeListeners();
|
||||||
|
notifyUserChangeListeners();
|
||||||
|
return const Err("unathorized");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Package private.
|
||||||
|
void _addSessionChangeListener(_ChangeListener listener) {
|
||||||
|
_sessionChangeListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Package private.
|
||||||
|
void _addUserChangeListener(_ChangeListener listener) {
|
||||||
|
_userChangeListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Class private.
|
||||||
|
void notifySessionChangeListeners() {
|
||||||
|
for (final listener in _sessionChangeListeners) {
|
||||||
|
listener.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Class private.
|
||||||
|
void notifyUserChangeListeners() {
|
||||||
|
for (final listener in _userChangeListeners) {
|
||||||
|
listener.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _ChangeListener {
|
||||||
|
void notify();
|
||||||
|
}
|
||||||
|
|
||||||
|
class NoUser implements Exception {}
|
||||||
|
|
||||||
|
class SessionProvider extends ChangeNotifier implements _ChangeListener {
|
||||||
|
final SessionController controller;
|
||||||
|
|
||||||
|
SessionProvider({required this.controller}) {
|
||||||
|
controller._addSessionChangeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void notify() {
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CurrentUserProvider extends ChangeNotifier implements _ChangeListener {
|
||||||
|
final SessionController controller;
|
||||||
|
|
||||||
|
CurrentUserProvider({required this.controller}) {
|
||||||
|
controller._addUserChangeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void notify() {
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
@ -1,132 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:mobile/models/user.dart';
|
|
||||||
import 'package:mobile/results.dart';
|
|
||||||
import 'package:mobile/server/server.dart';
|
|
||||||
|
|
||||||
class UserController extends ChangeNotifier {
|
|
||||||
final Server server;
|
|
||||||
String? _sessionToken;
|
|
||||||
User? _user;
|
|
||||||
|
|
||||||
Future<Result<User, Null>> userLoad = Future.error(Null);
|
|
||||||
|
|
||||||
UserController({required this.server});
|
|
||||||
|
|
||||||
/// Make sure a user exists before calling using `.loadUser()`.
|
|
||||||
User get user {
|
|
||||||
final user = _user;
|
|
||||||
if (user == null) {
|
|
||||||
throw NoUserExcept();
|
|
||||||
}
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<Result<Null, Null>> loadUser() async {
|
|
||||||
if (_sessionToken == null) {
|
|
||||||
return const Err(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
final userResult = await server.sessionUser(_sessionToken!);
|
|
||||||
switch (userResult) {
|
|
||||||
case Success<User>(data: final user):
|
|
||||||
_user = user;
|
|
||||||
return const Ok(null);
|
|
||||||
case Error<User>():
|
|
||||||
return const Err(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<Result<Null, Null>> loadedUser() async {
|
|
||||||
throw Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<Result<Null, String>> login(String email, String password) async {
|
|
||||||
switch (await server.login(email, password)) {
|
|
||||||
case Success<String>(data: final token):
|
|
||||||
_sessionToken = token;
|
|
||||||
notifyListeners();
|
|
||||||
return const Ok(null);
|
|
||||||
case Error<String>(message: final message):
|
|
||||||
notifyListeners();
|
|
||||||
return Err(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _validateToken() async {
|
|
||||||
final token = _sessionToken;
|
|
||||||
if (token == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final res = await server.sessionUser(token);
|
|
||||||
switch (res) {
|
|
||||||
case Success<User>():
|
|
||||||
return;
|
|
||||||
case Error<User>():
|
|
||||||
_sessionToken = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated("Use 'user' instead.")
|
|
||||||
User? get userOld {
|
|
||||||
loadUserOld();
|
|
||||||
return _user;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _notifyIfTokenChanged() async {
|
|
||||||
final prev = _sessionToken;
|
|
||||||
_validateToken();
|
|
||||||
if (prev != _sessionToken) {
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated("Use 'loadUser' instead.")
|
|
||||||
Future<void> loadUserOld() async {
|
|
||||||
final token = _sessionToken;
|
|
||||||
if (token == null) {
|
|
||||||
_user = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final res = await server.sessionUser(token);
|
|
||||||
switch (res) {
|
|
||||||
case Success<User>(data: final user):
|
|
||||||
_user = user;
|
|
||||||
return;
|
|
||||||
case Error<User>():
|
|
||||||
_user = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String? get sessionToken {
|
|
||||||
_notifyIfTokenChanged();
|
|
||||||
return _sessionToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> logout() async {
|
|
||||||
final token = _sessionToken;
|
|
||||||
if (token != null) {
|
|
||||||
await server.logout(token);
|
|
||||||
_sessionToken = null;
|
|
||||||
}
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<Result<Null, String>> addBalance() async {
|
|
||||||
final token = _sessionToken;
|
|
||||||
if (token == null) {
|
|
||||||
return const Err("No token");
|
|
||||||
}
|
|
||||||
final res = await server.addBalance(token);
|
|
||||||
notifyListeners();
|
|
||||||
switch (res) {
|
|
||||||
case Success<Null>():
|
|
||||||
return const Ok(null);
|
|
||||||
case Error<Null>(message: final message):
|
|
||||||
return Err(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NoUserExcept implements Exception {}
|
|
@ -10,9 +10,9 @@ class UsersController {
|
|||||||
String name, String email, String password) async {
|
String name, String email, String password) async {
|
||||||
final res = await server.register(name, email, password);
|
final res = await server.register(name, email, password);
|
||||||
switch (res) {
|
switch (res) {
|
||||||
case Success<Null>():
|
case Ok<Null, String>():
|
||||||
return const Ok(null);
|
return const Ok(null);
|
||||||
case Error<Null>(message: final message):
|
case Err<Null, String>(value: final message):
|
||||||
return Err(message);
|
return Err(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
import 'package:mobile/controllers/user.dart';
|
import 'package:mobile/controllers/session.dart';
|
||||||
import 'package:mobile/pages/dashboard.dart';
|
import 'package:mobile/pages/dashboard.dart';
|
||||||
import 'package:mobile/pages/log_in_page.dart';
|
import 'package:mobile/pages/log_in_page.dart';
|
||||||
import 'package:mobile/controllers/add_to_cart_state.dart';
|
import 'package:mobile/controllers/add_to_cart_state.dart';
|
||||||
@ -10,6 +10,7 @@ import 'package:mobile/controllers/paying_state.dart';
|
|||||||
import 'package:mobile/controllers/product.dart';
|
import 'package:mobile/controllers/product.dart';
|
||||||
import 'package:mobile/controllers/receipt.dart';
|
import 'package:mobile/controllers/receipt.dart';
|
||||||
import 'package:mobile/controllers/users.dart';
|
import 'package:mobile/controllers/users.dart';
|
||||||
|
import 'package:mobile/results.dart';
|
||||||
import 'package:mobile/server/backend_server.dart';
|
import 'package:mobile/server/backend_server.dart';
|
||||||
import 'package:mobile/server/server.dart';
|
import 'package:mobile/server/server.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
@ -17,29 +18,38 @@ import 'package:mobile/controllers/routing.dart';
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
final server = BackendServer();
|
final server = BackendServer();
|
||||||
final users = UsersController(server: server);
|
final usersController = UsersController(server: server);
|
||||||
|
final sessionController = SessionController(server: server);
|
||||||
|
|
||||||
final user = UserController(server: server);
|
sessionController.loadUser();
|
||||||
user.loadUser().ignore();
|
|
||||||
|
|
||||||
runApp(MyApp(
|
runApp(MyApp(
|
||||||
users: users,
|
usersController: usersController,
|
||||||
|
sessionController: sessionController,
|
||||||
server: server,
|
server: server,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
final UsersController users;
|
final UsersController usersController;
|
||||||
|
final SessionController sessionController;
|
||||||
|
|
||||||
final Server server;
|
final Server server;
|
||||||
|
|
||||||
const MyApp({super.key, required this.users, required this.server});
|
const MyApp(
|
||||||
|
{super.key,
|
||||||
|
required this.usersController,
|
||||||
|
required this.sessionController,
|
||||||
|
required this.server});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MultiProvider(
|
return MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
ChangeNotifierProvider(create: (_) => UserController(server: server)),
|
ChangeNotifierProvider(
|
||||||
|
create: (_) => SessionProvider(controller: sessionController)),
|
||||||
|
ChangeNotifierProvider(
|
||||||
|
create: (_) => CurrentUserProvider(controller: sessionController)),
|
||||||
ChangeNotifierProvider(create: (_) => RoutingController()),
|
ChangeNotifierProvider(create: (_) => RoutingController()),
|
||||||
ChangeNotifierProvider(
|
ChangeNotifierProvider(
|
||||||
create: (_) => ProductController(server: server)),
|
create: (_) => ProductController(server: server)),
|
||||||
@ -49,7 +59,7 @@ class MyApp extends StatelessWidget {
|
|||||||
ChangeNotifierProvider(create: (_) => PayingStateController()),
|
ChangeNotifierProvider(create: (_) => PayingStateController()),
|
||||||
ChangeNotifierProvider(create: (_) => AddToCartStateController()),
|
ChangeNotifierProvider(create: (_) => AddToCartStateController()),
|
||||||
ChangeNotifierProvider(create: (_) => LocationImageController()),
|
ChangeNotifierProvider(create: (_) => LocationImageController()),
|
||||||
Provider(create: (_) => users),
|
Provider(create: (_) => usersController),
|
||||||
],
|
],
|
||||||
child: MaterialApp(
|
child: MaterialApp(
|
||||||
title: 'Fresh Plaza',
|
title: 'Fresh Plaza',
|
||||||
@ -61,12 +71,24 @@ class MyApp extends StatelessWidget {
|
|||||||
GoogleFonts.merriweatherTextTheme(Theme.of(context).textTheme),
|
GoogleFonts.merriweatherTextTheme(Theme.of(context).textTheme),
|
||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
),
|
),
|
||||||
home: Consumer<UserController>(
|
home: Consumer<SessionProvider>(
|
||||||
builder: (_, sessionController, __) {
|
builder: (_, provider, ___) {
|
||||||
if (sessionController.sessionToken is String) {
|
if (provider.controller.hasUser) {
|
||||||
return Dashboard();
|
return Dashboard();
|
||||||
}
|
}
|
||||||
return const LogInPage();
|
return FutureBuilder(
|
||||||
|
future: provider.controller.loadUser(),
|
||||||
|
builder: (_, snapshot) {
|
||||||
|
final error = snapshot.error;
|
||||||
|
if (error != null) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
if (snapshot.data != null &&
|
||||||
|
snapshot.data is Err<Null, Null>) {
|
||||||
|
return const LoginPage();
|
||||||
|
}
|
||||||
|
return const Scaffold(body: CircularProgressIndicator());
|
||||||
|
});
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
@ -3,7 +3,7 @@ import 'package:mobile/controllers/routing.dart';
|
|||||||
import 'package:mobile/controllers/cart.dart';
|
import 'package:mobile/controllers/cart.dart';
|
||||||
import 'package:mobile/controllers/paying_state.dart';
|
import 'package:mobile/controllers/paying_state.dart';
|
||||||
import 'package:mobile/controllers/receipt.dart';
|
import 'package:mobile/controllers/receipt.dart';
|
||||||
import 'package:mobile/controllers/user.dart';
|
import 'package:mobile/controllers/session.dart';
|
||||||
import 'package:mobile/results.dart';
|
import 'package:mobile/results.dart';
|
||||||
import 'package:mobile/utils/price.dart';
|
import 'package:mobile/utils/price.dart';
|
||||||
import 'package:mobile/widgets/primary_button.dart';
|
import 'package:mobile/widgets/primary_button.dart';
|
||||||
@ -57,42 +57,42 @@ class FinishShoppingPage extends StatelessWidget {
|
|||||||
child: Center(
|
child: Center(
|
||||||
child: PrimaryButton(
|
child: PrimaryButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final session = context.read<UserController>();
|
// final session = context.read<SessionController>();
|
||||||
payingStateRepo.next();
|
// payingStateRepo.next();
|
||||||
await Future.delayed(const Duration(seconds: 1));
|
// await Future.delayed(const Duration(seconds: 1));
|
||||||
if (cartController.purchase(session.sessionToken!)
|
// if (cartController.purchase(session.sessionToken!)
|
||||||
is Err) {
|
// is Err) {
|
||||||
if (context.mounted) {
|
// if (context.mounted) {
|
||||||
showDialog<String>(
|
// showDialog<String>(
|
||||||
context: context,
|
// context: context,
|
||||||
builder: (BuildContext context) =>
|
// builder: (BuildContext context) =>
|
||||||
AlertDialog(
|
// AlertDialog(
|
||||||
content: const Text(
|
// content: const Text(
|
||||||
'Du har desværre ikke råd til at købe dette'),
|
// 'Du har desværre ikke råd til at købe dette'),
|
||||||
actions: <Widget>[
|
// actions: <Widget>[
|
||||||
TextButton(
|
// TextButton(
|
||||||
onPressed: () =>
|
// onPressed: () =>
|
||||||
Navigator.pop(context, 'OK'),
|
// Navigator.pop(context, 'OK'),
|
||||||
child: const Text('OK'),
|
// child: const Text('OK'),
|
||||||
),
|
// ),
|
||||||
],
|
// ],
|
||||||
),
|
// ),
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
payingStateRepo.reset();
|
// payingStateRepo.reset();
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
receiptRepo.createReceipt(cart);
|
// receiptRepo.createReceipt(cart);
|
||||||
payingStateRepo.next();
|
// payingStateRepo.next();
|
||||||
await Future.delayed(const Duration(seconds: 1));
|
// await Future.delayed(const Duration(seconds: 1));
|
||||||
cartController.clearCart();
|
// cartController.clearCart();
|
||||||
payingStateRepo.reset();
|
// payingStateRepo.reset();
|
||||||
if (context.mounted) {
|
// if (context.mounted) {
|
||||||
Navigator.pop(context);
|
// Navigator.pop(context);
|
||||||
final RoutingController routing =
|
// final RoutingController routing =
|
||||||
context.read<RoutingController>();
|
// context.read<RoutingController>();
|
||||||
routing.routeTo(PageSelector.homePage);
|
// routing.routeTo(PageSelector.homePage);
|
||||||
}
|
// }
|
||||||
},
|
},
|
||||||
child: const Text("Betal"))),
|
child: const Text("Betal"))),
|
||||||
),
|
),
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:mobile/controllers/user.dart';
|
import 'package:mobile/controllers/session.dart';
|
||||||
import 'package:mobile/pages/settings_page.dart';
|
import 'package:mobile/pages/settings_page.dart';
|
||||||
import 'package:mobile/utils/build_if_session_exists.dart';
|
|
||||||
import 'package:mobile/utils/price.dart';
|
import 'package:mobile/utils/price.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
@ -10,8 +9,6 @@ class HomePage extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final userController = context.watch<UserController>();
|
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
@ -30,29 +27,33 @@ class HomePage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Card(
|
Card(
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: const BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
borderRadius: BorderRadius.all(Radius.circular(10)),
|
borderRadius: BorderRadius.all(Radius.circular(10)),
|
||||||
color: Color(0xFFFFFFFF),
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
child: BuildIfSessionUserExists(
|
child: Consumer<CurrentUserProvider>(
|
||||||
sessionController: userController,
|
builder: (_, provider, ___) {
|
||||||
placeholder: const CircularProgressIndicator(),
|
final user = provider.controller.user;
|
||||||
builder: (context, user) => Text(
|
return Text("Saldo: ${formatDkkCents(user.balanceDkkCents)}",
|
||||||
"Saldo: ${formatDkkCents(user.balanceDkkCents)}",
|
style: Theme.of(context).textTheme.headlineSmall);
|
||||||
style: Theme.of(context).textTheme.headlineSmall))),
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
BuildIfSessionUserExists(
|
Consumer<CurrentUserProvider>(
|
||||||
sessionController: userController,
|
builder: (_, provider, ___) {
|
||||||
placeholder: const CircularProgressIndicator(),
|
final user = provider.controller.user;
|
||||||
builder: (context, user) => Text(
|
return Text(
|
||||||
"Velkommen ${user.name}",
|
"Velkommen ${user.name}",
|
||||||
style: Theme.of(context).textTheme.headlineMedium,
|
style: Theme.of(context).textTheme.headlineMedium,
|
||||||
))
|
);
|
||||||
|
},
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:mobile/controllers/user.dart';
|
import 'package:mobile/controllers/session.dart';
|
||||||
import 'package:mobile/pages/register_page.dart';
|
import 'package:mobile/pages/register_page.dart';
|
||||||
import 'package:mobile/results.dart';
|
import 'package:mobile/results.dart';
|
||||||
import 'package:mobile/widgets/error_box.dart';
|
import 'package:mobile/widgets/error_box.dart';
|
||||||
@ -7,30 +7,30 @@ import 'package:mobile/widgets/primary_button.dart';
|
|||||||
import 'package:mobile/widgets/primary_input.dart';
|
import 'package:mobile/widgets/primary_input.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class LogInPage extends StatelessWidget {
|
class LoginPage extends StatelessWidget {
|
||||||
const LogInPage({super.key});
|
const LoginPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return const Scaffold(
|
return const Scaffold(
|
||||||
body: Row(
|
body: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [LogInForm()]));
|
children: [LoginForm()]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LogInForm extends StatefulWidget {
|
class LoginForm extends StatefulWidget {
|
||||||
const LogInForm({super.key});
|
const LoginForm({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<StatefulWidget> createState() => LogInFormState();
|
State<StatefulWidget> createState() => LoginFormState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class LogInFormState extends State<LogInForm> {
|
class LoginFormState extends State<LoginForm> {
|
||||||
bool loginError = false;
|
bool loginError = false;
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final userController = context.read<UserController>();
|
final sessionProvider = context.read<SessionProvider>();
|
||||||
|
|
||||||
final mailController = TextEditingController();
|
final mailController = TextEditingController();
|
||||||
final passwordController = TextEditingController();
|
final passwordController = TextEditingController();
|
||||||
@ -63,8 +63,8 @@ class LogInFormState extends State<LogInForm> {
|
|||||||
),
|
),
|
||||||
PrimaryButton(
|
PrimaryButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final loginResult = await userController.login(
|
final loginResult = await sessionProvider.controller
|
||||||
mailController.text, passwordController.text);
|
.loginUser(mailController.text, passwordController.text);
|
||||||
switch (loginResult) {
|
switch (loginResult) {
|
||||||
case Ok<Null, String>():
|
case Ok<Null, String>():
|
||||||
setState(() => loginError = false);
|
setState(() => loginError = false);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:mobile/controllers/user.dart';
|
import 'package:mobile/controllers/session.dart';
|
||||||
import 'package:mobile/pages/settings_pages/saldo.dart';
|
import 'package:mobile/pages/settings_pages/saldo.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
@ -30,9 +30,11 @@ class SettingsPage extends StatelessWidget {
|
|||||||
icon: Icons.door_back_door,
|
icon: Icons.door_back_door,
|
||||||
title: "Log ud",
|
title: "Log ud",
|
||||||
action: (context) async {
|
action: (context) async {
|
||||||
final sessionsController = context.read<UserController>();
|
final sessionProvider = context.read<SessionProvider>();
|
||||||
Navigator.pop(context);
|
await sessionProvider.controller.logout();
|
||||||
await sessionsController.logout();
|
if (context.mounted) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:mobile/controllers/user.dart';
|
import 'package:mobile/controllers/session.dart';
|
||||||
import 'package:mobile/results.dart';
|
import 'package:mobile/results.dart';
|
||||||
import 'package:mobile/utils/build_if_session_exists.dart';
|
import 'package:mobile/utils/build_if_session_exists.dart';
|
||||||
import 'package:mobile/utils/price.dart';
|
import 'package:mobile/utils/price.dart';
|
||||||
@ -10,7 +10,6 @@ class SaldoSettingsPage extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final sessionController = context.watch<UserController>();
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
@ -26,22 +25,30 @@ class SaldoSettingsPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
BuildIfSessionUserExists(
|
Consumer<CurrentUserProvider>(builder: (_, provider, ___) {
|
||||||
sessionController: sessionController,
|
final user = provider.controller.user;
|
||||||
placeholder: const CircularProgressIndicator(),
|
return Text(
|
||||||
builder: (context, user) {
|
"Nuværende saldo: ${formatDkkCents(user.balanceDkkCents)}",
|
||||||
return Text(
|
style: Theme.of(context).textTheme.bodyLarge);
|
||||||
"Nuværende saldo: ${formatDkkCents(user.balanceDkkCents)}",
|
}),
|
||||||
style: Theme.of(context).textTheme.bodyLarge);
|
|
||||||
}),
|
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final res = await sessionController.addBalance();
|
final currentUserProvider = context.read<CurrentUserProvider>();
|
||||||
switch (res) {
|
final res = await currentUserProvider.controller.addBalance();
|
||||||
case Ok<Null, String>():
|
if (res case Err<Null, String>(value: final message)) {
|
||||||
print("yay");
|
if (context.mounted) {
|
||||||
case Err<Null, String>(value: final message):
|
showDialog(
|
||||||
print("Womp womp fejled er: $message");
|
context: context,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
content: Text('Serverfejl: $message'),
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(context, 'OK'),
|
||||||
|
child: const Text('OK'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.add),
|
icon: const Icon(Icons.add),
|
||||||
|
@ -4,6 +4,7 @@ import 'package:http/http.dart' as http;
|
|||||||
import 'package:mobile/models/cart_item.dart';
|
import 'package:mobile/models/cart_item.dart';
|
||||||
import 'package:mobile/models/product.dart';
|
import 'package:mobile/models/product.dart';
|
||||||
import 'package:mobile/models/user.dart';
|
import 'package:mobile/models/user.dart';
|
||||||
|
import 'package:mobile/results.dart';
|
||||||
import 'package:mobile/server/server.dart';
|
import 'package:mobile/server/server.dart';
|
||||||
|
|
||||||
class BackendServer implements Server {
|
class BackendServer implements Server {
|
||||||
@ -21,24 +22,23 @@ class BackendServer implements Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Response<List<Product>>> allProducts() async {
|
Future<Result<List<Product>, String>> allProducts() async {
|
||||||
final res = await http
|
final res = await http
|
||||||
.get(
|
.get(
|
||||||
Uri.parse("$_apiUrl/products/all"),
|
Uri.parse("$_apiUrl/products/all"),
|
||||||
)
|
)
|
||||||
.then((res) => json.decode(res.body));
|
.then((res) => json.decode(res.body));
|
||||||
if (res["ok"]) {
|
if (res["ok"]) {
|
||||||
return Success(
|
return Ok((res["products"] as List<dynamic>)
|
||||||
data: (res["products"] as List<dynamic>)
|
.map(((product) => Product.fromJson(product)))
|
||||||
.map(((product) => Product.fromJson(product)))
|
.toList());
|
||||||
.toList());
|
|
||||||
} else {
|
} else {
|
||||||
return Error(message: res["msg"]);
|
return Err(res["msg"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Response<Null>> register(
|
Future<Result<Null, String>> register(
|
||||||
String name,
|
String name,
|
||||||
String email,
|
String email,
|
||||||
String password,
|
String password,
|
||||||
@ -49,14 +49,14 @@ class BackendServer implements Server {
|
|||||||
).then((res) => json.decode(res.body));
|
).then((res) => json.decode(res.body));
|
||||||
|
|
||||||
if (res["ok"]) {
|
if (res["ok"]) {
|
||||||
return Success(data: null);
|
return Ok(null);
|
||||||
} else {
|
} else {
|
||||||
return Error(message: res["msg"]);
|
return Err(res["msg"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Response<String>> login(
|
Future<Result<String, String>> login(
|
||||||
String email,
|
String email,
|
||||||
String password,
|
String password,
|
||||||
) async {
|
) async {
|
||||||
@ -66,41 +66,41 @@ class BackendServer implements Server {
|
|||||||
).then((res) => json.decode(res.body));
|
).then((res) => json.decode(res.body));
|
||||||
|
|
||||||
if (res["ok"]) {
|
if (res["ok"]) {
|
||||||
return Success(data: res["token"]);
|
return Ok(res["token"]);
|
||||||
} else {
|
} else {
|
||||||
return Error(message: res["msg"]);
|
return Err(res["msg"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Response<Null>> logout(String token) async {
|
Future<Result<Null, String>> logout(String token) async {
|
||||||
final res = await _post(
|
final res = await _post(
|
||||||
endpoint: "sessions/logout",
|
endpoint: "sessions/logout",
|
||||||
).then((res) => json.decode(res.body));
|
).then((res) => json.decode(res.body));
|
||||||
|
|
||||||
if (res["ok"]) {
|
if (res["ok"]) {
|
||||||
return Success(data: null);
|
return Ok(null);
|
||||||
} else {
|
} else {
|
||||||
return Error(message: res["msg"]);
|
return Err(res["msg"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Response<User>> sessionUser(String token) async {
|
Future<Result<User, String>> sessionUser(String token) async {
|
||||||
("sending request fr with token $token");
|
("sending request fr with token $token");
|
||||||
final res = await http.get(
|
final res = await http.get(
|
||||||
Uri.parse("$_apiUrl/sessions/user"),
|
Uri.parse("$_apiUrl/sessions/user"),
|
||||||
headers: {"Session-Token": token},
|
headers: {"Session-Token": token},
|
||||||
).then((res) => json.decode(res.body));
|
).then((res) => json.decode(res.body));
|
||||||
if (res["ok"]) {
|
if (res["ok"]) {
|
||||||
return Success(data: User.fromJson(res["user"]));
|
return Ok(User.fromJson(res["user"]));
|
||||||
} else {
|
} else {
|
||||||
return Error(message: res["msg"]);
|
return Err(res["msg"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Response<Null>> purchaseCart(
|
Future<Result<Null, String>> purchaseCart(
|
||||||
String token, List<CartItem> cartItems) async {
|
String token, List<CartItem> cartItems) async {
|
||||||
final res = await http.post(Uri.parse("$_apiUrl/carts/purchase"), headers: {
|
final res = await http.post(Uri.parse("$_apiUrl/carts/purchase"), headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@ -113,14 +113,14 @@ class BackendServer implements Server {
|
|||||||
}).then((res) => json.decode(res.body));
|
}).then((res) => json.decode(res.body));
|
||||||
|
|
||||||
if (res["ok"]) {
|
if (res["ok"]) {
|
||||||
return Success(data: null);
|
return Ok(null);
|
||||||
} else {
|
} else {
|
||||||
return Error(message: res["msg"]);
|
return Err(res["msg"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Response<Null>> addBalance(String token) async {
|
Future<Result<Null, String>> addBalance(String token) async {
|
||||||
print("$_apiUrl/api/users/balance/add");
|
print("$_apiUrl/api/users/balance/add");
|
||||||
final res = await http.post(
|
final res = await http.post(
|
||||||
Uri.parse("$_apiUrl/users/balance/add"),
|
Uri.parse("$_apiUrl/users/balance/add"),
|
||||||
@ -132,9 +132,9 @@ class BackendServer implements Server {
|
|||||||
).then((res) => json.decode(res.body));
|
).then((res) => json.decode(res.body));
|
||||||
|
|
||||||
if (res["ok"]) {
|
if (res["ok"]) {
|
||||||
return Success(data: null);
|
return Ok(null);
|
||||||
} else {
|
} else {
|
||||||
return Error(message: res["msg"]);
|
return Err(res["msg"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,14 @@ import 'package:mobile/models/cart_item.dart';
|
|||||||
import 'package:mobile/models/coordinate.dart';
|
import 'package:mobile/models/coordinate.dart';
|
||||||
import 'package:mobile/models/product.dart';
|
import 'package:mobile/models/product.dart';
|
||||||
import 'package:mobile/models/user.dart';
|
import 'package:mobile/models/user.dart';
|
||||||
|
import 'package:mobile/results.dart';
|
||||||
import 'package:mobile/server/server.dart';
|
import 'package:mobile/server/server.dart';
|
||||||
|
|
||||||
class MockServer implements Server {
|
class MockServer implements Server {
|
||||||
@override
|
@override
|
||||||
Future<Response<List<Product>>> allProducts() async {
|
Future<Result<List<Product>, String>> allProducts() async {
|
||||||
var nextId = 0;
|
var nextId = 0;
|
||||||
return Success(data: <Product>[
|
return Ok(<Product>[
|
||||||
Product(
|
Product(
|
||||||
id: nextId++,
|
id: nextId++,
|
||||||
name: "Minimælk",
|
name: "Minimælk",
|
||||||
@ -91,45 +92,44 @@ class MockServer implements Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Response<Null>> register(
|
Future<Result<Null, String>> register(
|
||||||
String name,
|
String name,
|
||||||
String email,
|
String email,
|
||||||
String password,
|
String password,
|
||||||
) async {
|
) async {
|
||||||
return Success(data: null);
|
return Ok(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Response<String>> login(
|
Future<Result<String, String>> login(
|
||||||
String email,
|
String email,
|
||||||
String password,
|
String password,
|
||||||
) async {
|
) async {
|
||||||
return Success(data: "asdsadasdsad");
|
return Ok("asdsadasdsad");
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Response<Null>> logout(String token) async {
|
Future<Result<Null, String>> logout(String token) async {
|
||||||
return Success(data: null);
|
return Ok(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Response<User>> sessionUser(String token) async {
|
Future<Result<User, String>> sessionUser(String token) async {
|
||||||
return Success(
|
return Ok(User(
|
||||||
data: User(
|
id: 0,
|
||||||
id: 0,
|
email: "test@test.com",
|
||||||
email: "test@test.com",
|
name: "testuser",
|
||||||
name: "testuser",
|
balanceDkkCents: 10000));
|
||||||
balanceDkkCents: 10000));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Response<Null>> purchaseCart(
|
Future<Result<Null, String>> purchaseCart(
|
||||||
String token, List<CartItem> cartItems) async {
|
String token, List<CartItem> cartItems) async {
|
||||||
return Success(data: null);
|
return Ok(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Response<Null>> addBalance(String token) async {
|
Future<Result<Null, String>> addBalance(String token) async {
|
||||||
return Success(data: null);
|
return Ok(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,37 +1,27 @@
|
|||||||
import 'package:mobile/models/cart_item.dart';
|
import 'package:mobile/models/cart_item.dart';
|
||||||
import 'package:mobile/models/product.dart';
|
import 'package:mobile/models/product.dart';
|
||||||
import 'package:mobile/models/user.dart';
|
import 'package:mobile/models/user.dart';
|
||||||
|
import 'package:mobile/results.dart';
|
||||||
|
|
||||||
abstract class Server {
|
abstract class Server {
|
||||||
Future<Response<List<Product>>> allProducts();
|
Future<Result<List<Product>, String>> allProducts();
|
||||||
|
|
||||||
Future<Response<Null>> register(
|
Future<Result<Null, String>> register(
|
||||||
String name,
|
String name,
|
||||||
String email,
|
String email,
|
||||||
String password,
|
String password,
|
||||||
);
|
);
|
||||||
|
|
||||||
Future<Response<String>> login(
|
Future<Result<String, String>> login(
|
||||||
String email,
|
String email,
|
||||||
String password,
|
String password,
|
||||||
);
|
);
|
||||||
Future<Response<Null>> logout(String token);
|
Future<Result<Null, String>> logout(String token);
|
||||||
|
|
||||||
Future<Response<User>> sessionUser(String token);
|
Future<Result<User, String>> sessionUser(String token);
|
||||||
|
|
||||||
Future<Response<Null>> purchaseCart(String token, List<CartItem> cartItems);
|
Future<Result<Null, String>> purchaseCart(
|
||||||
|
String token, List<CartItem> cartItems);
|
||||||
|
|
||||||
Future<Response<Null>> addBalance(String token);
|
Future<Result<Null, String>> addBalance(String token);
|
||||||
}
|
|
||||||
|
|
||||||
sealed class Response<Data> {}
|
|
||||||
|
|
||||||
class Success<Data> extends Response<Data> {
|
|
||||||
Data data;
|
|
||||||
Success({required this.data});
|
|
||||||
}
|
|
||||||
|
|
||||||
class Error<Data> extends Response<Data> {
|
|
||||||
String message;
|
|
||||||
Error({required this.message});
|
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,3 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:mobile/controllers/user.dart';
|
import 'package:mobile/controllers/session.dart';
|
||||||
import 'package:mobile/models/user.dart';
|
import 'package:mobile/models/user.dart';
|
||||||
|
|
||||||
class BuildIfSessionUserExists extends StatelessWidget {
|
|
||||||
final UserController sessionController;
|
|
||||||
final Widget placeholder;
|
|
||||||
final Widget Function(BuildContext, User) builder;
|
|
||||||
|
|
||||||
const BuildIfSessionUserExists(
|
|
||||||
{super.key,
|
|
||||||
required this.sessionController,
|
|
||||||
required this.placeholder,
|
|
||||||
required this.builder});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return FutureBuilder(
|
|
||||||
future: sessionController.loadUserOld(),
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
final user = sessionController.userOld;
|
|
||||||
if (user == null) {
|
|
||||||
return placeholder;
|
|
||||||
}
|
|
||||||
return builder(context, user);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
// This is a basic Flutter widget test.
|
|
||||||
//
|
|
||||||
// To perform an interaction with a widget in your test, use the WidgetTester
|
|
||||||
// utility in the flutter_test package. For example, you can send tap and scroll
|
|
||||||
// gestures. You can also use WidgetTester to find child widgets in the widget
|
|
||||||
// tree, read text, and verify that the values of widget properties are correct.
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
|
|
||||||
import 'package:mobile/main.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
|
||||||
// Build our app and trigger a frame.
|
|
||||||
await tester.pumpWidget(const MyApp());
|
|
||||||
|
|
||||||
// Verify that our counter starts at 0.
|
|
||||||
expect(find.text('0'), findsOneWidget);
|
|
||||||
expect(find.text('1'), findsNothing);
|
|
||||||
|
|
||||||
// Tap the '+' icon and trigger a frame.
|
|
||||||
await tester.tap(find.byIcon(Icons.add));
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
// Verify that our counter has incremented.
|
|
||||||
expect(find.text('0'), findsNothing);
|
|
||||||
expect(find.text('1'), findsOneWidget);
|
|
||||||
});
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user