Moved User into application wide conntext.
Every page (after login) has access to the User object via context.read/watch<User>(). This reduces localstore and asnyc operations, as the screens do not have to load the user every time. Additionally this prevents anyone from using the without a user object.
This commit is contained in:
parent
42b6da7461
commit
bb9a8621a0
13 changed files with 471 additions and 527 deletions
172
lib/main.dart
172
lib/main.dart
|
@ -16,47 +16,6 @@ import './screens/auth.dart';
|
||||||
import './backend/request.dart';
|
import './backend/request.dart';
|
||||||
import 'package:routemaster/routemaster.dart';
|
import 'package:routemaster/routemaster.dart';
|
||||||
|
|
||||||
// routes when user is not logged in
|
|
||||||
final routesUnauthorized = RouteMap(routes: {
|
|
||||||
'/welcome/': (_) => const MaterialPage(child: WelcomePage()),
|
|
||||||
'/signup': (_) => const MaterialPage(child: AuthPage(mode: Mode.signup)),
|
|
||||||
'/signupOTA': (_) =>
|
|
||||||
const MaterialPage(child: AuthPage(mode: Mode.signupOTA)),
|
|
||||||
'/signin': (_) => const MaterialPage(child: AuthPage(mode: Mode.signin)),
|
|
||||||
}, onUnknownRoute: (_) => const MaterialPage(child: WelcomePage()));
|
|
||||||
|
|
||||||
// routes when user is logged in
|
|
||||||
final routesLoggedIn = RouteMap(routes: {
|
|
||||||
'/': (_) => const MaterialPage(child: HomePage()),
|
|
||||||
'/settings': (_) => const MaterialPage(child: SettingsPage()),
|
|
||||||
'/add-room/new': (_) => const MaterialPage(child: NewRoomPage()),
|
|
||||||
'/add-room': (_) => const MaterialPage(child: JoinRoomPage()),
|
|
||||||
'/r/:server/:tag/': (info) {
|
|
||||||
final server = info.pathParameters['server'] ?? "";
|
|
||||||
final tag = info.pathParameters['tag'] ?? "";
|
|
||||||
|
|
||||||
return MaterialPage(child: RoomPage(server, tag));
|
|
||||||
},
|
|
||||||
'/r/:server/:tag/edit': (info) {
|
|
||||||
final server = info.pathParameters['server'] ?? "";
|
|
||||||
final tag = info.pathParameters['tag'] ?? "";
|
|
||||||
|
|
||||||
return MaterialPage(child: EditRoomPage(server, tag));
|
|
||||||
},
|
|
||||||
'/r/:server/:tag/members': (info) {
|
|
||||||
final server = info.pathParameters['server'] ?? "";
|
|
||||||
final tag = info.pathParameters['tag'] ?? "";
|
|
||||||
|
|
||||||
return MaterialPage(child: ManageRoomMembersPage(server, tag));
|
|
||||||
},
|
|
||||||
'/r/:server/:tag/permissions': (info) {
|
|
||||||
final server = info.pathParameters['server'] ?? "";
|
|
||||||
final tag = info.pathParameters['tag'] ?? "";
|
|
||||||
|
|
||||||
return MaterialPage(child: EditRoomPermissionSetPage(server, tag));
|
|
||||||
},
|
|
||||||
}, onUnknownRoute: (_) => const Redirect('/'));
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
runApp(const OutbagApp());
|
runApp(const OutbagApp());
|
||||||
|
@ -73,8 +32,8 @@ class _OutbagAppState extends State {
|
||||||
// assume user is logged in
|
// assume user is logged in
|
||||||
// unless not userdata is found
|
// unless not userdata is found
|
||||||
// or the userdata turns out to be wrong
|
// or the userdata turns out to be wrong
|
||||||
bool isAuthorized = true;
|
|
||||||
AccountMeta? info;
|
AccountMeta? info;
|
||||||
|
User? user;
|
||||||
|
|
||||||
AppTheme theme = AppTheme.auto;
|
AppTheme theme = AppTheme.auto;
|
||||||
|
|
||||||
|
@ -85,11 +44,17 @@ class _OutbagAppState extends State {
|
||||||
// wait for user to be authorized
|
// wait for user to be authorized
|
||||||
User.listen((_) async {
|
User.listen((_) async {
|
||||||
try {
|
try {
|
||||||
await User.fromDisk();
|
final user = await User.fromDisk();
|
||||||
setState(() {
|
setState(() {
|
||||||
isAuthorized = true;
|
this.user = user;
|
||||||
});
|
});
|
||||||
} catch (_) {}
|
fetchInfo();
|
||||||
|
} catch (_) {
|
||||||
|
// no userdata found
|
||||||
|
setState(() {
|
||||||
|
user = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AppTheme.listen((_) async {
|
AppTheme.listen((_) async {
|
||||||
|
@ -106,15 +71,30 @@ class _OutbagAppState extends State {
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) => fetchInfo());
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||||
|
try {
|
||||||
|
final user = await User.fromDisk();
|
||||||
|
setState(() {
|
||||||
|
this.user = user;
|
||||||
|
});
|
||||||
|
fetchInfo();
|
||||||
|
} catch (_) {
|
||||||
|
// user unavailable
|
||||||
|
// invalid credentials
|
||||||
|
// log out
|
||||||
|
setState(() {
|
||||||
|
user = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void fetchInfo() {
|
void fetchInfo() async {
|
||||||
// try to obtain user account information
|
// try to obtain user account information
|
||||||
// with existing details
|
// with existing details
|
||||||
// NOTE: also functions as a way to verify ther data
|
// NOTE: also functions as a way to verify ther data
|
||||||
doNetworkRequest(null,
|
doNetworkRequest(null,
|
||||||
req: (user) => postWithCreadentials(
|
req: () => postWithCreadentials(
|
||||||
target: (user?.server)!,
|
target: (user?.server)!,
|
||||||
path: 'getMyAccount',
|
path: 'getMyAccount',
|
||||||
credentials: user!,
|
credentials: user!,
|
||||||
|
@ -122,16 +102,16 @@ class _OutbagAppState extends State {
|
||||||
onOK: (body) {
|
onOK: (body) {
|
||||||
final info = AccountMeta.fromJSON(body['data']);
|
final info = AccountMeta.fromJSON(body['data']);
|
||||||
setState(() {
|
setState(() {
|
||||||
isAuthorized = true;
|
|
||||||
this.info = info;
|
this.info = info;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onServerErr: (body) {
|
onServerErr: (_) {
|
||||||
// credentials are wrong
|
// credentials are wrong
|
||||||
// log out
|
// log out
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
isAuthorized = false;
|
info = null;
|
||||||
|
user = null;
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
@ -140,20 +120,7 @@ class _OutbagAppState extends State {
|
||||||
// approve login,
|
// approve login,
|
||||||
// until user goes back offline
|
// until user goes back offline
|
||||||
// NOTE TODO: check user data once online
|
// NOTE TODO: check user data once online
|
||||||
setState(() {
|
|
||||||
isAuthorized = true;
|
|
||||||
});
|
|
||||||
return true;
|
return true;
|
||||||
},
|
|
||||||
onUserErr: () {
|
|
||||||
// invalid credentials
|
|
||||||
// log out
|
|
||||||
setState(() {
|
|
||||||
isAuthorized = false;
|
|
||||||
});
|
|
||||||
// do not show snackbar,
|
|
||||||
// because the user was probably never logged in
|
|
||||||
return false;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +131,12 @@ class _OutbagAppState extends State {
|
||||||
Provider<AccountMeta?>.value(
|
Provider<AccountMeta?>.value(
|
||||||
value: info,
|
value: info,
|
||||||
),
|
),
|
||||||
Provider<AppTheme>.value(value: theme)
|
Provider<AppTheme>.value(value: theme),
|
||||||
|
// conditional user provider
|
||||||
|
// used to only provide a user outside of the login area
|
||||||
|
...(user!=null)?[
|
||||||
|
Provider<User>.value(value:user!)
|
||||||
|
]:[]
|
||||||
],
|
],
|
||||||
child: MaterialApp.router(
|
child: MaterialApp.router(
|
||||||
title: "Outbag",
|
title: "Outbag",
|
||||||
|
@ -172,8 +144,74 @@ class _OutbagAppState extends State {
|
||||||
theme: ThemeData(useMaterial3: true, brightness: Brightness.light),
|
theme: ThemeData(useMaterial3: true, brightness: Brightness.light),
|
||||||
darkTheme: ThemeData(useMaterial3: true, brightness: Brightness.dark),
|
darkTheme: ThemeData(useMaterial3: true, brightness: Brightness.dark),
|
||||||
routerDelegate: RoutemasterDelegate(
|
routerDelegate: RoutemasterDelegate(
|
||||||
routesBuilder: (context) =>
|
routesBuilder: (context) => RouteMap(
|
||||||
isAuthorized ? routesLoggedIn : routesUnauthorized),
|
routes: {
|
||||||
|
// pre authentification routes
|
||||||
|
...(user == null)
|
||||||
|
? {
|
||||||
|
'/welcome/': (_) =>
|
||||||
|
const MaterialPage(child: WelcomePage()),
|
||||||
|
'/signup': (_) => const MaterialPage(
|
||||||
|
child: AuthPage(mode: Mode.signup)),
|
||||||
|
'/signupOTA': (_) => const MaterialPage(
|
||||||
|
child: AuthPage(mode: Mode.signupOTA)),
|
||||||
|
'/signin': (_) => const MaterialPage(
|
||||||
|
child: AuthPage(mode: Mode.signin)),
|
||||||
|
}
|
||||||
|
: {},
|
||||||
|
|
||||||
|
// routes that need the user
|
||||||
|
// to exis
|
||||||
|
...(user!=null)?{
|
||||||
|
'/': (_) => const MaterialPage(child: HomePage()),
|
||||||
|
|
||||||
|
// user-space settings
|
||||||
|
'/settings': (_) =>
|
||||||
|
const MaterialPage(child: SettingsPage()),
|
||||||
|
|
||||||
|
// server dashboard
|
||||||
|
// TODO: add permission check
|
||||||
|
// so routes are only available
|
||||||
|
// if user is allowed to view dashboard
|
||||||
|
...{
|
||||||
|
|
||||||
|
},
|
||||||
|
// room related settings
|
||||||
|
'/add-room/new': (_) =>
|
||||||
|
const MaterialPage(child: NewRoomPage()),
|
||||||
|
'/add-room': (_) =>
|
||||||
|
const MaterialPage(child: JoinRoomPage()),
|
||||||
|
'/r/:server/:tag/': (info) {
|
||||||
|
final server = info.pathParameters['server'] ?? "";
|
||||||
|
final tag = info.pathParameters['tag'] ?? "";
|
||||||
|
|
||||||
|
return MaterialPage(child: RoomPage(server, tag));
|
||||||
|
},
|
||||||
|
'/r/:server/:tag/edit': (info) {
|
||||||
|
final server = info.pathParameters['server'] ?? "";
|
||||||
|
final tag = info.pathParameters['tag'] ?? "";
|
||||||
|
|
||||||
|
return MaterialPage(child: EditRoomPage(server, tag));
|
||||||
|
},
|
||||||
|
'/r/:server/:tag/members': (info) {
|
||||||
|
final server = info.pathParameters['server'] ?? "";
|
||||||
|
final tag = info.pathParameters['tag'] ?? "";
|
||||||
|
|
||||||
|
return MaterialPage(
|
||||||
|
child: ManageRoomMembersPage(server, tag));
|
||||||
|
},
|
||||||
|
'/r/:server/:tag/permissions': (info) {
|
||||||
|
final server = info.pathParameters['server'] ?? "";
|
||||||
|
final tag = info.pathParameters['tag'] ?? "";
|
||||||
|
|
||||||
|
return MaterialPage(
|
||||||
|
child: EditRoomPermissionSetPage(server, tag));
|
||||||
|
},
|
||||||
|
}:{}
|
||||||
|
},
|
||||||
|
onUnknownRoute: (_) => (user == null)
|
||||||
|
? const MaterialPage(child: WelcomePage())
|
||||||
|
: const Redirect('/'))),
|
||||||
routeInformationParser: const RoutemasterParser(),
|
routeInformationParser: const RoutemasterParser(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,6 @@ import 'package:outbag_app/tools/fetch_wrapper.dart';
|
||||||
import 'package:outbag_app/tools/snackbar.dart';
|
import 'package:outbag_app/tools/snackbar.dart';
|
||||||
import 'package:routemaster/routemaster.dart';
|
import 'package:routemaster/routemaster.dart';
|
||||||
import '../backend/resolve_url.dart';
|
import '../backend/resolve_url.dart';
|
||||||
import 'package:crypto/crypto.dart';
|
|
||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
enum Mode {
|
enum Mode {
|
||||||
signin,
|
signin,
|
||||||
|
@ -225,7 +223,7 @@ class _AuthPageState extends State<AuthPage> {
|
||||||
// hash password
|
// hash password
|
||||||
final password = hashPassword(_ctrPassword.text);
|
final password = hashPassword(_ctrPassword.text);
|
||||||
|
|
||||||
doNetworkRequest(scaffMgr, needUser: false, req: (_) {
|
doNetworkRequest(scaffMgr, req: () {
|
||||||
if (widget.mode == Mode.signin) {
|
if (widget.mode == Mode.signin) {
|
||||||
return postUnauthorized(
|
return postUnauthorized(
|
||||||
target: server,
|
target: server,
|
||||||
|
|
|
@ -36,30 +36,28 @@ class _HomePageState extends State<HomePage> {
|
||||||
|
|
||||||
void fetchList() async {
|
void fetchList() async {
|
||||||
final sm = ScaffoldMessenger.of(context);
|
final sm = ScaffoldMessenger.of(context);
|
||||||
|
final user = context.read<User>();
|
||||||
|
|
||||||
// load cached rooms
|
// load cached rooms
|
||||||
try {
|
try {
|
||||||
final newRooms = await Room.listRooms();
|
final newRooms = await Room.listRooms();
|
||||||
setState(() {
|
setState(() {
|
||||||
rooms = newRooms;
|
rooms = newRooms;
|
||||||
});
|
});
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|
||||||
doNetworkRequest(sm,
|
doNetworkRequest(
|
||||||
req: (user) => postWithCreadentials(
|
sm,
|
||||||
path: 'listRooms',
|
req: () => postWithCreadentials(
|
||||||
credentials: user!,
|
path: 'listRooms', credentials: user, target: user.server, body: {}),
|
||||||
target: user.server,
|
|
||||||
body: {}),
|
|
||||||
onOK: (body) async {
|
onOK: (body) async {
|
||||||
final List<Room> list = body['data'].map<Room>((json) {
|
final List<Room> list = body['data'].map<Room>((json) {
|
||||||
return Room.fromJSON(json);
|
return Room.fromJSON(json);
|
||||||
}).toList();
|
}).toList();
|
||||||
for (Room r in list) {
|
for (Room r in list) {
|
||||||
await r.toDisk();
|
await r.toDisk();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onUserErr: ()=>false
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'package:outbag_app/backend/request.dart';
|
||||||
import 'package:outbag_app/backend/room.dart';
|
import 'package:outbag_app/backend/room.dart';
|
||||||
import 'package:outbag_app/backend/user.dart';
|
import 'package:outbag_app/backend/user.dart';
|
||||||
import 'package:outbag_app/tools/fetch_wrapper.dart';
|
import 'package:outbag_app/tools/fetch_wrapper.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'package:routemaster/routemaster.dart';
|
import 'package:routemaster/routemaster.dart';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
|
@ -44,13 +45,14 @@ class _EditRoomPageState extends State<EditRoomPage> {
|
||||||
void fetchInfo() {
|
void fetchInfo() {
|
||||||
final sm = ScaffoldMessenger.of(context);
|
final sm = ScaffoldMessenger.of(context);
|
||||||
final rmaster = Routemaster.of(context);
|
final rmaster = Routemaster.of(context);
|
||||||
|
final user = context.read<User>();
|
||||||
|
|
||||||
doNetworkRequest(
|
doNetworkRequest(
|
||||||
sm,
|
sm,
|
||||||
req: (user) => postWithCreadentials(
|
req: () => postWithCreadentials(
|
||||||
path: 'getRoomInfo',
|
path: 'getRoomInfo',
|
||||||
credentials: user!,
|
credentials: user,
|
||||||
target: (user.server),
|
target: user.server,
|
||||||
body: {'room': widget.tag, 'server': widget.server}),
|
body: {'room': widget.tag, 'server': widget.server}),
|
||||||
onOK: (body) async {
|
onOK: (body) async {
|
||||||
final room = Room.fromJSON(body['data']);
|
final room = Room.fromJSON(body['data']);
|
||||||
|
@ -139,7 +141,8 @@ class _EditRoomPageState extends State<EditRoomPage> {
|
||||||
tooltip: "Go back",
|
tooltip: "Go back",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: SingleChildScrollView(child: Center(
|
body: SingleChildScrollView(
|
||||||
|
child: Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(14),
|
padding: const EdgeInsets.all(14),
|
||||||
child: ConstrainedBox(
|
child: ConstrainedBox(
|
||||||
|
@ -159,8 +162,8 @@ class _EditRoomPageState extends State<EditRoomPage> {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (ctx) => AlertDialog(
|
builder: (ctx) => AlertDialog(
|
||||||
title:
|
title: const Text(
|
||||||
const Text('Choose a room Icon'),
|
'Choose a room Icon'),
|
||||||
actions: const [],
|
actions: const [],
|
||||||
content: SizedBox(
|
content: SizedBox(
|
||||||
width: smallest * 0.3 * 3,
|
width: smallest * 0.3 * 3,
|
||||||
|
@ -174,15 +177,19 @@ class _EditRoomPageState extends State<EditRoomPage> {
|
||||||
icon: SvgPicture
|
icon: SvgPicture
|
||||||
.asset(
|
.asset(
|
||||||
icon.img,
|
icon.img,
|
||||||
width: smallest *
|
width:
|
||||||
|
smallest *
|
||||||
0.3,
|
0.3,
|
||||||
height: smallest *
|
height:
|
||||||
|
smallest *
|
||||||
0.3,
|
0.3,
|
||||||
),
|
),
|
||||||
tooltip: icon.text,
|
tooltip:
|
||||||
|
icon.text,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
_ctrIcon = icon;
|
_ctrIcon =
|
||||||
|
icon;
|
||||||
});
|
});
|
||||||
Navigator.of(
|
Navigator.of(
|
||||||
context)
|
context)
|
||||||
|
@ -239,11 +246,7 @@ class _EditRoomPageState extends State<EditRoomPage> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
))))),
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
floatingActionButton: FloatingActionButton.extended(
|
floatingActionButton: FloatingActionButton.extended(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final scaffMgr = ScaffoldMessenger.of(context);
|
final scaffMgr = ScaffoldMessenger.of(context);
|
||||||
|
|
|
@ -2,7 +2,9 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:outbag_app/backend/request.dart';
|
import 'package:outbag_app/backend/request.dart';
|
||||||
import 'package:outbag_app/backend/room.dart';
|
import 'package:outbag_app/backend/room.dart';
|
||||||
|
import 'package:outbag_app/backend/user.dart';
|
||||||
import 'package:outbag_app/tools/fetch_wrapper.dart';
|
import 'package:outbag_app/tools/fetch_wrapper.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'package:routemaster/routemaster.dart';
|
import 'package:routemaster/routemaster.dart';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
|
@ -18,11 +20,12 @@ class _JoinRoomPageState extends State {
|
||||||
|
|
||||||
void fetchRooms() {
|
void fetchRooms() {
|
||||||
final sm = ScaffoldMessenger.of(context);
|
final sm = ScaffoldMessenger.of(context);
|
||||||
|
final user = context.read<User>();
|
||||||
|
|
||||||
doNetworkRequest(null,
|
doNetworkRequest(null,
|
||||||
req: (user) => postWithCreadentials(
|
req: () => postWithCreadentials(
|
||||||
path: 'listPublicRooms',
|
path: 'listPublicRooms',
|
||||||
credentials: user!,
|
credentials: user,
|
||||||
target: user.server,
|
target: user.server,
|
||||||
body: {}),
|
body: {}),
|
||||||
onOK: (body) async {
|
onOK: (body) async {
|
||||||
|
@ -33,9 +36,9 @@ class _JoinRoomPageState extends State {
|
||||||
// use an empty blacklist when request is not successful
|
// use an empty blacklist when request is not successful
|
||||||
final List<Room> blacklist = [];
|
final List<Room> blacklist = [];
|
||||||
doNetworkRequest(sm,
|
doNetworkRequest(sm,
|
||||||
req: (user) => postWithCreadentials(
|
req: () => postWithCreadentials(
|
||||||
path: 'listRooms',
|
path: 'listRooms',
|
||||||
credentials: user!,
|
credentials: user,
|
||||||
target: user.server,
|
target: user.server,
|
||||||
body: {}),
|
body: {}),
|
||||||
onOK: (body) {
|
onOK: (body) {
|
||||||
|
@ -245,12 +248,14 @@ class _JoinRoomPageState extends State {
|
||||||
context);
|
context);
|
||||||
final nav =
|
final nav =
|
||||||
Navigator.of(context);
|
Navigator.of(context);
|
||||||
|
final user =
|
||||||
|
context.read<User>();
|
||||||
|
|
||||||
doNetworkRequest(scaffMgr,
|
doNetworkRequest(scaffMgr,
|
||||||
req: (user) =>
|
req: () =>
|
||||||
postWithCreadentials(
|
postWithCreadentials(
|
||||||
credentials:
|
credentials:
|
||||||
user!,
|
user,
|
||||||
target: user
|
target: user
|
||||||
.server,
|
.server,
|
||||||
path:
|
path:
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:outbag_app/backend/request.dart';
|
import 'package:outbag_app/backend/request.dart';
|
||||||
import 'package:outbag_app/backend/room.dart';
|
import 'package:outbag_app/backend/room.dart';
|
||||||
|
import 'package:outbag_app/backend/user.dart';
|
||||||
import 'package:outbag_app/screens/room/pages/about.dart';
|
import 'package:outbag_app/screens/room/pages/about.dart';
|
||||||
import 'package:outbag_app/screens/room/pages/categories.dart';
|
import 'package:outbag_app/screens/room/pages/categories.dart';
|
||||||
import 'package:outbag_app/screens/room/pages/products.dart';
|
import 'package:outbag_app/screens/room/pages/products.dart';
|
||||||
import 'package:outbag_app/screens/room/pages/list.dart';
|
import 'package:outbag_app/screens/room/pages/list.dart';
|
||||||
import 'package:outbag_app/tools/fetch_wrapper.dart';
|
import 'package:outbag_app/tools/fetch_wrapper.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'package:routemaster/routemaster.dart';
|
import 'package:routemaster/routemaster.dart';
|
||||||
|
|
||||||
class RoomPage extends StatefulWidget {
|
class RoomPage extends StatefulWidget {
|
||||||
|
@ -28,6 +30,7 @@ class _RoomPageState extends State<RoomPage> {
|
||||||
// fetch room information
|
// fetch room information
|
||||||
void fetchInfo() async {
|
void fetchInfo() async {
|
||||||
final sm = ScaffoldMessenger.of(context);
|
final sm = ScaffoldMessenger.of(context);
|
||||||
|
final user = context.read<User>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final diskRoom =
|
final diskRoom =
|
||||||
|
@ -38,10 +41,10 @@ class _RoomPageState extends State<RoomPage> {
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|
||||||
doNetworkRequest(sm,
|
doNetworkRequest(sm,
|
||||||
req: (user) => postWithCreadentials(
|
req: () => postWithCreadentials(
|
||||||
path: 'getRoomInfo',
|
path: 'getRoomInfo',
|
||||||
credentials: user!,
|
credentials: user,
|
||||||
target: (user.server),
|
target: user.server,
|
||||||
body: {'room': widget.tag, 'server': widget.server}),
|
body: {'room': widget.tag, 'server': widget.server}),
|
||||||
onOK: (body) async {
|
onOK: (body) async {
|
||||||
final info = RoomInfo.fromJSON(body['data']);
|
final info = RoomInfo.fromJSON(body['data']);
|
||||||
|
|
|
@ -2,7 +2,9 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:outbag_app/backend/permissions.dart';
|
import 'package:outbag_app/backend/permissions.dart';
|
||||||
import 'package:outbag_app/backend/request.dart';
|
import 'package:outbag_app/backend/request.dart';
|
||||||
import 'package:outbag_app/backend/room.dart';
|
import 'package:outbag_app/backend/room.dart';
|
||||||
|
import 'package:outbag_app/backend/user.dart';
|
||||||
import 'package:outbag_app/tools/fetch_wrapper.dart';
|
import 'package:outbag_app/tools/fetch_wrapper.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'package:routemaster/routemaster.dart';
|
import 'package:routemaster/routemaster.dart';
|
||||||
|
|
||||||
class ManageRoomMembersPage extends StatefulWidget {
|
class ManageRoomMembersPage extends StatefulWidget {
|
||||||
|
@ -22,13 +24,14 @@ class _ManageRoomMembersPageState extends State<ManageRoomMembersPage> {
|
||||||
void fetchUserInfo() {
|
void fetchUserInfo() {
|
||||||
final rmaster = Routemaster.of(context);
|
final rmaster = Routemaster.of(context);
|
||||||
final sm = ScaffoldMessenger.of(context);
|
final sm = ScaffoldMessenger.of(context);
|
||||||
|
final user = context.read<User>();
|
||||||
|
|
||||||
doNetworkRequest(
|
doNetworkRequest(
|
||||||
sm,
|
sm,
|
||||||
req: (user) => postWithCreadentials(
|
req: () => postWithCreadentials(
|
||||||
path: 'getRoomInfo',
|
path: 'getRoomInfo',
|
||||||
credentials: user!,
|
credentials: user,
|
||||||
target: (user.server),
|
target: user.server,
|
||||||
body: {'room': widget.tag, 'server': widget.server}),
|
body: {'room': widget.tag, 'server': widget.server}),
|
||||||
onAnyErr: () {
|
onAnyErr: () {
|
||||||
// user should not be here
|
// user should not be here
|
||||||
|
@ -49,10 +52,11 @@ class _ManageRoomMembersPageState extends State<ManageRoomMembersPage> {
|
||||||
void fetchMembers() {
|
void fetchMembers() {
|
||||||
final rmaster = Routemaster.of(context);
|
final rmaster = Routemaster.of(context);
|
||||||
final sm = ScaffoldMessenger.of(context);
|
final sm = ScaffoldMessenger.of(context);
|
||||||
|
final user = context.read<User>();
|
||||||
|
|
||||||
doNetworkRequest(sm,
|
doNetworkRequest(sm,
|
||||||
req: (user) => postWithCreadentials(
|
req: () => postWithCreadentials(
|
||||||
credentials: user!,
|
credentials: user,
|
||||||
target: user.server,
|
target: user.server,
|
||||||
path: 'getRoomMembers',
|
path: 'getRoomMembers',
|
||||||
body: {'room': widget.tag, 'server': widget.server}),
|
body: {'room': widget.tag, 'server': widget.server}),
|
||||||
|
@ -99,12 +103,12 @@ class _ManageRoomMembersPageState extends State<ManageRoomMembersPage> {
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.arrow_back),
|
icon: const Icon(Icons.arrow_back),
|
||||||
tooltip: "Go back",
|
tooltip: "Go back",
|
||||||
|
),
|
||||||
|
//actions: [
|
||||||
|
// // NOTE: Maybe add a search icon
|
||||||
|
// // and general search functionality here
|
||||||
|
//],
|
||||||
),
|
),
|
||||||
//actions: [
|
|
||||||
// // NOTE: Maybe add a search icon
|
|
||||||
// // and general search functionality here
|
|
||||||
//],
|
|
||||||
),
|
|
||||||
body: ListView.builder(
|
body: ListView.builder(
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
final item = list[index];
|
final item = list[index];
|
||||||
|
@ -140,7 +144,9 @@ class _ManageRoomMembersPageState extends State<ManageRoomMembersPage> {
|
||||||
title: Text(item.humanReadableName),
|
title: Text(item.humanReadableName),
|
||||||
subtitle: Text(role),
|
subtitle: Text(role),
|
||||||
leading: const Icon(Icons.person),
|
leading: const Icon(Icons.person),
|
||||||
onTap: !enable?null:() {
|
onTap: !enable
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => BottomSheet(
|
builder: (context) => BottomSheet(
|
||||||
|
@ -158,7 +164,8 @@ class _ManageRoomMembersPageState extends State<ManageRoomMembersPage> {
|
||||||
...((info?.isAdmin)! ||
|
...((info?.isAdmin)! ||
|
||||||
(info?.isOwner)! ||
|
(info?.isOwner)! ||
|
||||||
((info?.permissions)! &
|
((info?.permissions)! &
|
||||||
RoomPermission.changeAdmin !=
|
RoomPermission
|
||||||
|
.changeAdmin !=
|
||||||
0))
|
0))
|
||||||
? [
|
? [
|
||||||
ListTile(
|
ListTile(
|
||||||
|
@ -175,8 +182,10 @@ class _ManageRoomMembersPageState extends State<ManageRoomMembersPage> {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder:
|
builder:
|
||||||
(context) => AlertDialog(
|
(context) =>
|
||||||
icon: const Icon(Icons
|
AlertDialog(
|
||||||
|
icon: const Icon(
|
||||||
|
Icons
|
||||||
.supervisor_account),
|
.supervisor_account),
|
||||||
title: Text(item
|
title: Text(item
|
||||||
.isAdmin
|
.isAdmin
|
||||||
|
@ -188,12 +197,12 @@ class _ManageRoomMembersPageState extends State<ManageRoomMembersPage> {
|
||||||
: 'Do you really want to make ${item.humanReadableName} admin?'),
|
: 'Do you really want to make ${item.humanReadableName} admin?'),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed:
|
||||||
|
() {
|
||||||
// close popup
|
// close popup
|
||||||
// NOTE: cancel only closes the dialog
|
// NOTE: cancel only closes the dialog
|
||||||
// whilst OK closes both
|
// whilst OK closes both
|
||||||
Navigator.of(
|
Navigator.of(context)
|
||||||
context)
|
|
||||||
.pop();
|
.pop();
|
||||||
},
|
},
|
||||||
child: const Text(
|
child: const Text(
|
||||||
|
@ -204,20 +213,16 @@ class _ManageRoomMembersPageState extends State<ManageRoomMembersPage> {
|
||||||
() async {
|
() async {
|
||||||
// send request
|
// send request
|
||||||
final scaffMgr =
|
final scaffMgr =
|
||||||
ScaffoldMessenger.of(
|
ScaffoldMessenger.of(context);
|
||||||
context);
|
|
||||||
final nav =
|
final nav =
|
||||||
Navigator.of(
|
Navigator.of(context);
|
||||||
context);
|
final user =
|
||||||
|
context.read<User>();
|
||||||
|
|
||||||
doNetworkRequest(
|
doNetworkRequest(
|
||||||
scaffMgr,
|
scaffMgr,
|
||||||
req: (user) =>
|
req: () =>
|
||||||
postWithCreadentials(
|
postWithCreadentials(path: 'setAdminStatus', credentials: user, target: user.server, body: {
|
||||||
path: 'setAdminStatus',
|
|
||||||
credentials: user!,
|
|
||||||
target: user.server,
|
|
||||||
body: {
|
|
||||||
'room': widget.tag,
|
'room': widget.tag,
|
||||||
'roomServer': widget.server,
|
'roomServer': widget.server,
|
||||||
'server': item.serverTag,
|
'server': item.serverTag,
|
||||||
|
@ -233,8 +238,7 @@ class _ManageRoomMembersPageState extends State<ManageRoomMembersPage> {
|
||||||
nav.pop();
|
nav.pop();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child:
|
child: const Text(
|
||||||
const Text(
|
|
||||||
'OK'),
|
'OK'),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@ -251,9 +255,10 @@ class _ManageRoomMembersPageState extends State<ManageRoomMembersPage> {
|
||||||
0))
|
0))
|
||||||
? [
|
? [
|
||||||
ListTile(
|
ListTile(
|
||||||
leading:
|
leading: const Icon(
|
||||||
const Icon(Icons.person_remove),
|
Icons.person_remove),
|
||||||
title: const Text('Kick User'),
|
title:
|
||||||
|
const Text('Kick User'),
|
||||||
subtitle: const Text(
|
subtitle: const Text(
|
||||||
"Temporarrily remove user from server (they'll be able to join the room again)"),
|
"Temporarrily remove user from server (they'll be able to join the room again)"),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
@ -261,8 +266,10 @@ class _ManageRoomMembersPageState extends State<ManageRoomMembersPage> {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder:
|
builder:
|
||||||
(context) => AlertDialog(
|
(context) =>
|
||||||
icon: const Icon(Icons
|
AlertDialog(
|
||||||
|
icon: const Icon(
|
||||||
|
Icons
|
||||||
.person_remove),
|
.person_remove),
|
||||||
title: const Text(
|
title: const Text(
|
||||||
'Kick User'),
|
'Kick User'),
|
||||||
|
@ -270,13 +277,13 @@ class _ManageRoomMembersPageState extends State<ManageRoomMembersPage> {
|
||||||
'Do you really want to kick ${item.humanReadableName}?'),
|
'Do you really want to kick ${item.humanReadableName}?'),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed:
|
||||||
|
() {
|
||||||
// close popup
|
// close popup
|
||||||
// NOTE: cancel only closes the dialog
|
// NOTE: cancel only closes the dialog
|
||||||
// whilst OK closes both
|
// whilst OK closes both
|
||||||
|
|
||||||
Navigator.of(
|
Navigator.of(context)
|
||||||
context)
|
|
||||||
.pop();
|
.pop();
|
||||||
},
|
},
|
||||||
child: const Text(
|
child: const Text(
|
||||||
|
@ -287,18 +294,18 @@ class _ManageRoomMembersPageState extends State<ManageRoomMembersPage> {
|
||||||
() async {
|
() async {
|
||||||
// send request
|
// send request
|
||||||
final scaffMgr =
|
final scaffMgr =
|
||||||
ScaffoldMessenger.of(
|
ScaffoldMessenger.of(context);
|
||||||
context);
|
|
||||||
final nav =
|
final nav =
|
||||||
Navigator.of(
|
Navigator.of(context);
|
||||||
context);
|
final user =
|
||||||
|
context.read<User>();
|
||||||
|
|
||||||
doNetworkRequest(
|
doNetworkRequest(
|
||||||
scaffMgr,
|
scaffMgr,
|
||||||
req: (user) =>
|
req: () =>
|
||||||
postWithCreadentials(
|
postWithCreadentials(
|
||||||
path: 'kickMember',
|
path: 'kickMember',
|
||||||
credentials: user!,
|
credentials: user,
|
||||||
target: user.server,
|
target: user.server,
|
||||||
body: {
|
body: {
|
||||||
'room': widget.tag,
|
'room': widget.tag,
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'package:outbag_app/backend/room.dart';
|
||||||
import 'package:outbag_app/backend/user.dart';
|
import 'package:outbag_app/backend/user.dart';
|
||||||
import 'package:outbag_app/tools/fetch_wrapper.dart';
|
import 'package:outbag_app/tools/fetch_wrapper.dart';
|
||||||
import 'package:outbag_app/tools/snackbar.dart';
|
import 'package:outbag_app/tools/snackbar.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'package:routemaster/routemaster.dart';
|
import 'package:routemaster/routemaster.dart';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
|
@ -77,8 +78,8 @@ class _NewRoomPageState extends State {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (ctx) => AlertDialog(
|
builder: (ctx) => AlertDialog(
|
||||||
title:
|
title: const Text(
|
||||||
const Text('Choose a room Icon'),
|
'Choose a room Icon'),
|
||||||
actions: const [],
|
actions: const [],
|
||||||
content: SizedBox(
|
content: SizedBox(
|
||||||
width: smallest * 0.3 * 3,
|
width: smallest * 0.3 * 3,
|
||||||
|
@ -92,15 +93,19 @@ class _NewRoomPageState extends State {
|
||||||
icon: SvgPicture
|
icon: SvgPicture
|
||||||
.asset(
|
.asset(
|
||||||
icon.img,
|
icon.img,
|
||||||
width: smallest *
|
width:
|
||||||
|
smallest *
|
||||||
0.3,
|
0.3,
|
||||||
height: smallest *
|
height:
|
||||||
|
smallest *
|
||||||
0.3,
|
0.3,
|
||||||
),
|
),
|
||||||
tooltip: icon.text,
|
tooltip:
|
||||||
|
icon.text,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
_ctrIcon = icon;
|
_ctrIcon =
|
||||||
|
icon;
|
||||||
});
|
});
|
||||||
Navigator.of(
|
Navigator.of(
|
||||||
context)
|
context)
|
||||||
|
@ -177,11 +182,7 @@ class _NewRoomPageState extends State {
|
||||||
selectedIcon: Icon(_ctrVis.icon),
|
selectedIcon: Icon(_ctrVis.icon),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
))))),
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
floatingActionButton: FloatingActionButton.extended(
|
floatingActionButton: FloatingActionButton.extended(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final scaffMgr = ScaffoldMessenger.of(context);
|
final scaffMgr = ScaffoldMessenger.of(context);
|
||||||
|
@ -200,24 +201,13 @@ class _NewRoomPageState extends State {
|
||||||
|
|
||||||
// name may not be empty
|
// name may not be empty
|
||||||
if (_ctrName.text.isEmpty) {
|
if (_ctrName.text.isEmpty) {
|
||||||
showSimpleSnackbar(
|
showSimpleSnackbar(scaffMgr,
|
||||||
scaffMgr,
|
text: 'Please specify a room name', action: 'OK');
|
||||||
text: 'Please specify a room name',
|
|
||||||
action: 'OK'
|
|
||||||
);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
User user;
|
final user = context.read<User>();
|
||||||
try {
|
|
||||||
user = await User.fromDisk();
|
|
||||||
} catch (_) {
|
|
||||||
// user data invalid
|
|
||||||
// shouldn't happen
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final room = Room(
|
final room = Room(
|
||||||
id: _ctrID.text,
|
id: _ctrID.text,
|
||||||
serverTag: user.server.tag,
|
serverTag: user.server.tag,
|
||||||
|
@ -227,7 +217,7 @@ class _NewRoomPageState extends State {
|
||||||
visibility: _ctrVis);
|
visibility: _ctrVis);
|
||||||
|
|
||||||
doNetworkRequest(scaffMgr,
|
doNetworkRequest(scaffMgr,
|
||||||
req: (_) => postWithCreadentials(
|
req: () => postWithCreadentials(
|
||||||
target: user.server,
|
target: user.server,
|
||||||
credentials: user,
|
credentials: user,
|
||||||
path: 'createRoom',
|
path: 'createRoom',
|
||||||
|
@ -244,10 +234,7 @@ class _NewRoomPageState extends State {
|
||||||
await room.toDisk();
|
await room.toDisk();
|
||||||
// move to home page
|
// move to home page
|
||||||
rmaster.replace('/');
|
rmaster.replace('/');
|
||||||
},
|
});
|
||||||
// we manually fetch the user data above
|
|
||||||
// because we need the serverTag
|
|
||||||
needUser: false);
|
|
||||||
},
|
},
|
||||||
label: const Text('Create'),
|
label: const Text('Create'),
|
||||||
icon: const Icon(Icons.add)),
|
icon: const Icon(Icons.add)),
|
||||||
|
|
|
@ -3,8 +3,10 @@ import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:outbag_app/backend/permissions.dart';
|
import 'package:outbag_app/backend/permissions.dart';
|
||||||
import 'package:outbag_app/backend/request.dart';
|
import 'package:outbag_app/backend/request.dart';
|
||||||
import 'package:outbag_app/backend/room.dart';
|
import 'package:outbag_app/backend/room.dart';
|
||||||
|
import 'package:outbag_app/backend/user.dart';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
import 'package:outbag_app/tools/fetch_wrapper.dart';
|
import 'package:outbag_app/tools/fetch_wrapper.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'package:routemaster/routemaster.dart';
|
import 'package:routemaster/routemaster.dart';
|
||||||
|
|
||||||
class AboutRoomPage extends StatefulWidget {
|
class AboutRoomPage extends StatefulWidget {
|
||||||
|
@ -29,7 +31,7 @@ class _AboutRoomPageState extends State<AboutRoomPage> {
|
||||||
double smallest = min(width, height);
|
double smallest = min(width, height);
|
||||||
|
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
child:Center(
|
child: Center(
|
||||||
child: Column(children: [
|
child: Column(children: [
|
||||||
// room meta display
|
// room meta display
|
||||||
...(widget.room != null)
|
...(widget.room != null)
|
||||||
|
@ -51,7 +53,8 @@ class _AboutRoomPageState extends State<AboutRoomPage> {
|
||||||
'${widget.room?.id}@${widget.room?.serverTag}',
|
'${widget.room?.id}@${widget.room?.serverTag}',
|
||||||
style: textTheme.bodySmall,
|
style: textTheme.bodySmall,
|
||||||
),
|
),
|
||||||
Text(widget.room?.description ?? '',
|
Text(
|
||||||
|
widget.room?.description ?? '',
|
||||||
style: textTheme.bodyMedium,
|
style: textTheme.bodyMedium,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
|
@ -103,21 +106,19 @@ class _AboutRoomPageState extends State<AboutRoomPage> {
|
||||||
final scaffMgr =
|
final scaffMgr =
|
||||||
ScaffoldMessenger.of(context);
|
ScaffoldMessenger.of(context);
|
||||||
final nav = Navigator.of(context);
|
final nav = Navigator.of(context);
|
||||||
|
final user = context.read<User>();
|
||||||
|
|
||||||
doNetworkRequest(scaffMgr,
|
doNetworkRequest(scaffMgr,
|
||||||
req: (user) =>
|
req: () => postWithCreadentials(
|
||||||
postWithCreadentials(
|
|
||||||
path: 'setVisibility',
|
path: 'setVisibility',
|
||||||
target: (user?.server)!,
|
target: user.server,
|
||||||
body: {
|
body: {
|
||||||
'room':
|
'room': widget.room?.id,
|
||||||
widget.room?.id,
|
'server': (widget
|
||||||
'server': (widget.room
|
.room?.serverTag)!,
|
||||||
?.serverTag)!,
|
'visibility': vset.first
|
||||||
'visibility':
|
|
||||||
vset.first
|
|
||||||
},
|
},
|
||||||
credentials: user!),
|
credentials: user),
|
||||||
onOK: (_) {
|
onOK: (_) {
|
||||||
Room r = widget.room!;
|
Room r = widget.room!;
|
||||||
r.visibility = vis;
|
r.visibility = vis;
|
||||||
|
@ -193,7 +194,7 @@ class _AboutRoomPageState extends State<AboutRoomPage> {
|
||||||
onTap: () {
|
onTap: () {
|
||||||
// show checkbox screen
|
// show checkbox screen
|
||||||
Routemaster.of(context).push(
|
Routemaster.of(context).push(
|
||||||
'/r/${widget.room?.serverTag}/${widget.room?.id}/permissions');
|
'/r/${widget.room?.serverTag}/${widget.room?.id}/permissions');
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -262,20 +263,20 @@ class _AboutRoomPageState extends State<AboutRoomPage> {
|
||||||
ScaffoldMessenger.of(ctx);
|
ScaffoldMessenger.of(ctx);
|
||||||
final nav = Navigator.of(ctx);
|
final nav = Navigator.of(ctx);
|
||||||
final rmaster = Routemaster.of(ctx);
|
final rmaster = Routemaster.of(ctx);
|
||||||
|
final user = ctx.read<User>();
|
||||||
|
|
||||||
doNetworkRequest(
|
doNetworkRequest(scaffMgr,
|
||||||
scaffMgr,
|
req: () => postWithCreadentials(
|
||||||
req: (user)=>postWithCreadentials(
|
|
||||||
path: ((widget.info?.isOwner)!)
|
path: ((widget.info?.isOwner)!)
|
||||||
? 'deleteRoom'
|
? 'deleteRoom'
|
||||||
: 'leaveRoom',
|
: 'leaveRoom',
|
||||||
target: (user?.server)!,
|
target: user.server,
|
||||||
body: {
|
body: {
|
||||||
'room': widget.room?.id,
|
'room': widget.room?.id,
|
||||||
'server':
|
'server':
|
||||||
(widget.room?.serverTag)!,
|
(widget.room?.serverTag)!,
|
||||||
},
|
},
|
||||||
credentials: user!),
|
credentials: user),
|
||||||
onOK: (_) async {
|
onOK: (_) async {
|
||||||
// try delete room from disk
|
// try delete room from disk
|
||||||
try {
|
try {
|
||||||
|
@ -288,8 +289,7 @@ class _AboutRoomPageState extends State<AboutRoomPage> {
|
||||||
after: () {
|
after: () {
|
||||||
// close popup
|
// close popup
|
||||||
nav.pop();
|
nav.pop();
|
||||||
}
|
});
|
||||||
);
|
|
||||||
},
|
},
|
||||||
child: Text(((widget.info?.isOwner)!)
|
child: Text(((widget.info?.isOwner)!)
|
||||||
? 'Delete'
|
? 'Delete'
|
||||||
|
@ -301,9 +301,6 @@ class _AboutRoomPageState extends State<AboutRoomPage> {
|
||||||
))
|
))
|
||||||
]
|
]
|
||||||
: [],
|
: [],
|
||||||
]
|
])));
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,9 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:outbag_app/backend/permissions.dart';
|
import 'package:outbag_app/backend/permissions.dart';
|
||||||
import 'package:outbag_app/backend/request.dart';
|
import 'package:outbag_app/backend/request.dart';
|
||||||
import 'package:outbag_app/backend/room.dart';
|
import 'package:outbag_app/backend/room.dart';
|
||||||
|
import 'package:outbag_app/backend/user.dart';
|
||||||
import 'package:outbag_app/tools/fetch_wrapper.dart';
|
import 'package:outbag_app/tools/fetch_wrapper.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'package:routemaster/routemaster.dart';
|
import 'package:routemaster/routemaster.dart';
|
||||||
|
|
||||||
class EditRoomPermissionSetPage extends StatefulWidget {
|
class EditRoomPermissionSetPage extends StatefulWidget {
|
||||||
|
@ -24,13 +26,14 @@ class _EditRoomPermissionSetPageState extends State<EditRoomPermissionSetPage> {
|
||||||
void fetchInfo() {
|
void fetchInfo() {
|
||||||
final rmaster = Routemaster.of(context);
|
final rmaster = Routemaster.of(context);
|
||||||
final sm = ScaffoldMessenger.of(context);
|
final sm = ScaffoldMessenger.of(context);
|
||||||
|
final user = context.read<User>();
|
||||||
|
|
||||||
doNetworkRequest(
|
doNetworkRequest(
|
||||||
sm,
|
sm,
|
||||||
req: (user) => postWithCreadentials(
|
req: () => postWithCreadentials(
|
||||||
path: 'getRoomInfo',
|
path: 'getRoomInfo',
|
||||||
credentials: user!,
|
credentials: user,
|
||||||
target: (user.server),
|
target: user.server,
|
||||||
body: {'room': widget.tag, 'server': widget.server}),
|
body: {'room': widget.tag, 'server': widget.server}),
|
||||||
onAnyErr: () {
|
onAnyErr: () {
|
||||||
// user should not be here
|
// user should not be here
|
||||||
|
@ -94,11 +97,13 @@ class _EditRoomPermissionSetPageState extends State<EditRoomPermissionSetPage> {
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
final rmaster = Routemaster.of(context);
|
final rmaster = Routemaster.of(context);
|
||||||
final sm = ScaffoldMessenger.of(context);
|
final sm = ScaffoldMessenger.of(context);
|
||||||
|
final user = context.read<User>();
|
||||||
|
|
||||||
// update permissions
|
// update permissions
|
||||||
doNetworkRequest(sm,
|
doNetworkRequest(sm,
|
||||||
req: (user) => postWithCreadentials(
|
req: () => postWithCreadentials(
|
||||||
path: 'setRoomRight',
|
path: 'setRoomRight',
|
||||||
credentials: user!,
|
credentials: user,
|
||||||
target: user.server,
|
target: user.server,
|
||||||
body: {
|
body: {
|
||||||
'room': widget.tag,
|
'room': widget.tag,
|
||||||
|
|
|
@ -4,7 +4,7 @@ import 'package:outbag_app/backend/request.dart';
|
||||||
import 'package:outbag_app/backend/user.dart';
|
import 'package:outbag_app/backend/user.dart';
|
||||||
import 'package:outbag_app/tools/fetch_wrapper.dart';
|
import 'package:outbag_app/tools/fetch_wrapper.dart';
|
||||||
import 'package:outbag_app/tools/snackbar.dart';
|
import 'package:outbag_app/tools/snackbar.dart';
|
||||||
import 'package:routemaster/routemaster.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class ChangePasswordDialog extends StatefulWidget {
|
class ChangePasswordDialog extends StatefulWidget {
|
||||||
const ChangePasswordDialog({super.key});
|
const ChangePasswordDialog({super.key});
|
||||||
|
@ -18,39 +18,6 @@ class _ChangePasswordDialogState extends State<ChangePasswordDialog> {
|
||||||
final TextEditingController _ctrNewPassword = TextEditingController();
|
final TextEditingController _ctrNewPassword = TextEditingController();
|
||||||
final TextEditingController _ctrNewPasswordRepeat = TextEditingController();
|
final TextEditingController _ctrNewPasswordRepeat = TextEditingController();
|
||||||
|
|
||||||
User? user;
|
|
||||||
|
|
||||||
void loadUser() async {
|
|
||||||
final rmaster = Routemaster.of(context);
|
|
||||||
try {
|
|
||||||
final u = await User.fromDisk();
|
|
||||||
setState(() {
|
|
||||||
user = u;
|
|
||||||
});
|
|
||||||
} catch (_) {
|
|
||||||
// logout user
|
|
||||||
await User.removeDisk();
|
|
||||||
// move to welcome screen
|
|
||||||
rmaster.replace('/');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
|
|
||||||
User.listen((data) async {
|
|
||||||
try {
|
|
||||||
final u = await User.fromDisk();
|
|
||||||
setState(() {
|
|
||||||
user = u;
|
|
||||||
});
|
|
||||||
} catch (_) {}
|
|
||||||
});
|
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) => loadUser());
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
|
@ -120,6 +87,7 @@ class _ChangePasswordDialogState extends State<ChangePasswordDialog> {
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final scaffMgr = ScaffoldMessenger.of(context);
|
final scaffMgr = ScaffoldMessenger.of(context);
|
||||||
final nav = Navigator.of(context);
|
final nav = Navigator.of(context);
|
||||||
|
final user = context.read<User>();
|
||||||
|
|
||||||
// validate password
|
// validate password
|
||||||
if (_ctrNewPassword.text.length < 6) {
|
if (_ctrNewPassword.text.length < 6) {
|
||||||
|
@ -139,7 +107,7 @@ class _ChangePasswordDialogState extends State<ChangePasswordDialog> {
|
||||||
_ctrNewPasswordRepeat.clear();
|
_ctrNewPasswordRepeat.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (hashPassword(_ctrOldPassword.text) != user?.password) {
|
if (hashPassword(_ctrOldPassword.text) != user.password) {
|
||||||
// current password wrong
|
// current password wrong
|
||||||
showSimpleSnackbar(scaffMgr,
|
showSimpleSnackbar(scaffMgr,
|
||||||
text: 'Old password is wrong', action: 'Dismiss');
|
text: 'Old password is wrong', action: 'Dismiss');
|
||||||
|
@ -152,18 +120,17 @@ class _ChangePasswordDialogState extends State<ChangePasswordDialog> {
|
||||||
|
|
||||||
// send request
|
// send request
|
||||||
doNetworkRequest(scaffMgr,
|
doNetworkRequest(scaffMgr,
|
||||||
needUser: false,
|
req: () => postWithCreadentials(
|
||||||
req: (_) => postWithCreadentials(
|
|
||||||
path: 'changePassword',
|
path: 'changePassword',
|
||||||
target: (user?.server)!,
|
target: user.server,
|
||||||
body: {'accountKey': password},
|
body: {'accountKey': password},
|
||||||
credentials: user!),
|
credentials: user),
|
||||||
onOK: (_) async {
|
onOK: (_) async {
|
||||||
// update local user struct
|
// update local user struct
|
||||||
final updatedUser = User(
|
final updatedUser = User(
|
||||||
username: (user?.username)!,
|
username: user.username,
|
||||||
password: password,
|
password: password,
|
||||||
server: (user?.server)!);
|
server: user.server);
|
||||||
await updatedUser.toDisk();
|
await updatedUser.toDisk();
|
||||||
},
|
},
|
||||||
after: () {
|
after: () {
|
||||||
|
|
|
@ -15,247 +15,160 @@ class SettingsPage extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SettingsPageState extends State<SettingsPage> {
|
class _SettingsPageState extends State<SettingsPage> {
|
||||||
User? user;
|
|
||||||
AccountMeta? meta;
|
|
||||||
|
|
||||||
void fetchMeta() {
|
|
||||||
doNetworkRequest(ScaffoldMessenger.of(context), req: (user) {
|
|
||||||
setState(() {
|
|
||||||
this.user = user;
|
|
||||||
});
|
|
||||||
|
|
||||||
return postWithCreadentials(
|
|
||||||
path: 'getMyAccount',
|
|
||||||
credentials: user!,
|
|
||||||
target: user.server,
|
|
||||||
body: {});
|
|
||||||
}, onOK: (body) {
|
|
||||||
final meta = AccountMeta.fromJSON(body['data']);
|
|
||||||
setState(() {
|
|
||||||
this.meta = meta;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) => fetchMeta());
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final textTheme = Theme.of(context)
|
final textTheme = Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.apply(displayColor: Theme.of(context).colorScheme.onSurface);
|
.apply(displayColor: Theme.of(context).colorScheme.onSurface);
|
||||||
|
|
||||||
|
final user = context.watch<User>();
|
||||||
|
final meta = context.watch<AccountMeta?>();
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('Settings'),
|
title: const Text('Settings'),
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
// go back
|
// go back
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.arrow_back),
|
icon: const Icon(Icons.arrow_back),
|
||||||
tooltip: "Go back",
|
tooltip: "Go back",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
body: SingleChildScrollView(
|
||||||
body: SingleChildScrollView(
|
child: Center(
|
||||||
child: Center(
|
child: Column(children: [
|
||||||
child: Column(children: [
|
// uswer information widget
|
||||||
// uswer information widget
|
Padding(
|
||||||
Padding(
|
padding: const EdgeInsets.all(14),
|
||||||
padding: const EdgeInsets.all(14),
|
child: Card(
|
||||||
child: Card(
|
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: Text('${user?.humanReadable}',
|
child: Text(user.humanReadable,
|
||||||
style: textTheme.titleLarge)),
|
style: textTheme.titleLarge)),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('Room count limit:'),
|
title: const Text('Room count limit:'),
|
||||||
subtitle: const Text(
|
subtitle: const Text(
|
||||||
'How many rooms you are allowed to own'),
|
'How many rooms you are allowed to own'),
|
||||||
trailing: Text('${meta?.maxRoomCount ?? ""}'),
|
trailing: Text('${meta?.maxRoomCount ?? ""}'),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('Room size limit:'),
|
title: const Text('Room size limit:'),
|
||||||
subtitle: const Text(
|
subtitle: const Text(
|
||||||
'How many items/products/categories each room may contain'),
|
'How many items/products/categories each room may contain'),
|
||||||
trailing: Text('${meta?.maxRoomSize ?? ""}'),
|
trailing: Text('${meta?.maxRoomSize ?? ""}'),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('Room member limit:'),
|
title: const Text('Room member limit:'),
|
||||||
subtitle: const Text(
|
subtitle: const Text(
|
||||||
'How many members each of your rooms may have'),
|
'How many members each of your rooms may have'),
|
||||||
trailing:
|
trailing:
|
||||||
Text('${meta?.maxRoomMemberCount ?? ""}')),
|
Text('${meta?.maxRoomMemberCount ?? ""}')),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('Discoverable'),
|
title: const Text('Discoverable'),
|
||||||
subtitle: const Text(
|
subtitle: const Text(
|
||||||
'Determines if your account can be discovered by users from other servers'),
|
'Determines if your account can be discovered by users from other servers'),
|
||||||
trailing: Checkbox(
|
trailing: Checkbox(
|
||||||
tristate: true,
|
tristate: true,
|
||||||
value: meta?.discoverable,
|
value: meta?.discoverable,
|
||||||
onChanged: (_) {},
|
onChanged: (_) {},
|
||||||
))
|
))
|
||||||
],
|
],
|
||||||
)))),
|
)))),
|
||||||
|
|
||||||
// change theme button
|
// change theme button
|
||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('Change Theme'),
|
title: const Text('Change Theme'),
|
||||||
subtitle: const Text(
|
subtitle: const Text(
|
||||||
'You can change between a light theme, a dark theme and automatic theme selection'),
|
'You can change between a light theme, a dark theme and automatic theme selection'),
|
||||||
trailing: const Icon(Icons.chevron_right),
|
trailing: const Icon(Icons.chevron_right),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => AlertDialog(
|
builder: (context) => AlertDialog(
|
||||||
title: const Text('Change Theme'),
|
title: const Text('Change Theme'),
|
||||||
content: SingleChildScrollView(
|
content: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(children: [
|
||||||
children: [
|
const Padding(
|
||||||
const Padding(
|
padding: EdgeInsets.all(8),
|
||||||
padding: EdgeInsets.all(8),
|
child: Text('Choose your preferred theme'),
|
||||||
child: Text('Choose your preferred theme'),
|
),
|
||||||
),
|
SegmentedButton<AppTheme>(
|
||||||
SegmentedButton<AppTheme>(
|
selected: {context.watch<AppTheme>()},
|
||||||
selected: {context.watch<AppTheme>()},
|
selectedIcon: Icon(context.watch<AppTheme>().icon),
|
||||||
selectedIcon: Icon(context.watch<AppTheme>().icon),
|
showSelectedIcon: true,
|
||||||
showSelectedIcon: true,
|
multiSelectionEnabled: false,
|
||||||
multiSelectionEnabled: false,
|
emptySelectionAllowed: false,
|
||||||
emptySelectionAllowed: false,
|
segments: AppTheme.list().map((item) {
|
||||||
segments: AppTheme.list().map((item) {
|
return ButtonSegment<AppTheme>(
|
||||||
return ButtonSegment<AppTheme>(
|
value: item,
|
||||||
value: item,
|
icon: Icon(item.icon),
|
||||||
icon: Icon(item.icon),
|
label: Text(item.name));
|
||||||
label: Text(item.name));
|
}).toList(),
|
||||||
}).toList(),
|
onSelectionChanged: (item) async {
|
||||||
onSelectionChanged: (item) async {
|
try {
|
||||||
try {
|
await item.first.toDisk();
|
||||||
await item.first.toDisk();
|
} catch (_) {}
|
||||||
} catch (_) {}
|
},
|
||||||
},
|
),
|
||||||
),
|
])),
|
||||||
]
|
actions: [
|
||||||
)
|
FilledButton(
|
||||||
),
|
child: const Text('Close'),
|
||||||
actions: [
|
onPressed: () {
|
||||||
FilledButton(
|
Navigator.of(context).pop();
|
||||||
child: const Text('Close'),
|
},
|
||||||
onPressed: () {
|
)
|
||||||
Navigator.of(context).pop();
|
],
|
||||||
},
|
));
|
||||||
)
|
},
|
||||||
],
|
),
|
||||||
));
|
|
||||||
},
|
|
||||||
),
|
|
||||||
|
|
||||||
// change password button
|
// change password button
|
||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('Change password'),
|
title: const Text('Change password'),
|
||||||
subtitle: const Text('Choose a new password for your account'),
|
subtitle: const Text('Choose a new password for your account'),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => const ChangePasswordDialog());
|
builder: (context) => const ChangePasswordDialog());
|
||||||
},
|
},
|
||||||
trailing: const Icon(Icons.chevron_right),
|
trailing: const Icon(Icons.chevron_right),
|
||||||
),
|
),
|
||||||
|
|
||||||
// export account to json
|
// export account to json
|
||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('Export account'),
|
title: const Text('Export account'),
|
||||||
subtitle: const Text('Export account data'),
|
subtitle: const Text('Export account data'),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
// TODO: show confirm dialog
|
// TODO: show confirm dialog
|
||||||
// NOTE: json dump the localstore
|
// NOTE: json dump the localstore
|
||||||
// including users and rooms
|
// including users and rooms
|
||||||
// NOTE: feature not confirmed
|
// NOTE: feature not confirmed
|
||||||
},
|
},
|
||||||
trailing: const Icon(Icons.chevron_right),
|
trailing: const Icon(Icons.chevron_right),
|
||||||
),
|
),
|
||||||
|
|
||||||
// delete account button
|
// delete account button
|
||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('Delete account'),
|
title: const Text('Delete account'),
|
||||||
subtitle: const Text('Delete your account from your homeserver'),
|
subtitle: const Text('Delete your account from your homeserver'),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
// show confirm dialog
|
// show confirm dialog
|
||||||
// NOTE: same as logout
|
// NOTE: same as logout
|
||||||
// and performs a network request
|
// and performs a network request
|
||||||
// but deletes account beforehand
|
// but deletes account beforehand
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (ctx) => AlertDialog(
|
builder: (ctx) => AlertDialog(
|
||||||
title: const Text('Delete account'),
|
title: const Text('Delete account'),
|
||||||
content: const Text(
|
content: const Text(
|
||||||
'Do you really want to delete your account?'),
|
'Do you really want to delete your account?'),
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
// close popup
|
|
||||||
Navigator.of(ctx).pop();
|
|
||||||
},
|
|
||||||
child: const Text('Cancel'),
|
|
||||||
),
|
|
||||||
FilledButton(
|
|
||||||
onPressed: () async {
|
|
||||||
// send request
|
|
||||||
final scaffMgr = ScaffoldMessenger.of(ctx);
|
|
||||||
final nav = Navigator.of(ctx);
|
|
||||||
final rmaster = Routemaster.of(ctx);
|
|
||||||
|
|
||||||
doNetworkRequest(scaffMgr,
|
|
||||||
req: (user) => postWithCreadentials(
|
|
||||||
path: 'deleteAccount',
|
|
||||||
target: (user?.server)!,
|
|
||||||
body: {},
|
|
||||||
credentials: user!),
|
|
||||||
onOK: (_) async {
|
|
||||||
// delete everything
|
|
||||||
// delete user data (meta)
|
|
||||||
try {
|
|
||||||
await User.removeDisk();
|
|
||||||
} catch (_) {}
|
|
||||||
// TODO: delete all rooms
|
|
||||||
|
|
||||||
// go back home
|
|
||||||
rmaster.replace('/');
|
|
||||||
},
|
|
||||||
after: () {
|
|
||||||
// close popup
|
|
||||||
nav.pop();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: const Text('Delete Account'),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
));
|
|
||||||
},
|
|
||||||
trailing: const Icon(Icons.chevron_right),
|
|
||||||
),
|
|
||||||
|
|
||||||
// logout button
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(8),
|
|
||||||
child: FilledButton.tonal(
|
|
||||||
child: const Text('Log out'),
|
|
||||||
onPressed: () {
|
|
||||||
// show confirm dialog
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (ctx) => AlertDialog(
|
|
||||||
title: const Text('Log out'),
|
|
||||||
content:
|
|
||||||
const Text('Do you really want to log out?'),
|
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
@ -267,24 +180,82 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||||
FilledButton(
|
FilledButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
// send request
|
// send request
|
||||||
|
final scaffMgr = ScaffoldMessenger.of(ctx);
|
||||||
|
final nav = Navigator.of(ctx);
|
||||||
final rmaster = Routemaster.of(ctx);
|
final rmaster = Routemaster.of(ctx);
|
||||||
|
|
||||||
// delete everything
|
doNetworkRequest(scaffMgr,
|
||||||
// delete user data (meta)
|
req: () => postWithCreadentials(
|
||||||
try {
|
path: 'deleteAccount',
|
||||||
await User.removeDisk();
|
target: user.server,
|
||||||
} catch (_) {}
|
body: {},
|
||||||
// TODO: delete all rooms
|
credentials: user),
|
||||||
|
onOK: (_) async {
|
||||||
|
// delete everything
|
||||||
|
// delete user data (meta)
|
||||||
|
try {
|
||||||
|
await User.removeDisk();
|
||||||
|
} catch (_) {}
|
||||||
|
// TODO: delete all rooms
|
||||||
|
|
||||||
// go back home
|
// go back home
|
||||||
rmaster.replace('/');
|
rmaster.replace('/');
|
||||||
|
},
|
||||||
|
after: () {
|
||||||
|
// close popup
|
||||||
|
nav.pop();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
child: const Text('Log out'),
|
child: const Text('Delete Account'),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
trailing: const Icon(Icons.chevron_right),
|
||||||
|
),
|
||||||
|
|
||||||
|
// logout button
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
child: FilledButton.tonal(
|
||||||
|
child: const Text('Log out'),
|
||||||
|
onPressed: () {
|
||||||
|
// show confirm dialog
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (ctx) => AlertDialog(
|
||||||
|
title: const Text('Log out'),
|
||||||
|
content:
|
||||||
|
const Text('Do you really want to log out?'),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
// close popup
|
||||||
|
Navigator.of(ctx).pop();
|
||||||
|
},
|
||||||
|
child: const Text('Cancel'),
|
||||||
|
),
|
||||||
|
FilledButton(
|
||||||
|
onPressed: () async {
|
||||||
|
// send request
|
||||||
|
final rmaster = Routemaster.of(ctx);
|
||||||
|
|
||||||
|
// delete everything
|
||||||
|
// delete user data (meta)
|
||||||
|
try {
|
||||||
|
await User.removeDisk();
|
||||||
|
} catch (_) {}
|
||||||
|
// TODO: delete all rooms
|
||||||
|
|
||||||
|
// go back home
|
||||||
|
rmaster.replace('/');
|
||||||
|
},
|
||||||
|
child: const Text('Log out'),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
));
|
||||||
|
},
|
||||||
))
|
))
|
||||||
]))));
|
]))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,54 +1,19 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:outbag_app/backend/errors.dart';
|
import 'package:outbag_app/backend/errors.dart';
|
||||||
import 'package:outbag_app/backend/request.dart';
|
import 'package:outbag_app/backend/request.dart';
|
||||||
import 'package:outbag_app/backend/user.dart';
|
|
||||||
import 'package:outbag_app/tools/snackbar.dart';
|
import 'package:outbag_app/tools/snackbar.dart';
|
||||||
|
|
||||||
void doNetworkRequest(ScaffoldMessengerState? sm,
|
void doNetworkRequest(ScaffoldMessengerState? sm,
|
||||||
{required Future<Response> Function(User?) req,
|
{required Future<Response> Function() req,
|
||||||
Function(Map<String, dynamic>)? onOK,
|
Function(Map<String, dynamic> body)? onOK,
|
||||||
bool Function()? onNetworkErr,
|
bool Function()? onNetworkErr,
|
||||||
bool Function()? onUnknownErr,
|
bool Function()? onUnknownErr,
|
||||||
bool Function()? onUserErr,
|
|
||||||
Function()? onAnyErr,
|
Function()? onAnyErr,
|
||||||
Function()? after,
|
Function()? after,
|
||||||
bool Function(Map<String, dynamic>)? onServerErr,
|
bool Function(Map<String, dynamic>)? onServerErr}) async {
|
||||||
bool needUser = true}) async {
|
|
||||||
User? user;
|
|
||||||
try {
|
|
||||||
user = await User.fromDisk();
|
|
||||||
} catch (_) {
|
|
||||||
// no user data available
|
|
||||||
if (needUser) {
|
|
||||||
// show error & quit
|
|
||||||
bool showBar = true;
|
|
||||||
|
|
||||||
if (onUserErr != null) {
|
|
||||||
showBar = onUserErr();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showBar && sm != null) {
|
|
||||||
showSimpleSnackbar(sm, text: 'No user found', action: 'Authorize',
|
|
||||||
onTap: () {
|
|
||||||
try {
|
|
||||||
// try to remove broken user
|
|
||||||
User.removeDisk();
|
|
||||||
} catch (_) {}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (onAnyErr != null) {
|
|
||||||
onAnyErr();
|
|
||||||
}
|
|
||||||
if (after != null) {
|
|
||||||
after();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Response res;
|
Response res;
|
||||||
try {
|
try {
|
||||||
res = await req(user);
|
res = await req();
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
// network error
|
// network error
|
||||||
bool showBar = true;
|
bool showBar = true;
|
||||||
|
|
Loading…
Reference in a new issue