Skip to content

Commit

Permalink
Remembering user's login details, bug fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
jumpiniasty committed Jul 5, 2023
1 parent 196d1b9 commit 9846e1b
Show file tree
Hide file tree
Showing 12 changed files with 175 additions and 104 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ flutter install

## API

Drinkify uses [liquor-lovers](https://github.com/Kawaii-Addicts/liquor-lovers). Make sure to install it and run in order to use all the features provided by the app.
Drinkify uses [liquor-lovers](https://github.com/Kawaii-Addicts/liquor-lovers). Without it, app won't be able to work properly.

## Contributing

Expand Down
1 change: 0 additions & 1 deletion l10n.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
untranslated-messages-file: untranslated_msgs.txt
21 changes: 11 additions & 10 deletions lib/controllers/auth_controller.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:http/http.dart' as http;
import 'package:http_parser/http_parser.dart';
Expand All @@ -11,20 +10,18 @@ import '../models/create_user.dart';

///Used for logging in and signing up a user
class AuthController {
///Used only for logging in
TextEditingController emailCtrl = TextEditingController();

///Used only for logging in
TextEditingController passwordCtrl = TextEditingController();

///Handles logging in
Future<bool> loginUser() async {
static Future<bool> loginUser(
String email,
String password,
bool rememberMe,
) async {
final url = "$mainUrl/auth/token/";
final res = await http.post(
Uri.parse(url),
body: {
"email": emailCtrl.text,
"password": passwordCtrl.text,
"email": email,
"password": password,
},
);
if (res.statusCode == 200) {
Expand All @@ -38,6 +35,10 @@ class AuthController {
key: "refresh",
value: loginArr["refresh"],
);
await storage.write(
key: "remember",
value: "$rememberMe",
);
return true;
}
return false;
Expand Down
6 changes: 4 additions & 2 deletions lib/controllers/search_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ class SearchController {
return users;
}

static Future<List<Party>> seachPartiesByDistance(double meters) async {
static Future<List<Party>> seachPartiesByDistance({
double meters = 1000,
}) async {
const storage = FlutterSecureStorage();
final token = await storage.read(key: "access");
final url = "$mainUrl/parties/?range=$meters";
Expand All @@ -39,7 +41,7 @@ class SearchController {
},
);
final parties = <Party>[];
for (final p in jsonDecode(res.body)) {
for (final p in jsonDecode(res.body)["results"]) {
parties.add(Party.fromMap(p));
}
return parties;
Expand Down
65 changes: 44 additions & 21 deletions lib/routes/login_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,34 +16,39 @@ class LoginPage extends StatefulWidget {
}

class _LoginPageState extends State<LoginPage> {
late final AuthController authCtrl;
late String email;
late String password;
late final TextEditingController passwordResetEmailCtrl;
late bool rememberPassword;
late int? selectedFieldIndex;

@override
void initState() {
super.initState();
//TODO do the points below
// 1. check if JWT access token is still active
// 2. if so redirect user to home page
// 3. if access token is not active show regular login page instead of routing
authCtrl = AuthController();
passwordResetEmailCtrl = TextEditingController();
email = "";
password = "";
rememberPassword = false;
selectedFieldIndex = null;
}

@override
void dispose() {
super.dispose();
authCtrl.emailCtrl.dispose();
authCtrl.passwordCtrl.dispose();
passwordResetEmailCtrl.dispose();
WidgetsBinding.instance.addPostFrameCallback((_) async {
const storage = FlutterSecureStorage();
final storageEmail = await storage.read(key: "user_email");
final storagePassword = await storage.read(key: "user_password");
final storageRemember = await storage.read(key: "remember");
if (storageRemember != "true" ||
storageEmail == null ||
storagePassword == null) return;
final loggedIn = await AuthController.loginUser(
storageEmail,
storagePassword,
true,
);
if (loggedIn && mounted) context.go("/");
});
}

bool get _userCanLogin {
return !(authCtrl.emailCtrl.text == "" || authCtrl.passwordCtrl.text == "");
return !(email.isEmpty || password.isEmpty);
}

void _onFieldSelect(int index) {
Expand Down Expand Up @@ -86,19 +91,21 @@ class _LoginPageState extends State<LoginPage> {
caption: AppLocalizations.of(context)!.email,
icon: Icons.email_rounded,
placeholder: AppLocalizations.of(context)!.emailField,
ctrl: authCtrl.emailCtrl,
additionalValue: email,
keyboardType: TextInputType.emailAddress,
onSelect: (idx) => _onFieldSelect(idx),
onType: (val) => email = val,
),
EditField(
index: 1,
selectedFieldIndex: selectedFieldIndex,
caption: AppLocalizations.of(context)!.password,
icon: Icons.password,
placeholder: AppLocalizations.of(context)!.passwordField,
ctrl: authCtrl.passwordCtrl,
isPassword: true,
additionalValue: password,
onSelect: (idx) => _onFieldSelect(idx),
onType: (val) => password = val,
),
const SizedBox(height: 10),
GestureDetector(
Expand Down Expand Up @@ -165,18 +172,34 @@ class _LoginPageState extends State<LoginPage> {
child: GestureDetector(
onTap: () async {
if (_userCanLogin) {
final canLogin = await authCtrl.loginUser();
final loggedIn = await AuthController.loginUser(
email,
password,
rememberPassword,
);
final userData = await UserController.me();
const storage = FlutterSecureStorage();
await storage.write(
key: "user_publicId",
value: userData.publicId,
);
if (mounted && canLogin) {
context.go("/");
if (loggedIn) {
if (rememberPassword) {
await storage.write(
key: "user_email",
value: email,
);
await storage.write(
key: "user_password",
value: password,
);
} else {
await storage.delete(key: "user_email");
await storage.delete(key: "user_password");
}
if (mounted) context.go("/");
}
}
//TODO implement remembering user's login and password
},
child: AnimatedContainer(
width: double.infinity,
Expand Down
125 changes: 71 additions & 54 deletions lib/routes/parties_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,14 @@ class _PartiesPageState extends State<PartiesPage> {
@override
void initState() {
super.initState();
parties = [];
users = [];
searchType = SearchType.nearbyParties;
const storage = FlutterSecureStorage();
storage.read(key: "user_publicId").then((id) => userId = id!);
WidgetsBinding.instance.addPostFrameCallback((_) async {
const storage = FlutterSecureStorage();
final id = await storage.read(key: "user_publicId");
userId = id!;
});
}

@override
Expand Down Expand Up @@ -65,59 +70,71 @@ class _PartiesPageState extends State<PartiesPage> {
}

Widget _resultList<T>(List<T> iter) {
return Column(
children: [
const SizedBox(height: 130),
for (final i in iter)
T is Party
? PartyHolder(i as Party)
: UserHolder(
i as Friend,
onButtonTap: () async {
final success = await UserController.sendFriendInvitation(
FriendInvitation(
receiverPublicId: i.publicId!,
senderPublicId: userId,
),
);
if (success && mounted) {
showModalBottomSheet(
context: context,
backgroundColor: Theming.bgColor,
isScrollControlled: true,
builder: (ctx) => SuccessSheet(
success: true,
successMsg:
AppLocalizations.of(ctx)!.successFriendInvite,
failureMsg:
AppLocalizations.of(ctx)!.failureFriendInvite,
),
);
} else {
showModalBottomSheet(
context: context,
backgroundColor: Theming.bgColor,
isScrollControlled: true,
builder: (ctx) => SuccessSheet(
success: false,
successMsg:
AppLocalizations.of(ctx)!.successFriendInvite,
failureMsg:
AppLocalizations.of(ctx)!.failureFriendInvite,
return iter.isEmpty
? Center(
child: Text(
AppLocalizations.of(context)!.emptyHere,
style: TextStyle(
color: Theming.whiteTone.withOpacity(0.7),
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
)
: Column(
children: [
const SizedBox(height: 130),
for (final i in iter)
T is Party
? PartyHolder(i as Party)
: UserHolder(
i as Friend,
onButtonTap: () async {
final success =
await UserController.sendFriendInvitation(
FriendInvitation(
receiverPublicId: i.publicId!,
senderPublicId: userId,
),
);
if (success && mounted) {
showModalBottomSheet(
context: context,
backgroundColor: Theming.bgColor,
isScrollControlled: true,
builder: (ctx) => SuccessSheet(
success: true,
successMsg: AppLocalizations.of(ctx)!
.successFriendInvite,
failureMsg: AppLocalizations.of(ctx)!
.failureFriendInvite,
),
);
} else {
showModalBottomSheet(
context: context,
backgroundColor: Theming.bgColor,
isScrollControlled: true,
builder: (ctx) => SuccessSheet(
success: false,
successMsg: AppLocalizations.of(ctx)!
.successFriendInvite,
failureMsg: AppLocalizations.of(ctx)!
.failureFriendInvite,
),
);
}
},
buttonChild: const Icon(
Icons.person_add_alt_1_rounded,
color: Theming.whiteTone,
),
);
}
},
buttonChild: const Icon(
Icons.person_add_alt_1_rounded,
color: Theming.whiteTone,
),
),
SizedBox(
height: MediaQuery.of(context).viewPadding.bottom + 120,
),
],
);
),
SizedBox(
height: MediaQuery.of(context).viewPadding.bottom + 120,
),
],
);
}
}

Expand Down
8 changes: 7 additions & 1 deletion lib/routes/register_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,13 @@ class _RegisterPageState extends State<RegisterPage> {
pfp: pfp != null ? File(pfp!.path) : null,
),
);
if (canRegister && mounted) {
if (!canRegister) return;
final loggedIn = await AuthController.loginUser(
emailCtrl.text,
passwordCtrl.text,
false,
);
if (loggedIn && mounted) {
context.go("/");
}
}
Expand Down
5 changes: 2 additions & 3 deletions lib/routes/settings_routes/log_out_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,8 @@ class LogoutPage extends StatelessWidget {
const storage = FlutterSecureStorage();
await storage.delete(key: "access");
await storage.delete(key: "refresh");
if (context.mounted) {
context.go("/login");
}
await storage.write(key: "remember", value: "false");
if (context.mounted) context.go("/login");
},
child: Container(
padding: const EdgeInsets.symmetric(
Expand Down
2 changes: 1 addition & 1 deletion lib/utils/router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ final GlobalKey<NavigatorState> _navBarKey = GlobalKey<NavigatorState>();

GoRouter router = GoRouter(
navigatorKey: _rootKey,
initialLocation: "/",
initialLocation: "/login",
routes: [
ShellRoute(
navigatorKey: _navBarKey,
Expand Down
Loading

0 comments on commit 9846e1b

Please sign in to comment.