Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
L
library-app-flutter
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Ilham Maulana
library-app-flutter
Commits
7bcbe2db
Unverified
Commit
7bcbe2db
authored
Aug 07, 2024
by
Ilham Maulana Pratama
Committed by
GitHub
Aug 07, 2024
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #4 from impfundev/development
Development
parents
6d383880
a80e1707
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
566 additions
and
306 deletions
+566
-306
main.dart
lib/main.dart
+6
-1
loan.dart
lib/src/models/loan.dart
+0
-12
user.dart
lib/src/models/user.dart
+2
-5
auth_provider.dart
lib/src/providers/auth_provider.dart
+125
-55
book_provider.dart
lib/src/providers/book_provider.dart
+21
-3
form_screen.dart
lib/src/screens/form_screen.dart
+4
-2
list_screen.dart
lib/src/screens/list/list_screen.dart
+12
-0
member_list_screen.dart
lib/src/screens/list/member_list_screen.dart
+43
-20
book_list.dart
lib/src/widgets/books/book_list.dart
+93
-47
book_loan_form.dart
lib/src/widgets/forms/book_loan_form.dart
+1
-1
change_password_form.dart
lib/src/widgets/forms/change_password_form.dart
+42
-33
login_form.dart
lib/src/widgets/forms/login_form.dart
+10
-16
profile_edit_form.dart
lib/src/widgets/forms/profile_edit_form.dart
+16
-23
reset_password_form.dart
lib/src/widgets/forms/reset_password_form.dart
+32
-45
search_form.dart
lib/src/widgets/forms/search_form.dart
+11
-9
sign_up_form.dart
lib/src/widgets/forms/sign_up_form.dart
+6
-2
admin_loan_list.dart
lib/src/widgets/loans/admin_loan_list.dart
+64
-19
loan_list.dart
lib/src/widgets/loans/loan_list.dart
+64
-5
profile.dart
lib/src/widgets/profile.dart
+14
-8
No files found.
lib/main.dart
View file @
7bcbe2db
...
@@ -3,6 +3,7 @@ import 'package:flutter/gestures.dart';
...
@@ -3,6 +3,7 @@ import 'package:flutter/gestures.dart';
import
'package:go_router/go_router.dart'
;
import
'package:go_router/go_router.dart'
;
import
'package:google_fonts/google_fonts.dart'
;
import
'package:google_fonts/google_fonts.dart'
;
import
'package:library_app/src/screens/profile_edit_screen.dart'
;
import
'package:provider/provider.dart'
;
import
'package:provider/provider.dart'
;
import
'package:library_app/src/providers/auth_provider.dart'
;
import
'package:library_app/src/providers/auth_provider.dart'
;
import
'package:library_app/src/providers/navigations_provider.dart'
;
import
'package:library_app/src/providers/navigations_provider.dart'
;
...
@@ -54,7 +55,11 @@ class _LibraryApp extends State<LibraryApp> {
...
@@ -54,7 +55,11 @@ class _LibraryApp extends State<LibraryApp> {
GoRoute
(
GoRoute
(
path:
"/change-password"
,
path:
"/change-password"
,
builder:
(
context
,
state
)
=>
const
ChangePasswordScreen
(),
builder:
(
context
,
state
)
=>
const
ChangePasswordScreen
(),
)
),
GoRoute
(
path:
"/profile-edit"
,
builder:
(
context
,
state
)
=>
const
ProfileEditScreen
(),
),
],
],
);
);
...
...
lib/src/models/loan.dart
View file @
7bcbe2db
...
@@ -17,16 +17,4 @@ class Loan {
...
@@ -17,16 +17,4 @@ class Loan {
this
.
remainingDays
,
this
.
remainingDays
,
this
.
isOverdue
,
this
.
isOverdue
,
);
);
factory
Loan
.
fromJson
(
Map
<
String
,
dynamic
>
data
)
{
final
book
=
Book
.
fromJson
(
data
[
"book_detail"
]);
return
Loan
(
book
,
null
,
data
[
"loan_date"
],
data
[
"due_date"
],
data
[
"remaining_loan_time"
],
data
[
"is_overdue"
],
);
}
}
}
lib/src/models/user.dart
View file @
7bcbe2db
class
User
{
class
User
{
int
id
;
int
id
;
int
accountId
;
String
username
;
String
username
;
String
email
;
String
email
;
String
?
firstName
;
String
?
firstName
;
String
?
lastName
;
String
?
lastName
;
bool
isStaff
;
bool
isStaff
;
User
(
this
.
id
,
this
.
accountId
,
this
.
username
,
this
.
email
,
this
.
fir
stName
,
User
(
this
.
id
,
this
.
username
,
this
.
email
,
this
.
firstName
,
this
.
la
stName
,
this
.
lastName
,
this
.
isStaff
);
this
.
isStaff
);
factory
User
.
fromJson
(
Map
<
String
,
dynamic
>
data
)
{
factory
User
.
fromJson
(
Map
<
String
,
dynamic
>
data
)
{
return
User
(
return
User
(
data
[
'id'
]
as
int
,
data
[
'id'
]
as
int
,
data
[
'account_id'
]
as
int
,
data
[
'username'
]
as
String
,
data
[
'username'
]
as
String
,
data
[
'email'
]
as
String
,
data
[
'email'
]
as
String
,
data
[
'first_name'
]
as
String
?,
data
[
'first_name'
]
as
String
?,
...
@@ -36,7 +34,6 @@ class User {
...
@@ -36,7 +34,6 @@ class User {
final
User
initialUser
=
User
(
final
User
initialUser
=
User
(
1
,
1
,
2
,
"test_user"
,
"test_user"
,
"test@email.com"
,
"test@email.com"
,
"Test"
,
"Test"
,
...
...
lib/src/providers/auth_provider.dart
View file @
7bcbe2db
...
@@ -10,7 +10,9 @@ import 'package:library_app/src/models/user.dart';
...
@@ -10,7 +10,9 @@ import 'package:library_app/src/models/user.dart';
class
AuthProvider
with
ChangeNotifier
{
class
AuthProvider
with
ChangeNotifier
{
final
storage
=
const
FlutterSecureStorage
();
final
storage
=
const
FlutterSecureStorage
();
String
baseUrl
=
'http://localhost:8000/api/v1'
;
String
baseUrl
=
'http://localhost:8000/api/v1'
;
String
?
message
;
User
?
user
;
User
?
user
;
bool
isAuthenticated
=
false
;
bool
isAuthenticated
=
false
;
...
@@ -26,6 +28,11 @@ class AuthProvider with ChangeNotifier {
...
@@ -26,6 +28,11 @@ class AuthProvider with ChangeNotifier {
bool
changePasswordSucced
=
false
;
bool
changePasswordSucced
=
false
;
bool
loanBookSuccess
=
false
;
bool
loanBookSuccess
=
false
;
bool
hasNextPage
=
false
;
bool
hasPrevPage
=
false
;
int
pageNumber
=
1
;
int
?
totalPages
;
List
<
dynamic
>?
loans
;
List
<
dynamic
>?
loans
;
List
<
dynamic
>?
nearOutstandingLoans
;
List
<
dynamic
>?
nearOutstandingLoans
;
List
<
dynamic
>?
overduedLoans
;
List
<
dynamic
>?
overduedLoans
;
...
@@ -47,6 +54,37 @@ class AuthProvider with ChangeNotifier {
...
@@ -47,6 +54,37 @@ class AuthProvider with ChangeNotifier {
loanBookSuccess
=
value
;
loanBookSuccess
=
value
;
}
}
void
setInvalidUsernameOrPassword
(
bool
value
)
{
invalidUsernameOrPassword
=
value
;
}
void
resetAllState
()
{
user
=
null
;
message
=
null
;
memberLoans
=
null
;
loans
=
null
;
nearOutstandingLoans
=
null
;
overduedLoans
=
null
;
totalPages
=
null
;
isAuthenticated
=
false
;
invalidUsernameOrPassword
=
false
;
filterByUpcoming
=
false
;
filterByOverdued
=
false
;
isLoading
=
false
;
resetPasswordTokenSended
=
false
;
resetPasswordSucced
=
false
;
changePasswordSucced
=
false
;
loanBookSuccess
=
false
;
hasNextPage
=
false
;
hasPrevPage
=
false
;
}
void
setPage
(
int
value
)
{
pageNumber
=
value
;
notifyListeners
();
}
Future
<
void
>
signIn
(
Future
<
void
>
signIn
(
BuildContext
context
,
String
username
,
String
password
)
async
{
BuildContext
context
,
String
username
,
String
password
)
async
{
try
{
try
{
...
@@ -57,22 +95,20 @@ class AuthProvider with ChangeNotifier {
...
@@ -57,22 +95,20 @@ class AuthProvider with ChangeNotifier {
headers:
{
'Content-Type'
:
'application/json'
},
headers:
{
'Content-Type'
:
'application/json'
},
);
);
if
(
response
.
statusCode
==
20
0
)
{
if
(
response
.
statusCode
==
20
1
)
{
final
data
=
jsonDecode
(
response
.
body
);
final
data
=
jsonDecode
(
response
.
body
);
String
token
=
Token
.
fromJson
(
data
)!.
key
;
String
token
=
Token
.
fromJson
(
data
)!.
key
;
await
storeAccessToken
(
token
);
await
storeAccessToken
(
token
);
isAuthenticated
=
true
;
isAuthenticated
=
true
;
invalidUsernameOrPassword
=
false
;
setInvalidUsernameOrPassword
(
false
)
;
debugPrint
(
"Login successful
$token
"
);
debugPrint
(
"Login successful
$token
"
);
}
else
if
(
response
.
statusCode
==
401
)
{
}
else
if
(
response
.
statusCode
==
400
)
{
invalidUsernameOrPassword
=
true
;
setInvalidUsernameOrPassword
(
true
);
debugPrint
(
"Login failed:
${response.statusCode}
${response.body}
"
);
debugPrint
(
"Login failed:
${response.statusCode}
${response.body}
"
);
}
else
{
}
else
{
final
code
=
response
.
statusCode
;
debugPrint
(
"Login failed:
${response.statusCode}
${response.body}
"
);
debugPrint
(
"Login failed
$code
"
);
}
}
setLoading
(
false
);
setLoading
(
false
);
...
@@ -98,19 +134,7 @@ class AuthProvider with ChangeNotifier {
...
@@ -98,19 +134,7 @@ class AuthProvider with ChangeNotifier {
if
(
response
.
statusCode
==
200
)
{
if
(
response
.
statusCode
==
200
)
{
await
storage
.
delete
(
key:
'token'
);
await
storage
.
delete
(
key:
'token'
);
isAuthenticated
=
false
;
resetAllState
();
user
=
null
;
filterByUpcoming
=
false
;
filterByOverdued
=
false
;
memberLoans
=
null
;
isLoading
=
false
;
resetPasswordTokenSended
=
false
;
resetPasswordSucced
=
false
;
loans
=
null
;
nearOutstandingLoans
=
null
;
overduedLoans
=
null
;
}
else
{
}
else
{
debugPrint
(
"Logout failed:
${response.statusCode}
${response.body}
"
);
debugPrint
(
"Logout failed:
${response.statusCode}
${response.body}
"
);
}
}
...
@@ -132,22 +156,25 @@ class AuthProvider with ChangeNotifier {
...
@@ -132,22 +156,25 @@ class AuthProvider with ChangeNotifier {
"password"
:
password
,
"password"
:
password
,
};
};
final
response
=
await
http
.
post
(
final
response
=
await
http
.
post
(
Uri
.
parse
(
'
$baseUrl
/
members/
auth/register'
),
Uri
.
parse
(
'
$baseUrl
/auth/register'
),
body:
jsonEncode
(
body
),
body:
jsonEncode
(
body
),
headers:
{
'Content-Type'
:
'application/json'
},
headers:
{
'Content-Type'
:
'application/json'
},
);
);
if
(
response
.
statusCode
==
20
0
)
{
if
(
response
.
statusCode
==
20
1
)
{
final
data
=
jsonDecode
(
response
.
body
);
final
data
=
jsonDecode
(
response
.
body
);
String
token
=
Token
.
fromJson
(
data
)!.
key
;
String
token
=
Token
.
fromJson
(
data
)!.
key
;
storeAccessToken
(
token
);
storeAccessToken
(
token
);
isAuthenticated
=
true
;
isAuthenticated
=
true
;
message
=
null
;
if
(
context
.
mounted
)
{
if
(
context
.
mounted
)
{
context
.
go
(
"/"
);
context
.
go
(
"/"
);
}
}
debugPrint
(
"Signup successful
$token
"
);
debugPrint
(
"Signup successful
$token
"
);
}
else
{
}
else
{
final
data
=
jsonDecode
(
response
.
body
);
message
=
data
[
"message"
];
debugPrint
(
debugPrint
(
"Error: sign up failed,
${response.statusCode}
:
${response.body}
"
);
"Error: sign up failed,
${response.statusCode}
:
${response.body}
"
);
}
}
...
@@ -169,15 +196,17 @@ class AuthProvider with ChangeNotifier {
...
@@ -169,15 +196,17 @@ class AuthProvider with ChangeNotifier {
Uri
.
parse
(
'
$baseUrl
/user'
),
Uri
.
parse
(
'
$baseUrl
/user'
),
headers:
{
headers:
{
'Content-Type'
:
'application/json'
,
'Content-Type'
:
'application/json'
,
'Authorization'
:
'Bearer
$token
'
'Authorization'
:
'Bearer
$token
'
,
},
},
);
);
if
(
response
.
statusCode
==
200
)
{
if
(
response
.
statusCode
==
200
)
{
final
data
=
jsonDecode
(
response
.
body
);
final
data
=
jsonDecode
(
response
.
body
);
user
=
User
.
fromJson
(
data
);
user
=
User
.
fromJson
(
data
);
message
=
null
;
}
else
{
}
else
{
debugPrint
(
'Error fetching user details:
${response.statusCode}
'
);
debugPrint
(
'Error fetching user details:
${response.statusCode}
${response.body}
'
);
}
}
setLoading
(
false
);
setLoading
(
false
);
...
@@ -189,6 +218,7 @@ class AuthProvider with ChangeNotifier {
...
@@ -189,6 +218,7 @@ class AuthProvider with ChangeNotifier {
}
}
Future
<
void
>
updateUserDetail
(
Future
<
void
>
updateUserDetail
(
BuildContext
context
,
int
id
,
int
id
,
String
username
,
String
username
,
String
email
,
String
email
,
...
@@ -201,14 +231,15 @@ class AuthProvider with ChangeNotifier {
...
@@ -201,14 +231,15 @@ class AuthProvider with ChangeNotifier {
if
(
token
!=
null
)
{
if
(
token
!=
null
)
{
try
{
try
{
final
body
=
jsonEncode
(
{
final
data
=
{
"username"
:
username
,
"username"
:
username
,
"email"
:
email
,
"email"
:
email
,
"first_name"
:
firstName
,
"first_name"
:
firstName
,
"last_name"
:
lastName
,
"last_name"
:
lastName
,
});
};
final
body
=
jsonEncode
(
data
);
final
response
=
await
http
.
put
(
final
response
=
await
http
.
put
(
Uri
.
parse
(
'
$baseUrl
/user/
$id
/
'
),
Uri
.
parse
(
'
$baseUrl
/user/
update
'
),
body:
body
,
body:
body
,
headers:
{
headers:
{
'Content-Type'
:
'application/json'
,
'Content-Type'
:
'application/json'
,
...
@@ -217,9 +248,14 @@ class AuthProvider with ChangeNotifier {
...
@@ -217,9 +248,14 @@ class AuthProvider with ChangeNotifier {
);
);
if
(
response
.
statusCode
==
200
)
{
if
(
response
.
statusCode
==
200
)
{
final
data
=
jsonDecode
(
response
.
body
);
await
getUserDetail
();
user
=
User
.
fromJson
(
data
);
message
=
null
;
if
(
context
.
mounted
)
{
context
.
pop
();
}
}
else
{
}
else
{
final
data
=
jsonDecode
(
response
.
body
);
message
=
data
[
"message"
];
debugPrint
(
debugPrint
(
'Error update user details:
${response.statusCode}
,
${response.body}
'
);
'Error update user details:
${response.statusCode}
,
${response.body}
'
);
}
}
...
@@ -234,19 +270,20 @@ class AuthProvider with ChangeNotifier {
...
@@ -234,19 +270,20 @@ class AuthProvider with ChangeNotifier {
Future
<
void
>
changePassword
(
Future
<
void
>
changePassword
(
BuildContext
context
,
BuildContext
context
,
int
accountId
,
String
oldPassword
,
String
oldPassword
,
String
newPassword
,
String
newPassword1
,
String
newPassword2
,
)
async
{
)
async
{
final
token
=
await
getAccessToken
();
final
token
=
await
getAccessToken
();
try
{
try
{
setLoading
(
true
);
setLoading
(
true
);
final
response
=
await
http
.
p
os
t
(
final
response
=
await
http
.
p
u
t
(
Uri
.
parse
(
'
$baseUrl
/
members/
$accountId
/change-password'
),
Uri
.
parse
(
'
$baseUrl
/
auth
/change-password'
),
body:
jsonEncode
({
body:
jsonEncode
({
"old_password"
:
oldPassword
,
"old_password"
:
oldPassword
,
"new_password"
:
newPassword
,
"new_password1"
:
newPassword1
,
"new_password2"
:
newPassword2
,
}),
}),
headers:
{
headers:
{
'Content-Type'
:
'application/json'
,
'Content-Type'
:
'application/json'
,
...
@@ -255,11 +292,14 @@ class AuthProvider with ChangeNotifier {
...
@@ -255,11 +292,14 @@ class AuthProvider with ChangeNotifier {
);
);
if
(
response
.
statusCode
==
200
)
{
if
(
response
.
statusCode
==
200
)
{
message
=
null
;
if
(
context
.
mounted
)
{
if
(
context
.
mounted
)
{
context
.
go
(
"/"
);
context
.
go
(
"/"
);
}
}
changePasswordSucced
=
true
;
changePasswordSucced
=
true
;
}
else
{
}
else
{
final
data
=
jsonDecode
(
response
.
body
);
message
=
data
[
"message"
];
debugPrint
(
debugPrint
(
'Change password failed:
${response.statusCode}
,
${response.body}
'
);
'Change password failed:
${response.statusCode}
,
${response.body}
'
);
}
}
...
@@ -271,18 +311,24 @@ class AuthProvider with ChangeNotifier {
...
@@ -271,18 +311,24 @@ class AuthProvider with ChangeNotifier {
}
}
}
}
Future
<
void
>
resetPassword
(
String
email
)
async
{
Future
<
void
>
resetPassword
(
BuildContext
context
,
String
email
)
async
{
try
{
try
{
setLoading
(
true
);
setLoading
(
true
);
final
response
=
await
http
.
post
(
final
response
=
await
http
.
post
(
Uri
.
parse
(
'
$baseUrl
/
reset-password/request-token
'
),
Uri
.
parse
(
'
$baseUrl
/
auth/reset-password
'
),
body:
jsonEncode
({
"email"
:
email
}),
body:
jsonEncode
({
"email"
:
email
}),
headers:
{
'Content-Type'
:
'application/json'
},
headers:
{
'Content-Type'
:
'application/json'
},
);
);
if
(
response
.
statusCode
==
200
)
{
if
(
response
.
statusCode
==
200
)
{
message
=
null
;
resetPasswordTokenSended
=
true
;
resetPasswordTokenSended
=
true
;
if
(
context
.
mounted
)
{
context
.
go
(
"/confirm-reset-password"
);
}
}
else
{
}
else
{
final
data
=
jsonDecode
(
response
.
body
);
message
=
data
[
"message"
];
debugPrint
(
debugPrint
(
'Error reset user password:
${response.statusCode}
,
${response.body}
'
);
'Error reset user password:
${response.statusCode}
,
${response.body}
'
);
}
}
...
@@ -295,7 +341,11 @@ class AuthProvider with ChangeNotifier {
...
@@ -295,7 +341,11 @@ class AuthProvider with ChangeNotifier {
}
}
Future
<
void
>
confirmResetPassword
(
Future
<
void
>
confirmResetPassword
(
int
pin
,
String
password1
,
String
password2
)
async
{
BuildContext
context
,
int
pin
,
String
password1
,
String
password2
,
)
async
{
setLoading
(
true
);
setLoading
(
true
);
final
body
=
jsonEncode
({
final
body
=
jsonEncode
({
"pin"
:
pin
,
"pin"
:
pin
,
...
@@ -305,14 +355,20 @@ class AuthProvider with ChangeNotifier {
...
@@ -305,14 +355,20 @@ class AuthProvider with ChangeNotifier {
try
{
try
{
final
response
=
await
http
.
post
(
final
response
=
await
http
.
post
(
Uri
.
parse
(
'
$baseUrl
/
reset-password/
confirm'
),
Uri
.
parse
(
'
$baseUrl
/
auth/reset-password-
confirm'
),
body:
body
,
body:
body
,
headers:
{
'Content-Type'
:
'application/json'
},
headers:
{
'Content-Type'
:
'application/json'
},
);
);
if
(
response
.
statusCode
==
200
)
{
if
(
response
.
statusCode
==
200
)
{
message
=
null
;
resetPasswordSucced
=
true
;
resetPasswordSucced
=
true
;
if
(
context
.
mounted
)
{
context
.
go
(
"/"
);
}
}
else
{
}
else
{
final
data
=
jsonDecode
(
response
.
body
);
message
=
data
[
"message"
];
debugPrint
(
debugPrint
(
'Error confirm reset user password:
${response.statusCode}
,
${response.body}
'
);
'Error confirm reset user password:
${response.statusCode}
,
${response.body}
'
);
}
}
...
@@ -328,13 +384,13 @@ class AuthProvider with ChangeNotifier {
...
@@ -328,13 +384,13 @@ class AuthProvider with ChangeNotifier {
setLoading
(
true
);
setLoading
(
true
);
final
token
=
await
getAccessToken
();
final
token
=
await
getAccessToken
();
String
url
=
'
$baseUrl
/
members/
${user?.accountId}
/loans/
'
;
String
url
=
'
$baseUrl
/
user/loans
'
;
if
(
filterByUpcoming
)
{
if
(
filterByUpcoming
)
{
url
+=
'?near_outstanding=True'
;
url
+=
'?near_outstanding=True'
;
}
else
if
(
filterByOverdued
)
{
}
else
if
(
filterByOverdued
)
{
url
+=
'?overdue=True'
;
url
+=
'?overdue=True'
;
}
else
{
}
else
if
(
pageNumber
>
1
)
{
null
;
url
+=
"?page=
$pageNumber
"
;
}
}
try
{
try
{
...
@@ -347,9 +403,16 @@ class AuthProvider with ChangeNotifier {
...
@@ -347,9 +403,16 @@ class AuthProvider with ChangeNotifier {
);
);
if
(
response
.
statusCode
==
200
)
{
if
(
response
.
statusCode
==
200
)
{
message
=
null
;
final
data
=
jsonDecode
(
response
.
body
);
final
data
=
jsonDecode
(
response
.
body
);
memberLoans
=
data
[
"results"
];
memberLoans
=
data
[
"data"
];
hasNextPage
=
data
[
"has_next"
];
hasPrevPage
=
data
[
"has_prev"
];
pageNumber
=
data
[
"page_number"
];
totalPages
=
data
[
"total_pages"
];
}
else
{
}
else
{
final
data
=
jsonDecode
(
response
.
body
);
message
=
data
[
"message"
];
debugPrint
(
debugPrint
(
"Failed to get member loan.
${response.statusCode}
:
${response.body}
"
);
"Failed to get member loan.
${response.statusCode}
:
${response.body}
"
);
}
}
...
@@ -377,6 +440,7 @@ class AuthProvider with ChangeNotifier {
...
@@ -377,6 +440,7 @@ class AuthProvider with ChangeNotifier {
Future
<
void
>
createMemberLoan
(
int
memberId
,
int
bookId
,
int
loanDay
)
async
{
Future
<
void
>
createMemberLoan
(
int
memberId
,
int
bookId
,
int
loanDay
)
async
{
final
token
=
await
getAccessToken
();
final
token
=
await
getAccessToken
();
String
url
=
'
$baseUrl
/user/loans'
;
final
now
=
DateTime
.
now
();
final
now
=
DateTime
.
now
();
final
dueDate
=
now
.
add
(
Duration
(
days:
loanDay
));
final
dueDate
=
now
.
add
(
Duration
(
days:
loanDay
));
...
@@ -390,7 +454,7 @@ class AuthProvider with ChangeNotifier {
...
@@ -390,7 +454,7 @@ class AuthProvider with ChangeNotifier {
try
{
try
{
setLoading
(
true
);
setLoading
(
true
);
final
response
=
await
http
.
post
(
final
response
=
await
http
.
post
(
Uri
.
parse
(
'
$baseUrl
/members/
$memberId
/loans/'
),
Uri
.
parse
(
url
),
body:
jsonEncode
(
body
),
body:
jsonEncode
(
body
),
headers:
{
headers:
{
'Content-Type'
:
'application/json'
,
'Content-Type'
:
'application/json'
,
...
@@ -399,31 +463,33 @@ class AuthProvider with ChangeNotifier {
...
@@ -399,31 +463,33 @@ class AuthProvider with ChangeNotifier {
);
);
if
(
response
.
statusCode
==
200
)
{
if
(
response
.
statusCode
==
200
)
{
final
data
=
jsonDecode
(
response
.
body
)
;
message
=
null
;
memberLoans
=
data
[
"results"
]
;
await
getMemberLoan
()
;
}
else
{
}
else
{
final
data
=
jsonDecode
(
response
.
body
);
message
=
data
[
"message"
];
debugPrint
(
debugPrint
(
"Failed to
create
member loan.
${response.statusCode}
:
${response.body}
"
);
"Failed to
add
member loan.
${response.statusCode}
:
${response.body}
"
);
}
}
loanBookSuccess
=
true
;
loanBookSuccess
=
true
;
setLoading
(
false
);
setLoading
(
false
);
notifyListeners
();
notifyListeners
();
}
catch
(
error
)
{
}
catch
(
error
)
{
debugPrint
(
"Failed to
create
member loan.
$error
"
);
debugPrint
(
"Failed to
add
member loan.
$error
"
);
}
}
}
}
// for admin or librarian
// for admin or librarian
Future
<
void
>
getLoans
(
String
?
type
)
async
{
Future
<
void
>
getLoans
(
String
?
type
)
async
{
final
token
=
await
storage
.
read
(
key:
'access_token'
);
final
token
=
await
storage
.
read
(
key:
'access_token'
);
String
url
=
baseUrl
;
String
url
=
"
$baseUrl
/book-loans"
;
if
(
type
==
"upcoming"
)
{
if
(
type
==
"upcoming"
)
{
url
+=
"/upcoming-loans/"
;
url
+=
'?near_outstanding=True'
;
}
else
if
(
type
==
"overdue"
)
{
}
else
if
(
type
==
"overdue"
)
{
url
+=
"/overdued-loans/"
;
url
+=
'?overdue=True'
;
}
else
{
}
else
if
(
pageNumber
>
1
)
{
url
+=
"
/book-loans/
"
;
url
+=
"
?page=
$pageNumber
"
;
}
}
if
(
token
!=
null
)
{
if
(
token
!=
null
)
{
...
@@ -440,12 +506,16 @@ class AuthProvider with ChangeNotifier {
...
@@ -440,12 +506,16 @@ class AuthProvider with ChangeNotifier {
if
(
response
.
statusCode
==
200
)
{
if
(
response
.
statusCode
==
200
)
{
final
data
=
jsonDecode
(
response
.
body
);
final
data
=
jsonDecode
(
response
.
body
);
if
(
type
==
"upcoming"
)
{
if
(
type
==
"upcoming"
)
{
nearOutstandingLoans
=
data
[
"
results
"
];
nearOutstandingLoans
=
data
[
"
data
"
];
}
else
if
(
type
==
"overdue"
)
{
}
else
if
(
type
==
"overdue"
)
{
overduedLoans
=
data
[
"
results
"
];
overduedLoans
=
data
[
"
data
"
];
}
else
{
}
else
{
loans
=
data
[
"
results
"
];
loans
=
data
[
"
data
"
];
}
}
hasNextPage
=
data
[
"has_next"
];
hasPrevPage
=
data
[
"has_prev"
];
pageNumber
=
data
[
"page_number"
];
totalPages
=
data
[
"total_pages"
];
}
else
{
}
else
{
final
code
=
response
.
statusCode
;
final
code
=
response
.
statusCode
;
debugPrint
(
"Error: Fetch upcoming loans failed,
$code
"
);
debugPrint
(
"Error: Fetch upcoming loans failed,
$code
"
);
...
...
lib/src/providers/book_provider.dart
View file @
7bcbe2db
...
@@ -12,6 +12,11 @@ class BookProvider with ChangeNotifier {
...
@@ -12,6 +12,11 @@ class BookProvider with ChangeNotifier {
String
?
searchKeyword
;
String
?
searchKeyword
;
String
?
filterByCategory
;
String
?
filterByCategory
;
bool
hasNextPage
=
false
;
bool
hasPrevPage
=
false
;
int
pageNumber
=
1
;
int
?
totalPages
;
bool
isLoading
=
false
;
bool
isLoading
=
false
;
void
setLoading
(
bool
value
)
{
void
setLoading
(
bool
value
)
{
...
@@ -23,9 +28,11 @@ class BookProvider with ChangeNotifier {
...
@@ -23,9 +28,11 @@ class BookProvider with ChangeNotifier {
setLoading
(
true
);
setLoading
(
true
);
String
url
=
'
$baseUrl
/books'
;
String
url
=
'
$baseUrl
/books'
;
if
(
filterByCategory
!=
null
)
{
if
(
filterByCategory
!=
null
)
{
url
+=
'?category
__name
=
$filterByCategory
'
;
url
+=
'?category=
$filterByCategory
'
;
}
else
if
(
searchKeyword
!=
null
)
{
}
else
if
(
searchKeyword
!=
null
)
{
url
+=
"?search=
$searchKeyword
"
;
url
+=
"?search=
$searchKeyword
"
;
}
else
if
(
pageNumber
>
1
)
{
url
+=
"?page=
$pageNumber
"
;
}
}
final
response
=
await
http
.
get
(
final
response
=
await
http
.
get
(
...
@@ -35,7 +42,11 @@ class BookProvider with ChangeNotifier {
...
@@ -35,7 +42,11 @@ class BookProvider with ChangeNotifier {
if
(
response
.
statusCode
==
200
)
{
if
(
response
.
statusCode
==
200
)
{
final
data
=
jsonDecode
(
response
.
body
);
final
data
=
jsonDecode
(
response
.
body
);
books
=
data
[
"results"
];
books
=
data
[
"data"
];
hasNextPage
=
data
[
"has_next"
];
hasPrevPage
=
data
[
"has_prev"
];
pageNumber
=
data
[
"page_number"
];
totalPages
=
data
[
"total_pages"
];
}
else
{
}
else
{
final
code
=
response
.
statusCode
;
final
code
=
response
.
statusCode
;
debugPrint
(
"Error: Fetch books failed,
$code
"
);
debugPrint
(
"Error: Fetch books failed,
$code
"
);
...
@@ -58,8 +69,14 @@ class BookProvider with ChangeNotifier {
...
@@ -58,8 +69,14 @@ class BookProvider with ChangeNotifier {
notifyListeners
();
notifyListeners
();
}
}
void
setPage
(
int
value
)
{
pageNumber
=
value
;
notifyListeners
();
}
Future
<
void
>
getCategories
()
async
{
Future
<
void
>
getCategories
()
async
{
try
{
try
{
setLoading
(
true
);
final
response
=
await
http
.
get
(
final
response
=
await
http
.
get
(
Uri
.
parse
(
'
$baseUrl
/categories'
),
Uri
.
parse
(
'
$baseUrl
/categories'
),
headers:
{
'Content-Type'
:
'application/json'
},
headers:
{
'Content-Type'
:
'application/json'
},
...
@@ -67,11 +84,12 @@ class BookProvider with ChangeNotifier {
...
@@ -67,11 +84,12 @@ class BookProvider with ChangeNotifier {
if
(
response
.
statusCode
==
200
)
{
if
(
response
.
statusCode
==
200
)
{
final
data
=
jsonDecode
(
response
.
body
);
final
data
=
jsonDecode
(
response
.
body
);
categories
=
data
[
"results"
]
;
categories
=
data
;
}
else
{
}
else
{
debugPrint
(
"Error: Fetch books failed,
${response.statusCode}
"
);
debugPrint
(
"Error: Fetch books failed,
${response.statusCode}
"
);
}
}
setLoading
(
false
);
notifyListeners
();
notifyListeners
();
}
catch
(
error
)
{
}
catch
(
error
)
{
debugPrint
(
"Error: Fetch books failed,
$error
"
);
debugPrint
(
"Error: Fetch books failed,
$error
"
);
...
...
lib/src/screens/form_screen.dart
View file @
7bcbe2db
...
@@ -41,7 +41,9 @@ class _FormScreen extends State<FormScreen> {
...
@@ -41,7 +41,9 @@ class _FormScreen extends State<FormScreen> {
title:
Text
(
title
),
title:
Text
(
title
),
leading:
withBack
leading:
withBack
?
BackButton
(
?
BackButton
(
onPressed:
()
=>
context
.
push
(
backRoute
??
""
),
onPressed:
()
=>
backRoute
!=
null
?
context
.
push
(
backRoute
!)
:
context
.
pop
(),
)
)
:
null
,
:
null
,
actions:
action
,
actions:
action
,
...
@@ -99,7 +101,7 @@ class ChangePasswordScreen extends StatelessWidget {
...
@@ -99,7 +101,7 @@ class ChangePasswordScreen extends StatelessWidget {
return
FormScreen
(
return
FormScreen
(
title:
title
,
title:
title
,
backRoute:
"/"
,
backRoute:
null
,
body:
const
ChangePasswordForm
(),
body:
const
ChangePasswordForm
(),
);
);
}
}
...
...
lib/src/screens/list/list_screen.dart
View file @
7bcbe2db
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:library_app/src/providers/auth_provider.dart'
;
import
'package:library_app/src/providers/auth_provider.dart'
;
import
'package:library_app/src/providers/navigations_provider.dart'
;
import
'package:library_app/src/screens/list/admin_list_screen.dart'
;
import
'package:library_app/src/screens/list/admin_list_screen.dart'
;
import
'package:library_app/src/screens/list/member_list_screen.dart'
;
import
'package:library_app/src/screens/list/member_list_screen.dart'
;
import
'package:provider/provider.dart'
;
import
'package:provider/provider.dart'
;
...
@@ -12,6 +13,17 @@ class ListScreen extends StatefulWidget {
...
@@ -12,6 +13,17 @@ class ListScreen extends StatefulWidget {
}
}
class
_ListScreen
extends
State
<
ListScreen
>
{
class
_ListScreen
extends
State
<
ListScreen
>
{
@override
void
initState
()
{
Future
.
delayed
(
Duration
.
zero
,
()
{
Provider
.
of
<
NavigationsProvider
>(
context
,
listen:
false
).
navigate
(
0
);
},
);
super
.
initState
();
}
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
final
user
=
Provider
.
of
<
AuthProvider
>(
context
).
user
;
final
user
=
Provider
.
of
<
AuthProvider
>(
context
).
user
;
...
...
lib/src/screens/list/member_list_screen.dart
View file @
7bcbe2db
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:go_router/go_router.dart'
;
import
'package:library_app/src/models/category.dart'
;
import
'package:library_app/src/models/category.dart'
;
import
'package:library_app/src/providers/auth_provider.dart'
;
import
'package:library_app/src/providers/auth_provider.dart'
;
import
'package:library_app/src/providers/book_provider.dart'
;
import
'package:library_app/src/providers/book_provider.dart'
;
...
@@ -73,31 +74,53 @@ class _MemberListScreen extends State<MemberListScreen> {
...
@@ -73,31 +74,53 @@ class _MemberListScreen extends State<MemberListScreen> {
const
BookList
(),
const
BookList
(),
// Loans
// Loans
LoanList
(
LoanList
(
memberId:
authProvider
.
user
?.
accountI
d
??
0
,
memberId:
authProvider
.
user
?.
i
d
??
0
,
),
),
// Profile
// Profile
const
Profile
(),
const
Profile
(),
][
navProvider
.
currentPageIndex
],
][
navProvider
.
currentPageIndex
],
drawer:
Drawer
(
drawer:
Drawer
(
child:
ListView
(
child:
Column
(
padding:
EdgeInsets
.
zero
,
children:
[
children:
List
.
generate
(
Padding
(
category
!=
null
?
category
.
length
:
0
,
padding:
const
EdgeInsets
.
symmetric
(
(
index
)
{
horizontal:
10.0
,
vertical:
20.0
),
if
(
category
!=
null
)
{
child:
Row
(
return
ListTile
(
mainAxisAlignment:
MainAxisAlignment
.
start
,
title:
Text
(
category
.
elementAt
(
index
).
name
),
children:
[
onTap:
()
{
ElevatedButton
(
bookProvider
.
filterBookByCategory
(
child:
const
Row
(
category
!.
elementAt
(
index
).
name
);
children:
[
Icon
(
Icons
.
arrow_back
),
Text
(
"Back"
)],
bookProvider
.
getBooks
();
),
Navigator
.
pop
(
context
);
onPressed:
()
{
},
bookProvider
.
filterBookByCategory
(
null
);
);
bookProvider
.
getBooks
();
}
context
.
pop
();
return
Container
();
},
},
),
),
],
),
),
Expanded
(
child:
ListView
.
builder
(
itemCount:
category
!=
null
?
category
.
length
:
0
,
itemBuilder:
(
context
,
index
)
{
if
(
category
!=
null
)
{
return
ListTile
(
title:
Text
(
category
.
elementAt
(
index
).
name
),
onTap:
()
{
bookProvider
.
filterBookByCategory
(
category
!.
elementAt
(
index
).
name
);
bookProvider
.
getBooks
();
Navigator
.
pop
(
context
);
},
);
}
return
Container
();
},
),
),
],
),
),
),
),
);
);
...
...
lib/src/widgets/books/book_list.dart
View file @
7bcbe2db
...
@@ -21,60 +21,111 @@ class _BookList extends State<BookList> {
...
@@ -21,60 +21,111 @@ class _BookList extends State<BookList> {
Provider
.
of
<
BookProvider
>(
context
,
listen:
false
).
getBooks
();
Provider
.
of
<
BookProvider
>(
context
,
listen:
false
).
getBooks
();
}
}
@override
void
dispose
()
{
super
.
dispose
();
}
ScrollController
listScrollController
=
ScrollController
();
void
scrollToTop
()
{
if
(
listScrollController
.
hasClients
)
{
final
position
=
listScrollController
.
position
.
minScrollExtent
;
listScrollController
.
jumpTo
(
position
);
}
}
Future
<
void
>
nextPage
()
async
{
if
(
Provider
.
of
<
BookProvider
>(
context
,
listen:
false
).
hasNextPage
)
{
Provider
.
of
<
BookProvider
>(
context
,
listen:
false
).
setPage
(
Provider
.
of
<
BookProvider
>(
context
,
listen:
false
).
pageNumber
+
1
,
);
}
else
{
Provider
.
of
<
BookProvider
>(
context
,
listen:
false
).
setPage
(
Provider
.
of
<
BookProvider
>(
context
,
listen:
false
).
totalPages
!);
}
Provider
.
of
<
BookProvider
>(
context
,
listen:
false
).
getBooks
();
scrollToTop
();
}
Future
<
void
>
prevPage
()
async
{
if
(
Provider
.
of
<
BookProvider
>(
context
,
listen:
false
).
hasPrevPage
)
{
Provider
.
of
<
BookProvider
>(
context
,
listen:
false
).
setPage
(
Provider
.
of
<
BookProvider
>(
context
,
listen:
false
).
pageNumber
-
1
,
);
}
else
{
Provider
.
of
<
BookProvider
>(
context
,
listen:
false
).
setPage
(
1
);
}
Provider
.
of
<
BookProvider
>(
context
,
listen:
false
).
getBooks
();
scrollToTop
();
}
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
return
Consumer
<
BookProvider
>(
return
Consumer
<
BookProvider
>(
builder:
(
context
,
bookProvider
,
child
)
{
builder:
(
context
,
bookProvider
,
child
)
{
if
(!
bookProvider
.
isLoading
)
{
if
(
bookProvider
.
books
==
null
)
{
final
Iterable
<
Book
>
books
=
bookProvider
.
books
!.
map
((
book
)
{
return
const
Center
(
if
(
book
[
"category_detail"
]
!=
null
)
{
child:
CircularProgressIndicator
(),
final
Category
category
=
Category
.
fromJson
(
);
book
[
"category_detail"
],
}
);
final
Iterable
<
Book
>
books
=
bookProvider
.
books
!.
map
((
book
)
{
return
Book
(
if
(
book
[
"category"
]
!=
null
)
{
book
[
"id"
],
final
Category
category
=
Category
.
fromJson
(
book
[
"title"
],
book
[
"category"
],
book
[
"author"
],
);
book
[
"description"
],
book
[
"cover_image"
],
category
.
name
,
);
}
return
Book
(
return
Book
(
book
[
"id"
],
book
[
"id"
],
book
[
"title"
],
book
[
"title"
],
book
[
"author"
],
book
[
"author"
],
book
[
"description"
],
book
[
"description"
],
book
[
"cover_image"
],
book
[
"cover_image"
],
null
,
category
.
name
,
);
);
}
);
}
return
NestedScrollView
(
return
Book
(
headerSliverBuilder:
book
[
"id"
],
(
BuildContext
context
,
bool
innerBoxIsScrolled
)
{
book
[
"title"
],
return
[
const
TopAppBar
(
title:
"Books"
)];
book
[
"author"
],
},
book
[
"description"
],
body:
ListView
(
book
[
"cover_image"
],
children:
List
.
generate
(
books
.
length
,
(
index
)
{
null
,
return
BookItem
(
books
.
elementAt
(
index
),
);
}),
),
);
);
}
else
{
});
return
NestedScrollView
(
headerSliverBuilder:
return
NestedScrollView
(
(
BuildContext
context
,
bool
innerBoxIsScrolled
)
{
headerSliverBuilder:
(
BuildContext
context
,
bool
innerBoxIsScrolled
)
{
return
[
const
TopAppBar
(
title:
"Books"
)];
return
[
const
TopAppBar
(
title:
"Books"
)];
},
body:
ListView
.
builder
(
controller:
listScrollController
,
itemCount:
books
.
length
+
1
,
itemBuilder:
(
context
,
index
)
{
if
(
index
<
books
.
length
)
{
return
BookItem
(
books
.
elementAt
(
index
));
}
else
{
return
Container
(
padding:
const
EdgeInsets
.
all
(
10
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
ElevatedButton
(
onPressed:
prevPage
,
child:
const
Text
(
'Prev'
),
),
Text
(
bookProvider
.
pageNumber
.
toString
()),
ElevatedButton
(
onPressed:
nextPage
,
child:
const
Text
(
'Next'
),
),
],
),
);
}
},
},
body:
const
Center
(
),
child:
CircularProgressIndicator
(),
);
),
);
}
},
},
);
);
}
}
...
@@ -127,14 +178,9 @@ class _TopAppBar extends State<TopAppBar> {
...
@@ -127,14 +178,9 @@ class _TopAppBar extends State<TopAppBar> {
leading:
!
showWidget
leading:
!
showWidget
?
IconButton
(
?
IconButton
(
onPressed:
()
{
onPressed:
()
{
if
(
category
!=
null
)
{
Scaffold
.
of
(
context
).
openDrawer
();
bookProvider
.
filterBookByCategory
(
null
);
bookProvider
.
getBooks
();
}
else
{
Scaffold
.
of
(
context
).
openDrawer
();
}
},
},
icon:
Icon
(
category
!=
null
?
Icons
.
arrow_back
:
Icons
.
menu
),
icon:
const
Icon
(
Icons
.
menu
),
)
)
:
null
,
:
null
,
elevation:
10.0
,
elevation:
10.0
,
...
...
lib/src/widgets/forms/book_loan_form.dart
View file @
7bcbe2db
...
@@ -91,7 +91,7 @@ class _LoanBookForm extends State<LoanBookForm> {
...
@@ -91,7 +91,7 @@ class _LoanBookForm extends State<LoanBookForm> {
if
(
_formKey
.
currentState
!.
validate
())
{}
if
(
_formKey
.
currentState
!.
validate
())
{}
authProvider
authProvider
.
createMemberLoan
(
.
createMemberLoan
(
authProvider
.
user
!.
accountI
d
,
authProvider
.
user
!.
i
d
,
widget
.
bookId
,
widget
.
bookId
,
int
.
parse
(
loanDayController
.
text
),
int
.
parse
(
loanDayController
.
text
),
)
)
...
...
lib/src/widgets/forms/change_password_form.dart
View file @
7bcbe2db
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_svg/svg.dart'
;
import
'package:flutter_svg/svg.dart'
;
import
'package:go_router/go_router.dart'
;
import
'package:library_app/src/providers/auth_provider.dart'
;
import
'package:library_app/src/providers/auth_provider.dart'
;
import
'package:library_app/src/widgets/loading.dart'
;
import
'package:library_app/src/widgets/loading.dart'
;
import
'package:provider/provider.dart'
;
import
'package:provider/provider.dart'
;
...
@@ -15,7 +14,8 @@ class ChangePasswordForm extends StatefulWidget {
...
@@ -15,7 +14,8 @@ class ChangePasswordForm extends StatefulWidget {
class
_ChangePasswordForm
extends
State
<
ChangePasswordForm
>
{
class
_ChangePasswordForm
extends
State
<
ChangePasswordForm
>
{
final
GlobalKey
<
FormState
>
_formKey
=
GlobalKey
<
FormState
>();
final
GlobalKey
<
FormState
>
_formKey
=
GlobalKey
<
FormState
>();
final
oldPasswordController
=
TextEditingController
();
final
oldPasswordController
=
TextEditingController
();
final
newPasswordController
=
TextEditingController
();
final
newPasswordController1
=
TextEditingController
();
final
newPasswordController2
=
TextEditingController
();
bool
passwordVisible
=
false
;
bool
passwordVisible
=
false
;
...
@@ -28,7 +28,8 @@ class _ChangePasswordForm extends State<ChangePasswordForm> {
...
@@ -28,7 +28,8 @@ class _ChangePasswordForm extends State<ChangePasswordForm> {
@override
@override
void
dispose
()
{
void
dispose
()
{
oldPasswordController
.
dispose
();
oldPasswordController
.
dispose
();
newPasswordController
.
dispose
();
newPasswordController1
.
dispose
();
newPasswordController2
.
dispose
();
super
.
dispose
();
super
.
dispose
();
}
}
...
@@ -37,6 +38,7 @@ class _ChangePasswordForm extends State<ChangePasswordForm> {
...
@@ -37,6 +38,7 @@ class _ChangePasswordForm extends State<ChangePasswordForm> {
Size
screenSize
=
MediaQuery
.
of
(
context
).
size
;
Size
screenSize
=
MediaQuery
.
of
(
context
).
size
;
return
Consumer
<
AuthProvider
>(
builder:
(
context
,
authProvider
,
child
)
{
return
Consumer
<
AuthProvider
>(
builder:
(
context
,
authProvider
,
child
)
{
final
message
=
authProvider
.
message
;
return
Column
(
return
Column
(
children:
[
children:
[
Padding
(
Padding
(
...
@@ -79,7 +81,7 @@ class _ChangePasswordForm extends State<ChangePasswordForm> {
...
@@ -79,7 +81,7 @@ class _ChangePasswordForm extends State<ChangePasswordForm> {
),
),
),
),
validator:
(
String
?
value
)
{
validator:
(
String
?
value
)
{
if
(
value
==
null
||
value
.
isEmpty
)
{
if
(
value
==
null
)
{
return
"Please enter your old password"
;
return
"Please enter your old password"
;
}
else
{
}
else
{
return
null
;
return
null
;
...
@@ -88,7 +90,7 @@ class _ChangePasswordForm extends State<ChangePasswordForm> {
...
@@ -88,7 +90,7 @@ class _ChangePasswordForm extends State<ChangePasswordForm> {
keyboardType:
TextInputType
.
visiblePassword
,
keyboardType:
TextInputType
.
visiblePassword
,
),
),
TextFormField
(
TextFormField
(
controller:
newPasswordController
,
controller:
newPasswordController
1
,
obscureText:
passwordVisible
,
obscureText:
passwordVisible
,
decoration:
InputDecoration
(
decoration:
InputDecoration
(
hintText:
"Enter your New Password"
,
hintText:
"Enter your New Password"
,
...
@@ -107,7 +109,7 @@ class _ChangePasswordForm extends State<ChangePasswordForm> {
...
@@ -107,7 +109,7 @@ class _ChangePasswordForm extends State<ChangePasswordForm> {
),
),
),
),
validator:
(
String
?
value
)
{
validator:
(
String
?
value
)
{
if
(
value
==
null
||
value
.
isEmpty
)
{
if
(
value
==
null
)
{
return
"Please enter your new password"
;
return
"Please enter your new password"
;
}
else
{
}
else
{
return
null
;
return
null
;
...
@@ -115,36 +117,43 @@ class _ChangePasswordForm extends State<ChangePasswordForm> {
...
@@ -115,36 +117,43 @@ class _ChangePasswordForm extends State<ChangePasswordForm> {
},
},
keyboardType:
TextInputType
.
visiblePassword
,
keyboardType:
TextInputType
.
visiblePassword
,
),
),
TextFormField
(
controller:
newPasswordController2
,
decoration:
const
InputDecoration
(
hintText:
"Confirm your New Password"
,
labelText:
"Confirm New Password"
,
),
validator:
(
String
?
value
)
{
if
(
value
==
null
)
{
return
"Please enter your confirm new password"
;
}
else
{
return
null
;
}
},
),
Text
(
message
??
""
,
style:
const
TextStyle
(
color:
Colors
.
red
),
),
const
SizedBox
(
const
SizedBox
(
height:
20.0
,
height:
20.0
,
),
),
Column
(
SizedBox
(
children:
[
width:
double
.
infinity
,
SizedBox
(
child:
FilledButton
(
width:
double
.
infinity
,
onPressed:
()
async
{
child:
FilledButton
(
if
(
_formKey
.
currentState
!.
validate
())
{}
onPressed:
()
async
{
authProvider
.
changePassword
(
if
(
_formKey
.
currentState
!.
validate
())
{}
context
,
authProvider
.
changePassword
(
oldPasswordController
.
text
,
context
,
newPasswordController1
.
text
,
authProvider
.
user
!.
accountId
,
newPasswordController2
.
text
,
oldPasswordController
.
text
,
);
newPasswordController
.
text
,
},
);
child:
authProvider
.
isLoading
},
?
const
Loading
()
child:
authProvider
.
isLoading
:
const
Text
(
"Submit"
),
?
const
Loading
()
),
:
const
Text
(
"Submit"
),
),
),
SizedBox
(
width:
double
.
infinity
,
child:
TextButton
(
child:
const
Text
(
"Cancel"
),
onPressed:
()
=>
context
.
pop
(
"/"
),
),
),
],
),
),
],
],
),
),
...
...
lib/src/widgets/forms/login_form.dart
View file @
7bcbe2db
...
@@ -39,7 +39,8 @@ class _LoginForm extends State<LoginForm> {
...
@@ -39,7 +39,8 @@ class _LoginForm extends State<LoginForm> {
const
String
formText
=
"Log In to continue"
;
const
String
formText
=
"Log In to continue"
;
return
Consumer
<
AuthProvider
>(
builder:
(
context
,
authProvider
,
child
)
{
return
Consumer
<
AuthProvider
>(
builder:
(
context
,
authProvider
,
child
)
{
final
isInvalid
=
authProvider
.
invalidUsernameOrPassword
;
final
isInvalidUsernameOrPassword
=
authProvider
.
invalidUsernameOrPassword
;
return
Column
(
return
Column
(
children:
[
children:
[
...
@@ -106,28 +107,21 @@ class _LoginForm extends State<LoginForm> {
...
@@ -106,28 +107,21 @@ class _LoginForm extends State<LoginForm> {
},
},
keyboardType:
TextInputType
.
visiblePassword
,
keyboardType:
TextInputType
.
visiblePassword
,
),
),
Visibility
(
Padding
(
visible:
isInvalid
,
padding:
const
EdgeInsets
.
symmetric
(
vertical:
20.0
),
child:
Container
(
child:
Text
(
decoration:
BoxDecoration
(
isInvalidUsernameOrPassword
borderRadius:
BorderRadius
.
circular
(
10
),
?
"Invalid username or password"
color:
Theme
.
of
(
context
).
highlightColor
,
:
""
,
),
style:
const
TextStyle
(
color:
Colors
.
red
),
margin:
const
EdgeInsets
.
symmetric
(
vertical:
20.0
),
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
10.0
,
vertical:
8.0
),
child:
const
Text
(
"Invalid username or password"
),
),
),
),
),
const
SizedBox
(
height:
20.0
,
),
Column
(
Column
(
children:
[
children:
[
SizedBox
(
SizedBox
(
width:
double
.
infinity
,
width:
double
.
infinity
,
child:
FilledButton
(
child:
FilledButton
(
onPressed:
()
{
onPressed:
()
async
{
if
(
_formKey
.
currentState
!.
validate
())
{}
if
(
_formKey
.
currentState
!.
validate
())
{}
authProvider
.
signIn
(
authProvider
.
signIn
(
context
,
context
,
...
...
lib/src/widgets/forms/profile_edit_form.dart
View file @
7bcbe2db
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:go_router/go_router.dart'
;
import
'package:library_app/src/providers/auth_provider.dart'
;
import
'package:library_app/src/providers/auth_provider.dart'
;
import
'package:library_app/src/models/user.dart'
;
import
'package:library_app/src/models/user.dart'
;
...
@@ -43,6 +42,7 @@ class _ProfileEditForm extends State<ProfileEditForm> {
...
@@ -43,6 +42,7 @@ class _ProfileEditForm extends State<ProfileEditForm> {
lastNameControler
.
text
=
user
?.
lastName
??
""
;
lastNameControler
.
text
=
user
?.
lastName
??
""
;
return
Consumer
<
AuthProvider
>(
builder:
(
context
,
authProvider
,
child
)
{
return
Consumer
<
AuthProvider
>(
builder:
(
context
,
authProvider
,
child
)
{
final
message
=
authProvider
.
message
;
return
Column
(
return
Column
(
children:
[
children:
[
Form
(
Form
(
...
@@ -62,6 +62,7 @@ class _ProfileEditForm extends State<ProfileEditForm> {
...
@@ -62,6 +62,7 @@ class _ProfileEditForm extends State<ProfileEditForm> {
if
(
value
==
null
||
value
.
isEmpty
)
{
if
(
value
==
null
||
value
.
isEmpty
)
{
return
"Please enter your username"
;
return
"Please enter your username"
;
}
}
return
null
;
return
null
;
},
},
),
),
...
@@ -75,6 +76,7 @@ class _ProfileEditForm extends State<ProfileEditForm> {
...
@@ -75,6 +76,7 @@ class _ProfileEditForm extends State<ProfileEditForm> {
if
(
value
==
null
||
value
.
isEmpty
)
{
if
(
value
==
null
||
value
.
isEmpty
)
{
return
"Please enter your email"
;
return
"Please enter your email"
;
}
}
return
null
;
return
null
;
},
},
),
),
...
@@ -92,6 +94,10 @@ class _ProfileEditForm extends State<ProfileEditForm> {
...
@@ -92,6 +94,10 @@ class _ProfileEditForm extends State<ProfileEditForm> {
labelText:
"Last Name"
,
labelText:
"Last Name"
,
),
),
),
),
Text
(
message
??
""
,
style:
const
TextStyle
(
color:
Colors
.
red
),
),
Padding
(
Padding
(
padding:
const
EdgeInsets
.
only
(
top:
40.0
),
padding:
const
EdgeInsets
.
only
(
top:
40.0
),
child:
SizedBox
(
child:
SizedBox
(
...
@@ -99,33 +105,20 @@ class _ProfileEditForm extends State<ProfileEditForm> {
...
@@ -99,33 +105,20 @@ class _ProfileEditForm extends State<ProfileEditForm> {
child:
FilledButton
(
child:
FilledButton
(
onPressed:
()
{
onPressed:
()
{
if
(
_formKey
.
currentState
!.
validate
())
{}
if
(
_formKey
.
currentState
!.
validate
())
{}
authProvider
authProvider
.
updateUserDetail
(
.
updateUserDetail
(
context
,
authProvider
.
user
!.
id
,
authProvider
.
user
!.
id
,
usernameControler
.
text
,
usernameControler
.
text
,
emailControler
.
text
,
emailControler
.
text
,
firstNameControler
.
text
,
firstNameControler
.
text
,
lastNameControler
.
text
,
lastNameControler
.
text
,
authProvider
.
user
!.
isStaff
,
authProvider
.
user
!.
isStaff
,
)
);
.
then
(
(
res
)
=>
Navigator
.
pop
(
context
),
);
},
},
child:
const
Text
(
"Submit"
),
child:
const
Text
(
"Submit"
),
),
),
),
),
),
),
Padding
(
padding:
const
EdgeInsets
.
only
(
top:
10.0
),
child:
SizedBox
(
width:
double
.
infinity
,
child:
ElevatedButton
(
onPressed:
()
=>
context
.
go
(
"/change-password"
),
child:
const
Text
(
"Change Password"
),
),
),
)
],
],
),
),
),
),
...
...
lib/src/widgets/forms/reset_password_form.dart
View file @
7bcbe2db
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter_svg/flutter_svg.dart'
;
import
'package:flutter_svg/flutter_svg.dart'
;
import
'package:library_app/src/providers/auth_provider.dart'
;
import
'package:library_app/src/providers/auth_provider.dart'
;
import
'package:library_app/src/screens/form_screen.dart'
;
import
'package:library_app/src/widgets/loading.dart'
;
import
'package:library_app/src/widgets/loading.dart'
;
import
'package:provider/provider.dart'
;
import
'package:provider/provider.dart'
;
...
@@ -22,6 +22,8 @@ class _ResetPasswordForm extends State<ResetPasswordForm> {
...
@@ -22,6 +22,8 @@ class _ResetPasswordForm extends State<ResetPasswordForm> {
const
String
formText
=
"Confirm your email to continue reset password"
;
const
String
formText
=
"Confirm your email to continue reset password"
;
return
Consumer
<
AuthProvider
>(
builder:
(
context
,
authProvider
,
child
)
{
return
Consumer
<
AuthProvider
>(
builder:
(
context
,
authProvider
,
child
)
{
final
message
=
authProvider
.
message
;
return
Column
(
return
Column
(
children:
[
children:
[
Container
(
Container
(
...
@@ -67,13 +69,14 @@ class _ResetPasswordForm extends State<ResetPasswordForm> {
...
@@ -67,13 +69,14 @@ class _ResetPasswordForm extends State<ResetPasswordForm> {
validator:
(
String
?
value
)
{
validator:
(
String
?
value
)
{
if
(
value
==
null
||
value
.
isEmpty
)
{
if
(
value
==
null
||
value
.
isEmpty
)
{
return
"Please enter your email"
;
return
"Please enter your email"
;
}
else
if
(!
value
.
contains
(
"@"
))
{
return
"Email should include '@'"
;
}
}
return
null
;
return
null
;
},
},
),
),
// Flutter, iwant to go to ConfirmResetPasswordScreen after authProvider.resetPassword succeed with response 200
Text
(
message
??
""
,
style:
const
TextStyle
(
color:
Colors
.
red
),
),
Container
(
Container
(
padding:
const
EdgeInsets
.
symmetric
(
padding:
const
EdgeInsets
.
symmetric
(
vertical:
20.0
,
vertical:
20.0
,
...
@@ -85,22 +88,8 @@ class _ResetPasswordForm extends State<ResetPasswordForm> {
...
@@ -85,22 +88,8 @@ class _ResetPasswordForm extends State<ResetPasswordForm> {
child:
FilledButton
(
child:
FilledButton
(
onPressed:
()
{
onPressed:
()
{
if
(
_formKey
.
currentState
!.
validate
())
{}
if
(
_formKey
.
currentState
!.
validate
())
{}
authProvider
authProvider
.
resetPassword
(
.
resetPassword
(
emailController
.
text
)
context
,
emailController
.
text
);
.
then
(
(
response
)
{
Navigator
.
of
(
context
).
push
(
MaterialPageRoute
(
builder:
(
context
)
=>
const
ConfirmResetPasswordScreen
(),
),
);
},
).
catchError
(
(
error
)
{
debugPrint
(
'Exception:
$error
'
);
},
);
},
},
child:
authProvider
.
isLoading
child:
authProvider
.
isLoading
?
const
Loading
()
?
const
Loading
()
...
@@ -142,12 +131,7 @@ class _ConfirmResetPasswordForm extends State<ConfirmResetPasswordForm> {
...
@@ -142,12 +131,7 @@ class _ConfirmResetPasswordForm extends State<ConfirmResetPasswordForm> {
const
String
formText
=
"Enter the pin that we just sent to your email"
;
const
String
formText
=
"Enter the pin that we just sent to your email"
;
return
Consumer
<
AuthProvider
>(
builder:
(
context
,
authProvider
,
child
)
{
return
Consumer
<
AuthProvider
>(
builder:
(
context
,
authProvider
,
child
)
{
if
(
authProvider
.
isLoading
)
{
final
message
=
authProvider
.
message
;
return
const
Center
(
child:
CircularProgressIndicator
(),
);
}
return
Column
(
return
Column
(
children:
[
children:
[
Container
(
Container
(
...
@@ -190,6 +174,17 @@ class _ConfirmResetPasswordForm extends State<ConfirmResetPasswordForm> {
...
@@ -190,6 +174,17 @@ class _ConfirmResetPasswordForm extends State<ConfirmResetPasswordForm> {
labelText:
"confirmation pin"
,
labelText:
"confirmation pin"
,
suffixIcon:
Icon
(
Icons
.
password
),
suffixIcon:
Icon
(
Icons
.
password
),
),
),
keyboardType:
TextInputType
.
number
,
inputFormatters:
[
FilteringTextInputFormatter
.
digitsOnly
],
validator:
(
String
?
value
)
{
if
(
value
==
null
)
{
return
"Please enter your pin"
;
}
else
if
(
value
is
int
)
{
return
"Please enter pin in number"
;
}
return
null
;
},
),
),
TextFormField
(
TextFormField
(
controller:
password1Controller
,
controller:
password1Controller
,
...
@@ -241,12 +236,16 @@ class _ConfirmResetPasswordForm extends State<ConfirmResetPasswordForm> {
...
@@ -241,12 +236,16 @@ class _ConfirmResetPasswordForm extends State<ConfirmResetPasswordForm> {
validator:
(
String
?
value
)
{
validator:
(
String
?
value
)
{
if
(
value
==
null
||
value
.
isEmpty
)
{
if
(
value
==
null
||
value
.
isEmpty
)
{
return
"Please enter your password"
;
return
"Please enter your password"
;
}
else
{
return
null
;
}
}
return
null
;
},
},
keyboardType:
TextInputType
.
visiblePassword
,
keyboardType:
TextInputType
.
visiblePassword
,
),
),
Text
(
message
??
""
,
style:
const
TextStyle
(
color:
Colors
.
red
),
),
Container
(
Container
(
padding:
const
EdgeInsets
.
symmetric
(
padding:
const
EdgeInsets
.
symmetric
(
vertical:
20.0
,
vertical:
20.0
,
...
@@ -258,28 +257,16 @@ class _ConfirmResetPasswordForm extends State<ConfirmResetPasswordForm> {
...
@@ -258,28 +257,16 @@ class _ConfirmResetPasswordForm extends State<ConfirmResetPasswordForm> {
child:
FilledButton
(
child:
FilledButton
(
onPressed:
()
{
onPressed:
()
{
if
(
_formKey
.
currentState
!.
validate
())
{}
if
(
_formKey
.
currentState
!.
validate
())
{}
authProvider
authProvider
.
confirmResetPassword
(
.
confirmResetPassword
(
context
,
int
.
parse
(
pinController
.
text
),
int
.
parse
(
pinController
.
text
),
password1Controller
.
text
,
password1Controller
.
text
,
password2Controller
.
text
,
password2Controller
.
text
,
)
.
then
(
(
response
)
{
Navigator
.
of
(
context
).
push
(
MaterialPageRoute
(
builder:
(
context
)
=>
const
LoginScreen
(),
),
);
},
).
catchError
(
(
error
)
{
debugPrint
(
'Exception:
$error
'
);
},
);
);
},
},
child:
const
Text
(
"Submit"
),
child:
authProvider
.
isLoading
?
const
Loading
()
:
const
Text
(
"Submit"
),
),
),
),
),
],
],
...
...
lib/src/widgets/forms/search_form.dart
View file @
7bcbe2db
...
@@ -24,17 +24,19 @@ class _SearchForm extends State<SearchForm> {
...
@@ -24,17 +24,19 @@ class _SearchForm extends State<SearchForm> {
width:
queryData
.
size
.
width
*
0.8
,
width:
queryData
.
size
.
width
*
0.8
,
padding:
const
EdgeInsets
.
symmetric
(
vertical:
8.0
),
padding:
const
EdgeInsets
.
symmetric
(
vertical:
8.0
),
child:
SearchBar
(
child:
SearchBar
(
hintText:
"Enter
keywords
..."
,
hintText:
"Enter
book title
..."
,
elevation:
WidgetStateProperty
.
all
(
0
),
elevation:
WidgetStateProperty
.
all
(
0
),
onChanged:
(
value
)
{
onChanged:
(
value
)
{
Future
.
delayed
(
if
(
value
.
length
>=
3
)
{
Duration
.
zero
,
Future
.
delayed
(
()
{
Duration
.
zero
,
Provider
.
of
<
BookProvider
>(
context
,
listen:
false
)
()
{
.
setSearchKeyword
(
value
);
Provider
.
of
<
BookProvider
>(
context
,
listen:
false
)
Provider
.
of
<
BookProvider
>(
context
,
listen:
false
).
getBooks
();
.
setSearchKeyword
(
value
);
},
Provider
.
of
<
BookProvider
>(
context
,
listen:
false
).
getBooks
();
);
},
);
}
},
},
leading:
const
Icon
(
Icons
.
search
),
leading:
const
Icon
(
Icons
.
search
),
),
),
...
...
lib/src/widgets/forms/sign_up_form.dart
View file @
7bcbe2db
...
@@ -40,6 +40,8 @@ class _SignUpForm extends State<SignUpForm> {
...
@@ -40,6 +40,8 @@ class _SignUpForm extends State<SignUpForm> {
const
String
formText
=
"Sign In to get started"
;
const
String
formText
=
"Sign In to get started"
;
return
Consumer
<
AuthProvider
>(
builder:
(
context
,
authProvider
,
child
)
{
return
Consumer
<
AuthProvider
>(
builder:
(
context
,
authProvider
,
child
)
{
final
message
=
authProvider
.
message
;
return
Column
(
return
Column
(
children:
[
children:
[
Padding
(
Padding
(
...
@@ -120,8 +122,10 @@ class _SignUpForm extends State<SignUpForm> {
...
@@ -120,8 +122,10 @@ class _SignUpForm extends State<SignUpForm> {
},
},
keyboardType:
TextInputType
.
visiblePassword
,
keyboardType:
TextInputType
.
visiblePassword
,
),
),
const
SizedBox
(
Padding
(
height:
20.0
,
padding:
const
EdgeInsets
.
symmetric
(
vertical:
20.0
),
child:
Text
(
message
??
""
,
style:
const
TextStyle
(
color:
Colors
.
red
)),
),
),
Column
(
Column
(
children:
[
children:
[
...
...
lib/src/widgets/loans/admin_loan_list.dart
View file @
7bcbe2db
...
@@ -36,6 +36,40 @@ class _AdminLoanList extends State<AdminLoanList> {
...
@@ -36,6 +36,40 @@ class _AdminLoanList extends State<AdminLoanList> {
super
.
initState
();
super
.
initState
();
}
}
ScrollController
listScrollController
=
ScrollController
();
void
scrollToTop
()
{
if
(
listScrollController
.
hasClients
)
{
final
position
=
listScrollController
.
position
.
minScrollExtent
;
listScrollController
.
jumpTo
(
position
);
}
}
Future
<
void
>
nextPage
()
async
{
if
(
Provider
.
of
<
AuthProvider
>(
context
,
listen:
false
).
hasNextPage
)
{
Provider
.
of
<
AuthProvider
>(
context
,
listen:
false
).
setPage
(
Provider
.
of
<
AuthProvider
>(
context
,
listen:
false
).
pageNumber
+
1
,
);
}
else
{
Provider
.
of
<
AuthProvider
>(
context
,
listen:
false
).
setPage
(
Provider
.
of
<
AuthProvider
>(
context
,
listen:
false
).
totalPages
!);
}
Provider
.
of
<
AuthProvider
>(
context
,
listen:
false
).
getMemberLoan
();
scrollToTop
();
}
Future
<
void
>
prevPage
()
async
{
if
(
Provider
.
of
<
AuthProvider
>(
context
,
listen:
false
).
hasPrevPage
)
{
Provider
.
of
<
AuthProvider
>(
context
,
listen:
false
).
setPage
(
Provider
.
of
<
AuthProvider
>(
context
,
listen:
false
).
pageNumber
-
1
,
);
}
else
{
Provider
.
of
<
AuthProvider
>(
context
,
listen:
false
).
setPage
(
1
);
}
Provider
.
of
<
AuthProvider
>(
context
,
listen:
false
).
getMemberLoan
();
scrollToTop
();
}
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
return
Consumer
<
AuthProvider
>(
builder:
(
context
,
loanProvider
,
child
)
{
return
Consumer
<
AuthProvider
>(
builder:
(
context
,
loanProvider
,
child
)
{
...
@@ -45,18 +79,8 @@ class _AdminLoanList extends State<AdminLoanList> {
...
@@ -45,18 +79,8 @@ class _AdminLoanList extends State<AdminLoanList> {
if
(
getLoans
!=
null
)
{
if
(
getLoans
!=
null
)
{
var
loans
=
getLoans
.
map
(
var
loans
=
getLoans
.
map
(
(
loan
)
{
(
loan
)
{
var
book
=
Book
.
fromJson
(
loan
[
"book_detail"
]);
var
book
=
Book
.
fromJson
(
loan
[
"book"
]);
var
memberData
=
loan
[
"member_detail"
];
var
user
=
User
.
fromJson
(
loan
[
"user"
]);
var
userData
=
memberData
[
"user"
];
var
user
=
User
(
userData
[
"id"
],
memberData
[
"id"
],
userData
[
"username"
],
userData
[
"email"
],
userData
[
"first_name"
],
userData
[
"last_name"
],
userData
[
"is_staff"
],
);
return
Loan
(
return
Loan
(
book
,
book
,
...
@@ -73,13 +97,34 @@ class _AdminLoanList extends State<AdminLoanList> {
...
@@ -73,13 +97,34 @@ class _AdminLoanList extends State<AdminLoanList> {
headerSliverBuilder:
(
BuildContext
context
,
bool
innerBoxIsScrolled
)
{
headerSliverBuilder:
(
BuildContext
context
,
bool
innerBoxIsScrolled
)
{
return
[
TopAppBar
(
title:
title
)];
return
[
TopAppBar
(
title:
title
)];
},
},
body:
ListView
(
body:
ListView
.
builder
(
children:
List
.
generate
(
loans
.
length
,
(
index
)
{
controller:
listScrollController
,
return
LoanItem
(
itemCount:
loans
.
length
+
1
,
loans
.
elementAt
(
index
),
itemBuilder:
(
context
,
index
)
{
user:
loans
.
elementAt
(
index
).
user
,
if
(
index
<
loans
.
length
)
{
);
return
LoanItem
(
}),
loans
.
elementAt
(
index
),
);
}
else
{
return
Container
(
padding:
const
EdgeInsets
.
all
(
10
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
ElevatedButton
(
onPressed:
prevPage
,
child:
const
Text
(
'Prev'
),
),
Text
(
loanProvider
.
pageNumber
.
toString
()),
ElevatedButton
(
onPressed:
nextPage
,
child:
const
Text
(
'Next'
),
),
],
),
);
}
},
),
),
);
);
}
else
{
}
else
{
...
...
lib/src/widgets/loans/loan_list.dart
View file @
7bcbe2db
...
@@ -26,13 +26,47 @@ class _LoanList extends State<LoanList> {
...
@@ -26,13 +26,47 @@ class _LoanList extends State<LoanList> {
super
.
initState
();
super
.
initState
();
}
}
ScrollController
listScrollController
=
ScrollController
();
void
scrollToTop
()
{
if
(
listScrollController
.
hasClients
)
{
final
position
=
listScrollController
.
position
.
minScrollExtent
;
listScrollController
.
jumpTo
(
position
);
}
}
Future
<
void
>
nextPage
()
async
{
if
(
Provider
.
of
<
AuthProvider
>(
context
,
listen:
false
).
hasNextPage
)
{
Provider
.
of
<
AuthProvider
>(
context
,
listen:
false
).
setPage
(
Provider
.
of
<
AuthProvider
>(
context
,
listen:
false
).
pageNumber
+
1
,
);
}
else
{
Provider
.
of
<
AuthProvider
>(
context
,
listen:
false
).
setPage
(
Provider
.
of
<
AuthProvider
>(
context
,
listen:
false
).
totalPages
!);
}
Provider
.
of
<
AuthProvider
>(
context
,
listen:
false
).
getMemberLoan
();
scrollToTop
();
}
Future
<
void
>
prevPage
()
async
{
if
(
Provider
.
of
<
AuthProvider
>(
context
,
listen:
false
).
hasPrevPage
)
{
Provider
.
of
<
AuthProvider
>(
context
,
listen:
false
).
setPage
(
Provider
.
of
<
AuthProvider
>(
context
,
listen:
false
).
pageNumber
-
1
,
);
}
else
{
Provider
.
of
<
AuthProvider
>(
context
,
listen:
false
).
setPage
(
1
);
}
Provider
.
of
<
AuthProvider
>(
context
,
listen:
false
).
getMemberLoan
();
scrollToTop
();
}
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
return
Consumer
<
AuthProvider
>(
builder:
(
context
,
authProvider
,
child
)
{
return
Consumer
<
AuthProvider
>(
builder:
(
context
,
authProvider
,
child
)
{
if
(
authProvider
.
memberLoans
!=
null
)
{
if
(
authProvider
.
memberLoans
!=
null
)
{
var
loans
=
authProvider
.
memberLoans
!.
map
(
var
loans
=
authProvider
.
memberLoans
!.
map
(
(
loan
)
{
(
loan
)
{
var
book
=
Book
.
fromJson
(
loan
[
"book
_detail
"
]);
var
book
=
Book
.
fromJson
(
loan
[
"book"
]);
return
Loan
(
return
Loan
(
book
,
book
,
null
,
null
,
...
@@ -48,10 +82,35 @@ class _LoanList extends State<LoanList> {
...
@@ -48,10 +82,35 @@ class _LoanList extends State<LoanList> {
headerSliverBuilder:
(
BuildContext
context
,
bool
innerBoxIsScrolled
)
{
headerSliverBuilder:
(
BuildContext
context
,
bool
innerBoxIsScrolled
)
{
return
[
const
TopAppBar
(
title:
"Book Loans"
)];
return
[
const
TopAppBar
(
title:
"Book Loans"
)];
},
},
body:
ListView
(
body:
ListView
.
builder
(
children:
List
.
generate
(
loans
.
length
,
(
index
)
{
controller:
listScrollController
,
return
LoanItem
(
loans
.
elementAt
(
index
));
itemCount:
loans
.
length
+
1
,
}),
itemBuilder:
(
context
,
index
)
{
if
(
index
<
loans
.
length
)
{
return
LoanItem
(
loans
.
elementAt
(
index
),
user:
loans
.
elementAt
(
index
).
user
,
);
}
else
{
return
Container
(
padding:
const
EdgeInsets
.
all
(
10
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
ElevatedButton
(
onPressed:
prevPage
,
child:
const
Text
(
'Prev'
),
),
Text
(
authProvider
.
pageNumber
.
toString
()),
ElevatedButton
(
onPressed:
nextPage
,
child:
const
Text
(
'Next'
),
),
],
),
);
}
},
),
),
);
);
}
else
{
}
else
{
...
...
lib/src/widgets/profile.dart
View file @
7bcbe2db
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:library_app/src/providers/auth_provider.dart'
;
import
'package:provider/provider.dart'
;
import
'package:go_router/go_router.dart'
;
import
'package:library_app/src/
screens/profile_edit_screen
.dart'
;
import
'package:library_app/src/
providers/auth_provider
.dart'
;
import
'package:library_app/src/widgets/navigations.dart'
;
import
'package:library_app/src/widgets/navigations.dart'
;
import
'package:provider/provider.dart'
;
class
Profile
extends
StatefulWidget
{
class
Profile
extends
StatefulWidget
{
const
Profile
({
super
.
key
});
const
Profile
({
super
.
key
});
...
@@ -78,19 +78,25 @@ class _Profile extends State<Profile> {
...
@@ -78,19 +78,25 @@ class _Profile extends State<Profile> {
textAlign:
TextAlign
.
center
,
textAlign:
TextAlign
.
center
,
),
),
),
),
const
SizedBox
(
height:
10.0
,
),
FilledButton
(
FilledButton
(
child:
const
Text
(
"Edit Profile"
),
child:
const
Text
(
"Edit Profile"
),
onPressed:
()
{
onPressed:
()
{
Navigator
.
of
(
context
).
push
(
context
.
push
(
"/profile-edit"
);
MaterialPageRoute
(
builder:
(
context
)
=>
const
ProfileEditScreen
(),
),
);
},
},
),
),
const
SizedBox
(
const
SizedBox
(
height:
10.0
,
height:
10.0
,
),
),
ElevatedButton
(
onPressed:
()
=>
context
.
push
(
"/change-password"
),
child:
const
Text
(
"Change Password"
),
),
const
SizedBox
(
height:
10.0
,
),
OutlinedButton
(
OutlinedButton
(
child:
const
Text
(
"Log Out"
),
child:
const
Text
(
"Log Out"
),
onPressed:
()
{
onPressed:
()
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment