Skip to content

Commit

Permalink
Merge pull request #28 from ProductsWay/feature/show-wallet-on-accoun…
Browse files Browse the repository at this point in the history
…t-screen
  • Loading branch information
jellydn authored Oct 25, 2021
2 parents ba43aca + ee612d2 commit 9e21e3b
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 134 deletions.
1 change: 0 additions & 1 deletion mobile/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ class MyApp extends StatelessWidget {
'/': (_) => const SplashPage(),
'/login': (_) => const LoginPage(),
'/account': (_) => const AccountPage(),
'/wallet': (_) => const WalletPage(),
},
);
}
Expand Down
151 changes: 24 additions & 127 deletions mobile/lib/pages/account_page.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import 'package:flutter/material.dart';
import 'package:supabase/supabase.dart';
import 'package:conce_app/pages/user_profile_page.dart';
import 'package:conce_app/pages/wallet_page.dart';
import 'package:conce_app/components/auth_required_state.dart';
import 'package:conce_app/components/avatar.dart';
import 'package:conce_app/utils/constants.dart';

class AccountPage extends StatefulWidget {
const AccountPage({Key? key}) : super(key: key);
Expand All @@ -12,138 +11,36 @@ class AccountPage extends StatefulWidget {
}

class _AccountPageState extends AuthRequiredState<AccountPage> {
final _usernameController = TextEditingController();
final _websiteController = TextEditingController();
String? _userId;
String? _avatarUrl;
var _loading = false;

/// Called once a user id is received within `onAuthenticated()`
Future<void> _getProfile(String userId) async {
setState(() {
_loading = true;
});
final response = await supabase
.from('profiles')
.select()
.eq('id', userId)
.single()
.execute();
final error = response.error;
if (error != null && response.status != 406) {
context.showErrorSnackBar(message: error.message);
}
final data = response.data;
if (data != null) {
_usernameController.text = (data['username'] ?? '') as String;
_websiteController.text = (data['website'] ?? '') as String;
_avatarUrl = (data['avatar_url'] ?? '') as String;
}
setState(() {
_loading = false;
});
}

/// Called when user taps `Update` button
Future<void> _updateProfile() async {
setState(() {
_loading = true;
});
final userName = _usernameController.text;
final website = _websiteController.text;
final user = supabase.auth.currentUser;
final updates = {
'id': user!.id,
'username': userName,
'website': website,
'updated_at': DateTime.now().toIso8601String(),
};
final response = await supabase.from('profiles').upsert(updates).execute();
final error = response.error;
if (error != null) {
context.showErrorSnackBar(message: error.message);
} else {
context.showSnackBar(message: 'Successfully updated profile!');
}
setState(() {
_loading = false;
});
}

Future<void> _signOut() async {
final response = await supabase.auth.signOut();
final error = response.error;
if (error != null) {
context.showErrorSnackBar(message: error.message);
}
Navigator.of(context).pushReplacementNamed('/login');
}

/// Called when image has been uploaded to Supabase storage from within Avatar widget
Future<void> _onUpload(String imageUrl) async {
final response = await supabase.from('profiles').upsert({
'id': _userId,
'avatar_url': imageUrl,
}).execute();
final error = response.error;
if (error != null) {
context.showErrorSnackBar(message: error.message);
}
setState(() {
_avatarUrl = imageUrl;
});
context.showSnackBar(message: 'Updated your profile image!');
}

@override
void onAuthenticated(Session session) {
final user = session.user;
if (user != null) {
_userId = user.id;
_getProfile(user.id);
}
}

@override
void onUnauthenticated() {
Navigator.of(context).pushReplacementNamed('/login');
}

@override
void dispose() {
_usernameController.dispose();
_websiteController.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Profile')),
body: ListView(
padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 12),
children: [
Avatar(
imageUrl: _avatarUrl,
onUpload: _onUpload,
),
const SizedBox(height: 18),
TextFormField(
controller: _usernameController,
decoration: const InputDecoration(labelText: 'User Name'),
),
const SizedBox(height: 18),
TextFormField(
controller: _websiteController,
decoration: const InputDecoration(labelText: 'Website'),
// show 2 tabs: user profile and wallet
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
title: const Text('Account'),
bottom: const TabBar(
tabs: [
Tab(
text: 'Profile',
),
Tab(
text: 'Wallet',
),
],
),
const SizedBox(height: 18),
ElevatedButton(
onPressed: _updateProfile,
child: Text(_loading ? 'Saving...' : 'Update')),
const SizedBox(height: 18),
ElevatedButton(onPressed: _signOut, child: const Text('Sign Out')),
],
),
body: const TabBarView(
children: [
UserProfilePage(),
WalletPage(),
],
),
),
);
}
Expand Down
147 changes: 147 additions & 0 deletions mobile/lib/pages/user_profile_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import 'package:flutter/material.dart';
import 'package:supabase/supabase.dart';
import 'package:conce_app/components/auth_required_state.dart';
import 'package:conce_app/components/avatar.dart';
import 'package:conce_app/utils/constants.dart';

class UserProfilePage extends StatefulWidget {
const UserProfilePage({Key? key}) : super(key: key);

@override
_UserProfilePageState createState() => _UserProfilePageState();
}

class _UserProfilePageState extends AuthRequiredState<UserProfilePage> {
final _usernameController = TextEditingController();
final _websiteController = TextEditingController();
String? _userId;
String? _avatarUrl;
var _loading = false;

/// Called once a user id is received within `onAuthenticated()`
Future<void> _getProfile(String userId) async {
setState(() {
_loading = true;
});
final response = await supabase
.from('profiles')
.select()
.eq('id', userId)
.single()
.execute();
final error = response.error;
if (error != null && response.status != 406) {
context.showErrorSnackBar(message: error.message);
}
final data = response.data;
if (data != null) {
_usernameController.text = (data['username'] ?? '') as String;
_websiteController.text = (data['website'] ?? '') as String;
_avatarUrl = (data['avatar_url'] ?? '') as String;
}
setState(() {
_loading = false;
});
}

/// Called when user taps `Update` button
Future<void> _updateProfile() async {
setState(() {
_loading = true;
});
final userName = _usernameController.text;
final website = _websiteController.text;
final user = supabase.auth.currentUser;
final updates = {
'id': user!.id,
'username': userName,
'website': website,
'updated_at': DateTime.now().toIso8601String(),
};
final response = await supabase.from('profiles').upsert(updates).execute();
final error = response.error;
if (error != null) {
context.showErrorSnackBar(message: error.message);
} else {
context.showSnackBar(message: 'Successfully updated profile!');
}
setState(() {
_loading = false;
});
}

Future<void> _signOut() async {
final response = await supabase.auth.signOut();
final error = response.error;
if (error != null) {
context.showErrorSnackBar(message: error.message);
}
Navigator.of(context).pushReplacementNamed('/login');
}

/// Called when image has been uploaded to Supabase storage from within Avatar widget
Future<void> _onUpload(String imageUrl) async {
final response = await supabase.from('profiles').upsert({
'id': _userId,
'avatar_url': imageUrl,
}).execute();
final error = response.error;
if (error != null) {
context.showErrorSnackBar(message: error.message);
}
setState(() {
_avatarUrl = imageUrl;
});
context.showSnackBar(message: 'Updated your profile image!');
}

@override
void onAuthenticated(Session session) {
final user = session.user;
if (user != null) {
_userId = user.id;
_getProfile(user.id);
}
}

@override
void onUnauthenticated() {
Navigator.of(context).pushReplacementNamed('/login');
}

@override
void dispose() {
_usernameController.dispose();
_websiteController.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
return ListView(
padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 12),
children: [
Avatar(
imageUrl: _avatarUrl,
onUpload: _onUpload,
),
const SizedBox(height: 18),
TextFormField(
controller: _usernameController,
decoration: const InputDecoration(labelText: 'User Name'),
),
const SizedBox(height: 18),
TextFormField(
controller: _websiteController,
decoration: const InputDecoration(labelText: 'Website'),
),
const SizedBox(height: 18),
ElevatedButton(
onPressed: _updateProfile,
child: Text(_loading ? 'Saving...' : 'Update')),
const SizedBox(height: 18),
ElevatedButton(onPressed: _signOut, child: const Text('Sign Out')),
],
);
}
}
8 changes: 2 additions & 6 deletions mobile/lib/pages/wallet_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,7 @@ class _WalletPageState extends AuthRequiredState<WalletPage> {

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Wallet')),
body: ListView(
return ListView(
padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 12),
children: [
// showl loading text or wallet address
Expand All @@ -69,8 +67,6 @@ class _WalletPageState extends AuthRequiredState<WalletPage> {
style: Theme.of(context).textTheme.headline6,
),
const SizedBox(height: 18),
],
),
);
]);
}
}

0 comments on commit 9e21e3b

Please sign in to comment.