-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: sign user out after 2 hours/Never #514
Changes from all commits
df7b3f8
b3c70bc
5842c52
2dda1f1
7c4abbb
65cb4e1
4698cf5
a6ea67d
b08a641
bcb49e9
94686ca
ca6ac43
8d11d7e
4505f97
058d48c
ec8f80d
92dec1c
4c6dec2
5844a43
be36bbf
f698de7
fce0515
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -279,6 +279,7 @@ abstract final class Strings { | |
static const deleteAccount = 'Delete account'; | ||
static const credits = 'Credits'; | ||
static const privacyPolicy = 'Privacy policy'; | ||
static const sessionTimeout = 'Session timeout'; | ||
|
||
static const emailShimmerText = '[email protected]'; | ||
static const openingHoursShimmerText = 'Somedays: 8-16'; | ||
|
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -2,17 +2,21 @@ import 'package:coffeecard/core/styles/app_colors.dart'; | |||||||||
import 'package:coffeecard/core/styles/app_text_styles.dart'; | ||||||||||
import 'package:flutter/material.dart'; | ||||||||||
|
||||||||||
class Dropdown<FilterCategory> extends StatelessWidget { | ||||||||||
class Dropdown<T> extends StatelessWidget { | ||||||||||
final bool loading; | ||||||||||
final FilterCategory value; | ||||||||||
final List<DropdownMenuItem<FilterCategory>>? items; | ||||||||||
final void Function(FilterCategory?) onChanged; | ||||||||||
final T value; | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Give a more descriptive name for the type T
Suggested change
|
||||||||||
final List<DropdownMenuItem<T>> items; | ||||||||||
final void Function(T?) onChanged; | ||||||||||
final TextStyle? textStyle; | ||||||||||
final Color? dropdownColor; | ||||||||||
Comment on lines
+10
to
+11
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make required with no default value. What I suspect you really want is a way to change the colour of the text, in which case you can also change the TextStyle field into a Color field instead.
Suggested change
|
||||||||||
|
||||||||||
const Dropdown({ | ||||||||||
required this.loading, | ||||||||||
required this.value, | ||||||||||
required this.items, | ||||||||||
required this.onChanged, | ||||||||||
this.textStyle, | ||||||||||
this.dropdownColor, | ||||||||||
}); | ||||||||||
|
||||||||||
Container get _underline { | ||||||||||
|
@@ -29,17 +33,18 @@ class Dropdown<FilterCategory> extends StatelessWidget { | |||||||||
); | ||||||||||
} | ||||||||||
|
||||||||||
Color get _color => loading ? AppColors.lightGray : AppColors.white; | ||||||||||
Color get _color => | ||||||||||
loading ? AppColors.lightGray : (dropdownColor ?? AppColors.white); | ||||||||||
|
||||||||||
@override | ||||||||||
Widget build(BuildContext context) { | ||||||||||
return Theme( | ||||||||||
data: ThemeData(disabledColor: AppColors.lightGray), | ||||||||||
child: DropdownButton( | ||||||||||
dropdownColor: AppColors.secondary, | ||||||||||
dropdownColor: dropdownColor ?? AppColors.secondary, | ||||||||||
underline: _underline, | ||||||||||
icon: Icon(Icons.arrow_drop_down, color: _color), | ||||||||||
style: AppTextStyle.buttonText, | ||||||||||
style: textStyle ?? AppTextStyle.buttonText, | ||||||||||
value: value, | ||||||||||
items: items, | ||||||||||
onChanged: loading ? null : onChanged, | ||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import 'dart:convert'; | ||
|
||
import 'package:coffeecard/features/session/data/models/session_details_model.dart'; | ||
import 'package:flutter_secure_storage/flutter_secure_storage.dart'; | ||
import 'package:fpdart/fpdart.dart'; | ||
import 'package:logger/logger.dart'; | ||
|
||
class SessionLocalDataSource { | ||
static const _sessionKey = 'session'; | ||
|
||
final FlutterSecureStorage storage; | ||
final Logger logger; | ||
|
||
const SessionLocalDataSource({ | ||
required this.storage, | ||
required this.logger, | ||
}); | ||
|
||
Future<void> saveSessionDetails(SessionDetailsModel sessionDetails) async { | ||
await storage.write( | ||
key: _sessionKey, | ||
value: json.encode(sessionDetails), | ||
); | ||
|
||
logger.d('$sessionDetails added to storage'); | ||
} | ||
|
||
Future<Option<SessionDetailsModel>> getSessionDetails() async { | ||
final jsonString = await storage.read(key: _sessionKey); | ||
|
||
if (jsonString == null) { | ||
return none(); | ||
} | ||
|
||
final sessionDetails = SessionDetailsModel.fromJson( | ||
json.decode(jsonString) as Map<String, dynamic>, | ||
); | ||
|
||
return some(sessionDetails); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import 'package:coffeecard/features/session/domain/entities/session_details.dart'; | ||
import 'package:fpdart/fpdart.dart'; | ||
|
||
class SessionDetailsModel extends SessionDetails { | ||
const SessionDetailsModel({ | ||
required super.sessionTimeout, | ||
required super.lastLogin, | ||
}); | ||
|
||
factory SessionDetailsModel.fromJson(Map<String, dynamic> json) { | ||
return SessionDetailsModel( | ||
sessionTimeout: _parseOption(json, 'session_timeout', _parseDuration), | ||
lastLogin: _parseOption(json, 'last_login', DateTime.parse), | ||
); | ||
} | ||
|
||
Map<String, dynamic> toJson() { | ||
return { | ||
'last_login': _optionToString(lastLogin), | ||
'session_timeout': _optionToString(sessionTimeout), | ||
}; | ||
} | ||
|
||
static String? _optionToString<T>(Option<T> option) { | ||
return option.match(() => 'null', (value) => value.toString()); | ||
} | ||
|
||
static Option<T> _parseOption<T>( | ||
Map<String, dynamic> jsonMap, | ||
String key, | ||
T Function(String) callback, | ||
) { | ||
if (!jsonMap.containsKey(key)) { | ||
return none(); | ||
} | ||
|
||
final val = jsonMap[key] as String; | ||
|
||
if (val == 'null') { | ||
return none(); | ||
} | ||
|
||
return Some(callback(val)); | ||
} | ||
|
||
static Duration _parseDuration(String duration) { | ||
final parts = duration.split(':'); | ||
|
||
final hours = int.parse(parts[0]); | ||
final minutes = int.parse(parts[1]); | ||
final seconds = int.parse(parts[2].split('.')[0]); | ||
|
||
return Duration(hours: hours, minutes: minutes, seconds: seconds); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import 'package:equatable/equatable.dart'; | ||
import 'package:fpdart/fpdart.dart'; | ||
|
||
class SessionDetails extends Equatable { | ||
final Option<Duration?> sessionTimeout; | ||
final Option<DateTime> lastLogin; | ||
|
||
const SessionDetails({required this.sessionTimeout, required this.lastLogin}); | ||
|
||
@override | ||
List<Object?> get props => [sessionTimeout, lastLogin]; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import 'package:coffeecard/features/session/data/datasources/session_local_data_source.dart'; | ||
import 'package:coffeecard/features/session/domain/entities/session_details.dart'; | ||
import 'package:fpdart/fpdart.dart'; | ||
|
||
class GetSessionDetails { | ||
final SessionLocalDataSource dataSource; | ||
|
||
GetSessionDetails({required this.dataSource}); | ||
|
||
Future<Option<SessionDetails>> call() { | ||
return dataSource.getSessionDetails(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import 'package:coffeecard/features/session/data/datasources/session_local_data_source.dart'; | ||
import 'package:coffeecard/features/session/data/models/session_details_model.dart'; | ||
import 'package:fpdart/fpdart.dart'; | ||
|
||
class SaveSessionDetails { | ||
final SessionLocalDataSource dataSource; | ||
|
||
SaveSessionDetails({required this.dataSource}); | ||
|
||
Future<void> call({ | ||
required Option<Duration?> sessionTimeout, | ||
required Option<DateTime> lastLogin, | ||
}) async { | ||
return dataSource.saveSessionDetails( | ||
SessionDetailsModel(sessionTimeout: sessionTimeout, lastLogin: lastLogin), | ||
); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't change the intended use case for this widget.