Compare commits
No commits in common. "bad485ac1d4f1da9f3d5d37456e2eae2a279705d" and "7647542421324a79310f0aa823a66396e0df87ed" have entirely different histories.
bad485ac1d
...
7647542421
@ -29,8 +29,6 @@ def get(user, id):
|
||||
owner = user and (user.get('_id') == proj['user'])
|
||||
if not owner and proj['visibility'] != 'public':
|
||||
raise util.errors.BadRequest('Forbidden')
|
||||
if obj['type'] == 'file' and 'storedName' in obj:
|
||||
obj['url'] = uploads.get_presigned_url('projects/{0}/{1}'.format(proj['_id'], obj['storedName']))
|
||||
if obj['type'] == 'pattern' and 'preview' in obj and '.png' in obj['preview']:
|
||||
obj['previewUrl'] = uploads.get_presigned_url('projects/{0}/{1}'.format(proj['_id'], obj['preview']))
|
||||
del obj['preview']
|
||||
|
1
mobile/flutter_jank_metrics_01.json
Normal file
1
mobile/flutter_jank_metrics_01.json
Normal file
File diff suppressed because one or more lines are too long
1
mobile/flutter_jank_metrics_02.json
Normal file
1
mobile/flutter_jank_metrics_02.json
Normal file
File diff suppressed because one or more lines are too long
@ -6,41 +6,31 @@ import 'group_noticeboard.dart';
|
||||
import 'group_members.dart';
|
||||
|
||||
class _GroupScreenState extends State<GroupScreen> {
|
||||
final String id;
|
||||
Map<String, dynamic>? _group;
|
||||
int _selectedIndex = 0;
|
||||
List<Widget> _widgetOptions = <Widget> [];
|
||||
final Map<String, dynamic> _group;
|
||||
|
||||
_GroupScreenState(this.id) { }
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
fetchGroup();
|
||||
super.initState();
|
||||
_GroupScreenState(this._group) {
|
||||
_widgetOptions = <Widget> [
|
||||
GroupNoticeBoardTab(this._group),
|
||||
GroupMembersTab(this._group)
|
||||
];
|
||||
}
|
||||
|
||||
void fetchGroup() async {
|
||||
Api api = Api();
|
||||
var data = await api.request('GET', '/groups/' + id);
|
||||
if (data['success'] == true) {
|
||||
setState(() {
|
||||
_group = data['payload'];
|
||||
});
|
||||
}
|
||||
void _onItemTapped(int index) {
|
||||
setState(() {
|
||||
_selectedIndex = index;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(_group?['name'] ?? 'Group')
|
||||
title: Text(_group['name'])
|
||||
),
|
||||
body: Center(
|
||||
child: _group != null ?
|
||||
[
|
||||
GroupNoticeBoardTab(_group!),
|
||||
GroupMembersTab(_group!)
|
||||
].elementAt(_selectedIndex)
|
||||
: CircularProgressIndicator(),
|
||||
child: _widgetOptions.elementAt(_selectedIndex),
|
||||
),
|
||||
bottomNavigationBar: BottomNavigationBar(
|
||||
items: const <BottomNavigationBarItem>[
|
||||
@ -55,17 +45,15 @@ class _GroupScreenState extends State<GroupScreen> {
|
||||
],
|
||||
currentIndex: _selectedIndex,
|
||||
selectedItemColor: Colors.pink[600],
|
||||
onTap: (int index) => setState(() {
|
||||
_selectedIndex = index;
|
||||
}),
|
||||
onTap: _onItemTapped,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class GroupScreen extends StatefulWidget {
|
||||
final String id;
|
||||
GroupScreen(this.id) { }
|
||||
final Map<String,dynamic> group;
|
||||
GroupScreen(this.group) { }
|
||||
@override
|
||||
_GroupScreenState createState() => _GroupScreenState(id);
|
||||
_GroupScreenState createState() => _GroupScreenState(group);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'group.dart';
|
||||
import 'api.dart';
|
||||
import 'model.dart';
|
||||
import 'lib.dart';
|
||||
@ -16,8 +16,6 @@ class _GroupsTabState extends State<GroupsTab> {
|
||||
}
|
||||
|
||||
void getGroups() async {
|
||||
AppModel model = Provider.of<AppModel>(context, listen: false);
|
||||
if (model.user == null) return;
|
||||
setState(() => _loading = true);
|
||||
Api api = Api();
|
||||
var data = await api.request('GET', '/groups');
|
||||
@ -38,7 +36,14 @@ class _GroupsTabState extends State<GroupsTab> {
|
||||
}
|
||||
return Card(
|
||||
child: InkWell(
|
||||
onTap: () => context.push('/groups/' + group['_id']),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => GroupScreen(group),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: ListTile(
|
||||
leading: Icon(Icons.people),
|
||||
trailing: Icon(Icons.keyboard_arrow_right),
|
||||
|
@ -263,7 +263,12 @@ class PatternCard extends StatelessWidget {
|
||||
),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
context.push('/' + object['userObject']['username'] + '/' + object['projectObject']['path'] + '/' + object['_id']);
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ObjectScreen(object, object['projectObject']),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
|
@ -13,9 +13,7 @@ import 'register.dart';
|
||||
import 'onboarding.dart';
|
||||
import 'home.dart';
|
||||
import 'project.dart';
|
||||
import 'object.dart';
|
||||
import 'settings.dart';
|
||||
import 'group.dart';
|
||||
|
||||
final router = GoRouter(
|
||||
routes: [
|
||||
@ -39,9 +37,7 @@ final router = GoRouter(
|
||||
GoRoute(path: '/onboarding', builder: (context, state) => OnboardingScreen()),
|
||||
GoRoute(path: '/home', builder: (context, state) => HomeScreen()),
|
||||
GoRoute(path: '/settings', builder: (context, state) => SettingsScreen()),
|
||||
GoRoute(path: '/groups/:id', builder: (context, state) => GroupScreen(state.pathParameters['id']!)),
|
||||
GoRoute(path: '/:username/:path', builder: (context, state) => ProjectScreen(state.pathParameters['username']!, state.pathParameters['path']!)),
|
||||
GoRoute(path: '/:username/:path/:id', builder: (context, state) => ObjectScreen(state.pathParameters['username']!, state.pathParameters['path']!, state.pathParameters['id']!)),
|
||||
GoRoute(path: '/:username/:id', builder: (context, state) => ProjectScreen(state.pathParameters['username']!, state.pathParameters['id']!)),
|
||||
],
|
||||
);
|
||||
|
||||
@ -118,7 +114,9 @@ class Startup extends StatelessWidget {
|
||||
_handled = true;
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
String? token = prefs.getString('apiToken');
|
||||
print('Nooo');
|
||||
if (token != null) {
|
||||
print('HEE');
|
||||
AppModel model = Provider.of<AppModel>(context, listen: false);
|
||||
await model.setToken(token!);
|
||||
FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
|
||||
|
@ -3,7 +3,6 @@ import 'package:flutter/cupertino.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:flutter_html/flutter_html.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'dart:io';
|
||||
import 'api.dart';
|
||||
import 'util.dart';
|
||||
@ -11,32 +10,30 @@ import 'patterns/pattern.dart';
|
||||
import 'patterns/viewer.dart';
|
||||
|
||||
class _ObjectScreenState extends State<ObjectScreen> {
|
||||
final String username;
|
||||
final String projectPath;
|
||||
final String id;
|
||||
final Map<String,dynamic>? project;
|
||||
Map<String,dynamic>? object;
|
||||
Map<String,dynamic>? pattern;
|
||||
final Map<String,dynamic> _project;
|
||||
Map<String,dynamic> _object;
|
||||
Map<String,dynamic>? _pattern;
|
||||
bool _isLoading = false;
|
||||
final Function? onUpdate;
|
||||
final Function? onDelete;
|
||||
final Api api = Api();
|
||||
final Util util = Util();
|
||||
|
||||
_ObjectScreenState(this.username, this.projectPath, this.id, {this.object, this.project, this.onUpdate, this.onDelete}) { }
|
||||
_ObjectScreenState(this._object, this._project, {this.onUpdate, this.onDelete}) { }
|
||||
|
||||
@override
|
||||
initState() {
|
||||
super.initState();
|
||||
fetchObject();
|
||||
if (_object['type'] == 'pattern') {
|
||||
_fetchPattern();
|
||||
}
|
||||
}
|
||||
|
||||
void fetchObject() async {
|
||||
var data = await api.request('GET', '/objects/' + id);
|
||||
void _fetchPattern() async {
|
||||
var data = await api.request('GET', '/objects/' + _object['_id']);
|
||||
if (data['success'] == true) {
|
||||
setState(() {
|
||||
object = data['payload'];
|
||||
pattern = data['payload']['pattern'];
|
||||
_pattern = data['payload']['pattern'];
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -44,14 +41,14 @@ class _ObjectScreenState extends State<ObjectScreen> {
|
||||
void _shareObject() async {
|
||||
setState(() => _isLoading = true);
|
||||
File? file;
|
||||
if (object!['type'] == 'pattern') {
|
||||
var data = await api.request('GET', '/objects/' + id + '/wif');
|
||||
if (_object['type'] == 'pattern') {
|
||||
var data = await api.request('GET', '/objects/' + _object['_id'] + '/wif');
|
||||
if (data['success'] == true) {
|
||||
file = await util.writeFile(object!['name'] + '.wif', data['payload']['wif']);
|
||||
file = await util.writeFile(_object['name'] + '.wif', data['payload']['wif']);
|
||||
}
|
||||
} else {
|
||||
String fileName = Uri.file(object!['url']).pathSegments.last;
|
||||
file = await api.downloadFile(object!['url'], fileName);
|
||||
String fileName = Uri.file(_object['url']).pathSegments.last;
|
||||
file = await api.downloadFile(_object['url'], fileName);
|
||||
}
|
||||
|
||||
if (file != null) {
|
||||
@ -61,10 +58,12 @@ class _ObjectScreenState extends State<ObjectScreen> {
|
||||
}
|
||||
|
||||
void _deleteObject(BuildContext context, BuildContext modalContext) async {
|
||||
var data = await api.request('DELETE', '/objects/' + id);
|
||||
var data = await api.request('DELETE', '/objects/' + _object['_id']);
|
||||
if (data['success']) {
|
||||
context.go('/home');
|
||||
onDelete!(id);
|
||||
Navigator.pop(context);
|
||||
Navigator.pop(modalContext);
|
||||
Navigator.pop(context);
|
||||
onDelete!(_object['_id']);
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,7 +77,7 @@ class _ObjectScreenState extends State<ObjectScreen> {
|
||||
CupertinoDialogAction(
|
||||
isDefaultAction: true,
|
||||
child: Text('No'),
|
||||
onPressed: () => context.pop(),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
CupertinoDialogAction(
|
||||
isDestructiveAction: true,
|
||||
@ -106,22 +105,22 @@ class _ObjectScreenState extends State<ObjectScreen> {
|
||||
TextButton(
|
||||
child: Text('CANCEL'),
|
||||
onPressed: () {
|
||||
context.pop();
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: Text('OK'),
|
||||
onPressed: () async {
|
||||
var data = await api.request('PUT', '/objects/' + id, {'name': renameController.text});
|
||||
var data = await api.request('PUT', '/objects/' + _object['_id'], {'name': renameController.text});
|
||||
if (data['success']) {
|
||||
context.pop();
|
||||
object!['name'] = data['payload']['name'];
|
||||
onUpdate!(id, data['payload']);
|
||||
Navigator.pop(context);
|
||||
_object['name'] = data['payload']['name'];
|
||||
onUpdate!(_object['_id'], data['payload']);
|
||||
setState(() {
|
||||
object = object;
|
||||
_object = _object;
|
||||
});
|
||||
}
|
||||
context.pop();
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
],
|
||||
@ -137,7 +136,7 @@ class _ObjectScreenState extends State<ObjectScreen> {
|
||||
return CupertinoActionSheet(
|
||||
title: Text('Manage this object'),
|
||||
cancelButton: CupertinoActionSheetAction(
|
||||
onPressed: () => modalContext.pop(),
|
||||
onPressed: () => Navigator.of(modalContext).pop(),
|
||||
child: Text('Cancel')
|
||||
),
|
||||
actions: [
|
||||
@ -157,22 +156,15 @@ class _ObjectScreenState extends State<ObjectScreen> {
|
||||
}
|
||||
|
||||
Widget getObjectWidget() {
|
||||
if (object == null) {
|
||||
return Center(child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [CircularProgressIndicator()]
|
||||
));
|
||||
if (_object['isImage'] == true) {
|
||||
return Image.network(_object['url']);
|
||||
}
|
||||
else if (object!['isImage'] == true && object!['url'] != null) {
|
||||
print(object!['url']);
|
||||
return Image.network(object!['url']);
|
||||
}
|
||||
else if (object!['type'] == 'pattern') {
|
||||
if (pattern != null) {
|
||||
return PatternViewer(pattern!, withEditor: true);
|
||||
else if (_object['type'] == 'pattern') {
|
||||
if (_pattern != null) {
|
||||
return PatternViewer(_pattern!, withEditor: true);
|
||||
}
|
||||
else if (object!['previewUrl'] != null) {
|
||||
return Image.network(object!['previewUrl']!);;
|
||||
else if (_object['previewUrl'] != null) {
|
||||
return Image.network(_object['previewUrl']!);;
|
||||
}
|
||||
else {
|
||||
return Column(
|
||||
@ -192,7 +184,7 @@ class _ObjectScreenState extends State<ObjectScreen> {
|
||||
Text('Treadl cannot display this type of item.'),
|
||||
SizedBox(height: 20),
|
||||
ElevatedButton(child: Text('View file'), onPressed: () {
|
||||
launch(object!['url']);
|
||||
launch(_object['url']);
|
||||
}),
|
||||
],
|
||||
));
|
||||
@ -202,11 +194,11 @@ class _ObjectScreenState extends State<ObjectScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String description = '';
|
||||
if (object?['description'] != null)
|
||||
description = object!['description']!;
|
||||
if (_object['description'] != null)
|
||||
description = _object['description'];
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(object?['name'] ?? 'Object'),
|
||||
title: Text(_object['name']),
|
||||
actions: <Widget>[
|
||||
IconButton(
|
||||
icon: Icon(Icons.ios_share),
|
||||
@ -236,15 +228,12 @@ class _ObjectScreenState extends State<ObjectScreen> {
|
||||
}
|
||||
|
||||
class ObjectScreen extends StatefulWidget {
|
||||
final String username;
|
||||
final String projectPath;
|
||||
final String id;
|
||||
final Map<String,dynamic>? object;
|
||||
final Map<String,dynamic>? project;
|
||||
final Map<String,dynamic> _object;
|
||||
final Map<String,dynamic> _project;
|
||||
final Function? onUpdate;
|
||||
final Function? onDelete;
|
||||
ObjectScreen(this.username, this.projectPath, this.id, {this.object, this.project, this.onUpdate, this.onDelete}) { }
|
||||
ObjectScreen(this._object, this._project, {this.onUpdate, this.onDelete}) { }
|
||||
@override
|
||||
_ObjectScreenState createState() => _ObjectScreenState(username, projectPath, id, object: object, project: project, onUpdate: onUpdate, onDelete: onDelete);
|
||||
_ObjectScreenState createState() => _ObjectScreenState(_object, _project, onUpdate: onUpdate, onDelete: onDelete);
|
||||
}
|
||||
|
||||
|
@ -112,7 +112,7 @@ class _OnboardingScreenState extends State<OnboardingScreen> {
|
||||
CupertinoButton(
|
||||
color: Colors.white,
|
||||
child: Text('Get started', style: TextStyle(color: Colors.pink)),
|
||||
onPressed: () => context.go('/home'),
|
||||
onPressed: () => context.go('/'),
|
||||
),
|
||||
]
|
||||
)
|
||||
|
@ -9,7 +9,7 @@ import 'package:intl/intl.dart';
|
||||
import 'dart:io';
|
||||
import 'api.dart';
|
||||
import 'util.dart';
|
||||
import 'model.dart';
|
||||
import 'object.dart';
|
||||
|
||||
class _ProjectScreenState extends State<ProjectScreen> {
|
||||
final String username;
|
||||
@ -252,7 +252,12 @@ class _ProjectScreenState extends State<ProjectScreen> {
|
||||
return new Card(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
context.push('/' + username + '/' + projectPath + '/' + object['_id']);
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ObjectScreen(object, project!, onUpdate: _onUpdateObject, onDelete: _onDeleteObject),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: ListTile(
|
||||
leading: leader,
|
||||
@ -264,31 +269,8 @@ class _ProjectScreenState extends State<ProjectScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget getBody() {
|
||||
if (_loading || project == null)
|
||||
return CircularProgressIndicator();
|
||||
else if ((_objects != null && _objects.length > 0) || _creating)
|
||||
return ListView.builder(
|
||||
itemCount: _objects.length + (_creating ? 1 : 0),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return getObjectCard(index);
|
||||
},
|
||||
);
|
||||
else
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text('This project is currently empty', style: TextStyle(fontSize: 20), textAlign: TextAlign.center),
|
||||
Image(image: AssetImage('assets/empty.png'), width: 300),
|
||||
Text('Add a pattern file, an image, or something else to this project using the + button below.', textAlign: TextAlign.center),
|
||||
]);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
AppModel model = Provider.of<AppModel>(context);
|
||||
User? user = model.user;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(project?['name'] ?? 'Project'),
|
||||
@ -307,13 +289,33 @@ class _ProjectScreenState extends State<ProjectScreen> {
|
||||
) : SizedBox(width: 0),
|
||||
]
|
||||
),
|
||||
body: Container(
|
||||
body: _loading ?
|
||||
Container(
|
||||
margin: const EdgeInsets.all(10.0),
|
||||
alignment: Alignment.center,
|
||||
child: CircularProgressIndicator()
|
||||
)
|
||||
: Container(
|
||||
margin: const EdgeInsets.all(10.0),
|
||||
alignment: Alignment.center,
|
||||
child: getBody(),
|
||||
child: ((_objects != null && _objects.length > 0) || _creating) ?
|
||||
ListView.builder(
|
||||
itemCount: _objects.length + (_creating ? 1 : 0),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return getObjectCard(index);
|
||||
},
|
||||
)
|
||||
:
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text('This project is currently empty', style: TextStyle(fontSize: 20), textAlign: TextAlign.center),
|
||||
Image(image: AssetImage('assets/empty.png'), width: 300),
|
||||
Text('Add a pattern file, an image, or something else to this project using the + button below.', textAlign: TextAlign.center),
|
||||
])
|
||||
),
|
||||
floatingActionButtonLocation: ExpandableFab.location,
|
||||
floatingActionButton: user != null ? ExpandableFab(
|
||||
floatingActionButton: ExpandableFab(
|
||||
distance: 70,
|
||||
type: ExpandableFabType.up,
|
||||
openButtonBuilder: RotateFloatingActionButtonBuilder(
|
||||
@ -353,7 +355,7 @@ class _ProjectScreenState extends State<ProjectScreen> {
|
||||
),
|
||||
]),
|
||||
],
|
||||
) : null,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -19,8 +19,6 @@ class _ProjectsTabState extends State<ProjectsTab> {
|
||||
}
|
||||
|
||||
void getProjects() async {
|
||||
AppModel model = Provider.of<AppModel>(context, listen: false);
|
||||
if (model.user == null) return;
|
||||
setState(() {
|
||||
_loading = true;
|
||||
});
|
||||
@ -133,8 +131,6 @@ class _ProjectsTabState extends State<ProjectsTab> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
AppModel model = Provider.of<AppModel>(context);
|
||||
User? user = model.user;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('My Projects'),
|
||||
@ -152,11 +148,11 @@ class _ProjectsTabState extends State<ProjectsTab> {
|
||||
alignment: Alignment.center,
|
||||
child: getBody()
|
||||
),
|
||||
floatingActionButton: user != null ? FloatingActionButton(
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: showNewProjectDialog,
|
||||
child: _creatingProject ? CircularProgressIndicator(backgroundColor: Colors.white) : Icon(Icons.add),
|
||||
backgroundColor: Colors.pink[500],
|
||||
) : null,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -79,8 +79,6 @@ class SettingsScreen extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
AppModel model = Provider.of<AppModel>(context);
|
||||
User? user = model.user;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('About Treadl'),
|
||||
@ -99,23 +97,15 @@ class SettingsScreen extends StatelessWidget {
|
||||
|
||||
SizedBox(height: 30),
|
||||
|
||||
user != null ? Column(
|
||||
children: [
|
||||
ListTile(
|
||||
leading: Icon(Icons.exit_to_app),
|
||||
title: Text('Logout'),
|
||||
onTap: () => _logout(context),
|
||||
),
|
||||
ListTile(
|
||||
leading: Icon(Icons.delete),
|
||||
title: Text('Delete Account'),
|
||||
onTap: () => _deleteAccount(context),
|
||||
),
|
||||
]
|
||||
) : CupertinoButton(
|
||||
color: Colors.pink,
|
||||
child: Text('Join Treadl', style: TextStyle(color: Colors.white)),
|
||||
onPressed: () => context.push('/welcome'),
|
||||
ListTile(
|
||||
leading: Icon(Icons.exit_to_app),
|
||||
title: Text('Logout'),
|
||||
onTap: () => _logout(context),
|
||||
),
|
||||
ListTile(
|
||||
leading: Icon(Icons.delete),
|
||||
title: Text('Delete Account'),
|
||||
onTap: () => _deleteAccount(context),
|
||||
),
|
||||
|
||||
SizedBox(height: 30),
|
||||
|
Loading…
Reference in New Issue
Block a user