Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Hoàng Văn Đạt
mypoint_flutter_app
Commits
b3c72190
Commit
b3c72190
authored
Nov 19, 2025
by
DatHV
Browse files
update invite friend.
update config build
parent
6b980613
Changes
29
Hide whitespace changes
Inline
Side-by-side
lib/features/splash/splash_screen.dart
View file @
b3c72190
...
...
@@ -33,7 +33,7 @@ class _SplashScreenState extends BaseState<SplashScreen> with BasicState {
return
;
}
if
(
updateData
.
status
==
UpdateStatus
.
none
)
{
_viewModel
.
directionWhenTokenInvalid
();
_viewModel
.
makeDataFollowInitApp
();
}
else
{
_showSuggestUpdateAlert
(
updateData
);
}
...
...
lib/features/splash/splash_screen_viewmodel.dart
View file @
b3c72190
...
...
@@ -106,7 +106,6 @@ class SplashScreenViewModel extends RestfulApiViewModel {
}
Future
<
void
>
directionWhenTokenInvalid
()
async
{
if
(
Get
.
currentRoute
==
onboardingScreen
)
return
;
// if (kIsWeb) {
// print('❌ No token found on web, closing app');
// final closeSuccess = await webCloseApp({
...
...
lib/features/voucher/voucher_tab_screen.dart
View file @
b3c72190
import
'package:flutter/foundation.dart'
;
import
'package:flutter/material.dart'
;
import
'package:get/get.dart'
;
import
'../../app/routing/directional_action_type.dart'
;
...
...
@@ -32,14 +33,23 @@ class _VoucherTabScreenState extends State<VoucherTabScreen> with PopupOnInit {
return
Scaffold
(
appBar:
CustomNavigationBar
(
title:
"Ưu đãi"
,
leftButtons:
[],
leftButtons:
[
if
(
kIsWeb
)
IconButton
(
icon:
const
Icon
(
Icons
.
search
,
color:
Colors
.
white
),
onPressed:
()
{
Get
.
toNamed
(
vouchersScreen
,
arguments:
{
"enableSearch"
:
true
});
},
),
],
rightButtons:
[
IconButton
(
icon:
const
Icon
(
Icons
.
search
,
color:
Colors
.
white
),
onPressed:
()
{
Get
.
toNamed
(
vouchersScreen
,
arguments:
{
"enableSearch"
:
true
});
},
),
if
(!
kIsWeb
)
IconButton
(
icon:
const
Icon
(
Icons
.
search
,
color:
Colors
.
white
),
onPressed:
()
{
Get
.
toNamed
(
vouchersScreen
,
arguments:
{
"enableSearch"
:
true
});
},
),
],
),
body:
Obx
(()
{
...
...
lib/shared/navigation/directional_screen.dart
View file @
b3c72190
...
...
@@ -372,7 +372,7 @@ class DirectionalScreen {
}
}
void
_logUnsupported
(
type
)
{
void
_logUnsupported
(
DirectionalScreenName
type
)
{
debugPrint
(
"⚠️ DirectionalScreen action type không được hỗ trợ:
${type.rawValue}
"
);
}
...
...
lib/shared/router_gage.dart
View file @
b3c72190
...
...
@@ -68,6 +68,8 @@ const qrCodeScreen = '/qrCodeScreen';
const
myMobileCardDetailScreen
=
'/myMobileCardDetailScreen'
;
const
healthBookCardDetail
=
'/healthBookCardDetail'
;
const
notificationDetailScreen
=
'/notificationDetailScreen'
;
const
referralCodeInviteFriendScreen
=
'/referralCodeInviteFriendScreen'
;
const
campaignInviteReferralInfoScreen
=
'/campaignInviteReferralInfoScreen'
;
class
RouterPage
{
static
List
<
GetPage
>
pages
()
{
...
...
@@ -138,6 +140,8 @@ class RouterPage {
GetPage
(
name:
healthBookScreen
,
page:
()
=>
const
HealthBookDeferredScreen
()),
GetPage
(
name:
healthBookCardDetail
,
page:
()
=>
const
HealthBookCardDetailDeferredScreen
()),
GetPage
(
name:
notificationDetailScreen
,
page:
()
=>
NotificationDetailScreen
()),
GetPage
(
name:
referralCodeInviteFriendScreen
,
page:
()
=>
const
ReferralCodeInviteFriendDeferredScreen
()),
GetPage
(
name:
campaignInviteReferralInfoScreen
,
page:
()
=>
const
CampaignInviteReferralInfoDeferredScreen
()),
];
}
}
}
\ No newline at end of file
lib/shared/widgets/button_container.dart
deleted
100644 → 0
View file @
6b980613
import
'package:flutter/material.dart'
;
class
ButtonContainer
extends
StatelessWidget
{
final
Color
color
;
final
double
cornerRadius
;
final
double
?
height
;
final
double
?
width
;
final
Widget
child
;
final
bool
visible
;
const
ButtonContainer
({
super
.
key
,
required
this
.
child
,
this
.
height
,
this
.
width
,
this
.
color
=
Colors
.
white
,
this
.
cornerRadius
=
8
,
this
.
visible
=
true
,
});
@override
Widget
build
(
BuildContext
context
)
{
return
Visibility
(
visible:
visible
,
child:
Container
(
decoration:
BoxDecoration
(
borderRadius:
BorderRadius
.
circular
(
cornerRadius
),
color:
color
),
width:
width
,
height:
height
,
child:
child
,
),
);
}
}
lib/shared/widgets/custom_app_bar.dart
deleted
100644 → 0
View file @
6b980613
import
'package:flutter/material.dart'
;
import
'back_button.dart'
;
class
CustomAppBar
extends
StatelessWidget
implements
PreferredSizeWidget
{
final
String
title
;
final
List
<
Widget
>
leftButtons
;
final
List
<
Widget
>
rightButtons
;
final
double
height
;
const
CustomAppBar
({
super
.
key
,
required
this
.
title
,
this
.
leftButtons
=
const
[],
this
.
rightButtons
=
const
[],
this
.
height
=
56
,
});
static
CustomAppBar
back
({
required
String
title
})
{
return
CustomAppBar
(
title:
title
,
leftButtons:
[
CustomBackButton
()]);
}
@override
Widget
build
(
BuildContext
context
)
{
return
SafeArea
(
child:
Container
(
height:
height
,
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
16
),
child:
Stack
(
alignment:
Alignment
.
center
,
children:
[
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
Row
(
children:
leftButtons
),
Row
(
children:
rightButtons
)],
),
Padding
(
padding:
const
EdgeInsets
.
only
(
left:
24
,
right:
24
),
child:
Center
(
child:
Text
(
title
,
textAlign:
TextAlign
.
center
,
maxLines:
1
,
style:
const
TextStyle
(
fontSize:
18
,
fontWeight:
FontWeight
.
bold
,
color:
Colors
.
black87
,
),
),
),
),
],
),
),
);
}
@override
Size
get
preferredSize
=>
Size
.
fromHeight
(
height
);
}
\ No newline at end of file
lib/shared/widgets/custom_navigation_bar.dart
View file @
b3c72190
import
'package:auto_size_text/auto_size_text.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/material.dart'
;
import
'package:get/get.dart'
;
import
'../../app/config/constants.dart'
;
import
'../../features/home/header_home_viewmodel.dart'
;
import
'back_button.dart'
;
import
'image_loader.dart'
;
...
...
@@ -21,7 +23,15 @@ class CustomNavigationBar extends StatelessWidget implements PreferredSizeWidget
});
@override
Size
get
preferredSize
=>
const
Size
.
fromHeight
(
kToolbarHeight
);
Size
get
preferredSize
{
final
dispatcher
=
WidgetsBinding
.
instance
.
platformDispatcher
;
final
view
=
dispatcher
.
implicitView
??
(
dispatcher
.
views
.
isNotEmpty
?
dispatcher
.
views
.
first
:
null
);
double
paddingTop
=
view
!=
null
?
MediaQueryData
.
fromView
(
view
).
padding
.
top
:
0.0
;
if
(
paddingTop
==
0
&&
kIsWeb
)
{
paddingTop
=
Constants
.
webTopPadding
;
}
return
Size
.
fromHeight
(
kToolbarHeight
+
paddingTop
);
}
@override
Widget
build
(
BuildContext
context
)
{
...
...
@@ -37,27 +47,28 @@ class CustomNavigationBar extends StatelessWidget implements PreferredSizeWidget
}
Widget
_buildAppBar
(
String
bgImage
,
BuildContext
context
)
{
final
double
statusBarHeight
=
MediaQuery
.
of
(
context
).
padding
.
top
;
double
statusBarHeight
=
MediaQuery
.
of
(
context
).
padding
.
top
;
double
extraWebPadding
=
0
;
if
(
statusBarHeight
==
0
&&
kIsWeb
)
{
extraWebPadding
=
Constants
.
webTopPadding
;
}
final
double
totalTopPadding
=
statusBarHeight
+
extraWebPadding
;
final
bool
isHttp
=
bgImage
.
startsWith
(
'http://'
)
||
bgImage
.
startsWith
(
'https://'
);
final
paddingTitle
=
(
leftButtons
.
isNotEmpty
||
rightButtons
.
isNotEmpty
)
?
48.0
:
16.0
;
// cách 2 đầu
return
Container
(
height:
statusBarHeight
+
kToolbarHeight
,
decoration:
BoxDecoration
(
color:
bgImage
.
isEmpty
?
Colors
.
white
:
null
,
),
child:
Stack
(
fit:
StackFit
.
expand
,
children:
[
if
(
bgImage
.
isNotEmpty
)
isHttp
?
loadNetworkImage
(
url:
bgImage
,
fit:
BoxFit
.
cover
,
placeholderAsset:
_defaultBgImage
,
)
:
Image
.
asset
(
_defaultBgImage
,
fit:
BoxFit
.
cover
),
SafeArea
(
bottom:
false
,
height:
totalTopPadding
+
kToolbarHeight
,
decoration:
BoxDecoration
(
color:
bgImage
.
isEmpty
?
Colors
.
white
:
null
),
child:
Stack
(
fit:
StackFit
.
expand
,
children:
[
if
(
bgImage
.
isNotEmpty
)
isHttp
?
loadNetworkImage
(
url:
bgImage
,
fit:
BoxFit
.
cover
,
placeholderAsset:
_defaultBgImage
)
:
Image
.
asset
(
_defaultBgImage
,
fit:
BoxFit
.
cover
),
SafeArea
(
bottom:
false
,
child:
Padding
(
padding:
EdgeInsets
.
only
(
top:
extraWebPadding
),
child:
Stack
(
alignment:
Alignment
.
center
,
children:
[
...
...
@@ -66,49 +77,28 @@ class CustomNavigationBar extends StatelessWidget implements PreferredSizeWidget
child:
AutoSizeText
(
title
,
maxLines:
1
,
minFontSize:
12
,
// 👈 không nhỏ hơn 8
stepGranularity:
0.1
,
// scale mượt hơn
overflow:
TextOverflow
.
visible
,
// giữ nguyên như bạn đang dùng
minFontSize:
12
,
stepGranularity:
0.1
,
overflow:
TextOverflow
.
visible
,
// giữ nguyên như bạn đang dùng
textAlign:
TextAlign
.
center
,
style:
const
TextStyle
(
fontSize:
18
,
// 👈 cỡ tối đa mong muốn
fontSize:
18
,
// 👈 cỡ tối đa mong muốn
fontWeight:
FontWeight
.
w800
,
color:
Colors
.
white
,
),
),
// child: FittedBox(
// fit: BoxFit.scaleDown, // tự giảm font để vừa khung
// child: Text(
// title,
// maxLines: 1,
// softWrap: false,
// overflow: TextOverflow.visible, // không dùng ellipsis
// textAlign: TextAlign.center,
// style: const TextStyle(
// fontSize: 18, // cỡ tối đa
// fontWeight: FontWeight.w800,
// color: Colors.white,
// ),
// ),
// ),
),
// Text(
// title,
// maxLines: 1,
// style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w800, color: Colors.white),
// textAlign: TextAlign.center,
// ),
// Buttons bên trái
if
(
leftButtons
.
isNotEmpty
)
Positioned
(
left:
12
,
child:
Row
(
mainAxisSize:
MainAxisSize
.
min
,
children:
leftButtons
)),
// Buttons bên phải
if
(
rightButtons
.
isNotEmpty
)
Positioned
(
right:
12
,
child:
Row
(
mainAxisSize:
MainAxisSize
.
min
,
children:
rightButtons
)),
],
),
),
],
),
);
),
],
),
);
}
}
lib/shared/widgets/custom_search_navigation_bar.dart
View file @
b3c72190
import
'package:flutter/foundation.dart'
;
import
'package:flutter/material.dart'
;
import
'package:get/get.dart'
;
import
'../../app/config/constants.dart'
;
import
'../../features/home/header_home_viewmodel.dart'
;
import
'back_button.dart'
;
import
'image_loader.dart'
;
...
...
@@ -21,7 +23,15 @@ class CustomSearchNavigationBar extends StatefulWidget implements PreferredSizeW
});
@override
Size
get
preferredSize
=>
const
Size
.
fromHeight
(
kToolbarHeight
);
Size
get
preferredSize
{
final
dispatcher
=
WidgetsBinding
.
instance
.
platformDispatcher
;
final
view
=
dispatcher
.
implicitView
??
(
dispatcher
.
views
.
isNotEmpty
?
dispatcher
.
views
.
first
:
null
);
double
paddingTop
=
view
!=
null
?
MediaQueryData
.
fromView
(
view
).
padding
.
top
:
0.0
;
if
(
paddingTop
==
0
&&
kIsWeb
)
{
paddingTop
=
Constants
.
webTopPadding
;
}
return
Size
.
fromHeight
(
kToolbarHeight
+
paddingTop
);
}
@override
_CustomSearchNavigationBarState
createState
()
=>
_CustomSearchNavigationBarState
();
...
...
@@ -51,16 +61,14 @@ class _CustomSearchNavigationBarState extends State<CustomSearchNavigationBar> {
Widget
_buildAppBar
(
String
bgImage
,
BuildContext
context
)
{
final
bool
isHttp
=
bgImage
.
startsWith
(
'http://'
)
||
bgImage
.
startsWith
(
'https://'
);
final
double
statusBarHeight
=
MediaQuery
.
of
(
context
).
padding
.
top
;
double
statusBarHeight
=
MediaQuery
.
of
(
context
).
padding
.
top
;
double
extraWebPadding
=
0
;
if
(
statusBarHeight
==
0
&&
kIsWeb
)
{
extraWebPadding
=
Constants
.
webTopPadding
;
}
final
double
totalTopPadding
=
statusBarHeight
+
extraWebPadding
;
return
SizedBox
(
height:
statusBarHeight
+
kToolbarHeight
,
// decoration: BoxDecoration(
// image:
// widget.backgroundImage != null
// ? DecorationImage(image: AssetImage(widget.backgroundImage!), fit: BoxFit.cover)
// : null,
// color: widget.backgroundImage == null ? Colors.white : null,
// ),
height:
totalTopPadding
+
kToolbarHeight
,
child:
Stack
(
fit:
StackFit
.
expand
,
children:
[
...
...
@@ -70,52 +78,55 @@ class _CustomSearchNavigationBarState extends State<CustomSearchNavigationBar> {
:
Image
.
asset
(
_defaultBgImage
,
fit:
BoxFit
.
cover
),
SafeArea
(
bottom:
false
,
child:
Stack
(
alignment:
Alignment
.
center
,
children:
[
Positioned
(
left:
widget
.
showBackButton
?
68
:
16
,
right:
widget
.
rightButtons
.
isNotEmpty
?
60
:
16
,
child:
Container
(
height:
36
,
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
8
),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
12
)),
child:
Row
(
children:
[
const
Icon
(
Icons
.
search
,
size:
20
),
const
SizedBox
(
width:
4
),
Expanded
(
child:
TextField
(
controller:
_controller
,
onChanged:
(
value
)
{
setState
(()
{});
// Update UI for suffix icon
widget
.
onSearchChanged
?.
call
(
value
);
},
decoration:
InputDecoration
(
border:
InputBorder
.
none
,
hintText:
widget
.
hintText
,
isDense:
true
,
contentPadding:
EdgeInsets
.
zero
,
child:
Padding
(
padding:
EdgeInsets
.
only
(
top:
extraWebPadding
),
child:
Stack
(
alignment:
Alignment
.
center
,
children:
[
Positioned
(
left:
widget
.
showBackButton
?
68
:
16
,
right:
widget
.
rightButtons
.
isNotEmpty
?
60
:
16
,
child:
Container
(
height:
36
,
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
8
),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
12
)),
child:
Row
(
children:
[
const
Icon
(
Icons
.
search
,
size:
20
),
const
SizedBox
(
width:
4
),
Expanded
(
child:
TextField
(
controller:
_controller
,
onChanged:
(
value
)
{
setState
(()
{});
// Update UI for suffix icon
widget
.
onSearchChanged
?.
call
(
value
);
},
decoration:
InputDecoration
(
border:
InputBorder
.
none
,
hintText:
widget
.
hintText
,
isDense:
true
,
contentPadding:
EdgeInsets
.
zero
,
),
),
),
)
,
if
(
_controller
.
text
.
isNotEmpty
)
GestureDetector
(
onTap:
()
{
_controller
.
clear
(
);
widget
.
onSearchChanged
?.
call
(
''
);
setState
(()
{});
}
,
child:
const
Icon
(
Icons
.
close
,
size:
20
),
)
,
]
,
if
(
_controller
.
text
.
isNotEmpty
)
GestureDetector
(
onTap:
()
{
_controller
.
clear
();
widget
.
onSearchChanged
?.
call
(
''
);
setState
(()
{}
);
},
child:
const
Icon
(
Icons
.
close
,
size:
20
)
,
),
]
,
)
,
),
),
),
if
(
widget
.
showBackButton
)
Positioned
(
left:
12
,
child:
CustomBackButton
()),
if
(
widget
.
rightButtons
.
isNotEmpty
)
Positioned
(
right:
12
,
child:
Row
(
mainAxisSize:
MainAxisSize
.
min
,
children:
widget
.
rightButtons
))
,
]
,
if
(
widget
.
showBackButton
)
Positioned
(
left:
12
,
child:
CustomBackButton
()
),
if
(
widget
.
rightButtons
.
isNotEmpty
)
Positioned
(
right:
12
,
child:
Row
(
mainAxisSize:
MainAxisSize
.
min
,
children:
widget
.
rightButtons
)),
]
,
)
,
),
),
],
...
...
Prev
1
2
Next
Write
Preview
Supports
Markdown
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