Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
A
AppUms_Lecturer
Overview
Overview
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
tungnq
AppUms_Lecturer
Commits
5cfc51c6
Commit
5cfc51c6
authored
Sep 12, 2025
by
tungnq
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
TODO: Bổ sung tính năng vuốt màn hình cho màn tháng
parent
7d9699f8
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
71 additions
and
8 deletions
+71
-8
index.js
src/screens/class_schedule/index.js
+5
-1
style.js
src/screens/class_schedule/style.js
+37
-5
view.js
src/screens/class_schedule/view.js
+29
-2
No files found.
src/screens/class_schedule/index.js
View file @
5cfc51c6
import
React
,
{
useState
,
useMemo
,
useRef
}
from
'react'
;
import
React
,
{
useState
,
useMemo
,
useRef
}
from
'react'
;
import
{
Animated
,
PanResponder
,
Dimensions
}
from
'react-native'
;
import
{
Animated
,
PanResponder
,
Dimensions
,
DeviceEventEmitter
}
from
'react-native'
;
import
ClassScheduleView
from
'./view'
;
import
ClassScheduleView
from
'./view'
;
// ==================== HẰNG SỐ ====================
// ==================== HẰNG SỐ ====================
...
@@ -288,6 +288,10 @@ const ClassSchedule = ({events = [], onDateSelect, onEventPress}) => {
...
@@ -288,6 +288,10 @@ const ClassSchedule = ({events = [], onDateSelect, onEventPress}) => {
}
}
setCurrentDate
(
newDate
);
setCurrentDate
(
newDate
);
setSelectedDate
(
null
);
setSelectedDate
(
null
);
// Phát sự kiện để cập nhật header title
DeviceEventEmitter
.
emit
(
'onDateChange'
,
newDate
.
toISOString
());
if
(
showBottomSheet
)
{
if
(
showBottomSheet
)
{
hideBottomSheetModal
();
hideBottomSheetModal
();
}
}
...
...
src/screens/class_schedule/style.js
View file @
5cfc51c6
...
@@ -7,11 +7,14 @@ const CELL_HEIGHT = (screenHeight - 140) / 6;
...
@@ -7,11 +7,14 @@ const CELL_HEIGHT = (screenHeight - 140) / 6;
const
BOTTOM_SHEET_HEIGHT
=
screenHeight
*
0.6
;
const
BOTTOM_SHEET_HEIGHT
=
screenHeight
*
0.6
;
const
styles
=
StyleSheet
.
create
({
const
styles
=
StyleSheet
.
create
({
// Container chính của màn hình
container
:
{
container
:
{
flex
:
1
,
flex
:
1
,
backgroundColor
:
R
.
colors
.
white
,
backgroundColor
:
R
.
colors
.
white
,
alignItems
:
'center'
,
alignItems
:
'center'
,
},
},
// Header tháng/năm với nút điều hướng
header
:
{
header
:
{
flexDirection
:
'row'
,
flexDirection
:
'row'
,
alignItems
:
'center'
,
alignItems
:
'center'
,
...
@@ -24,6 +27,7 @@ const styles = StyleSheet.create({
...
@@ -24,6 +27,7 @@ const styles = StyleSheet.create({
color
:
R
.
colors
.
black
,
color
:
R
.
colors
.
black
,
fontWeight
:
'600'
,
fontWeight
:
'600'
,
},
},
// Nút điều hướng tháng trước/sau
navButton
:
{
navButton
:
{
width
:
30
,
width
:
30
,
height
:
30
,
height
:
30
,
...
@@ -37,6 +41,8 @@ const styles = StyleSheet.create({
...
@@ -37,6 +41,8 @@ const styles = StyleSheet.create({
fontSize
:
R
.
fontsize
.
fontsSizeTitle
,
fontSize
:
R
.
fontsize
.
fontsSizeTitle
,
fontFamily
:
R
.
fonts
.
fontMedium
,
fontFamily
:
R
.
fonts
.
fontMedium
,
},
},
// Tiêu đề các ngày trong tuần
weekDaysContainer
:
{
weekDaysContainer
:
{
flexDirection
:
'row'
,
flexDirection
:
'row'
,
paddingBottom
:
5
,
paddingBottom
:
5
,
...
@@ -52,10 +58,14 @@ const styles = StyleSheet.create({
...
@@ -52,10 +58,14 @@ const styles = StyleSheet.create({
fontWeight
:
'600'
,
fontWeight
:
'600'
,
color
:
R
.
colors
.
black
,
color
:
R
.
colors
.
black
,
},
},
// Lưới lịch
calendarGrid
:
{},
calendarGrid
:
{},
weekRow
:
{
weekRow
:
{
flexDirection
:
'row'
,
flexDirection
:
'row'
,
},
},
// Ô ngày trong lịch
dayCell
:
{
dayCell
:
{
width
:
CELL_WIDTH
,
width
:
CELL_WIDTH
,
minHeight
:
CELL_HEIGHT
,
minHeight
:
CELL_HEIGHT
,
...
@@ -64,11 +74,12 @@ const styles = StyleSheet.create({
...
@@ -64,11 +74,12 @@ const styles = StyleSheet.create({
padding
:
4
,
padding
:
4
,
alignItems
:
'center'
,
alignItems
:
'center'
,
},
},
// Ô ngày được chọn
selectedDayCell
:
{
selectedDayCell
:
{
borderColor
:
R
.
colors
.
blue
,
borderColor
:
R
.
colors
.
blue
,
borderWidth
:
1
,
borderWidth
:
1
,
},
},
// Text số ngày
dayText
:
{
dayText
:
{
fontSize
:
R
.
fontsize
.
fontSizeLabel
,
fontSize
:
R
.
fontsize
.
fontSizeLabel
,
fontWeight
:
'400'
,
fontWeight
:
'400'
,
...
@@ -76,15 +87,18 @@ const styles = StyleSheet.create({
...
@@ -76,15 +87,18 @@ const styles = StyleSheet.create({
color
:
R
.
colors
.
black
,
color
:
R
.
colors
.
black
,
marginBottom
:
2
,
marginBottom
:
2
,
},
},
// Text ngày không thuộc tháng hiện tại
dayTextInactive
:
{
dayTextInactive
:
{
color
:
R
.
colors
.
black
,
color
:
R
.
colors
.
black
,
opacity
:
1
,
opacity
:
1
,
},
},
// Text ngày được chọn
selectedDayText
:
{
selectedDayText
:
{
color
:
R
.
colors
.
black
,
color
:
R
.
colors
.
black
,
fontWeight
:
'bold'
,
fontWeight
:
'bold'
,
fontFamily
:
R
.
fonts
.
fontSemiBold
,
fontFamily
:
R
.
fonts
.
fontSemiBold
,
},
},
// Text ngày hôm nay
todayText
:
{
todayText
:
{
color
:
R
.
colors
.
white
,
color
:
R
.
colors
.
white
,
fontWeight
:
'bold'
,
fontWeight
:
'bold'
,
...
@@ -95,10 +109,12 @@ const styles = StyleSheet.create({
...
@@ -95,10 +109,12 @@ const styles = StyleSheet.create({
paddingVertical
:
2
,
paddingVertical
:
2
,
},
},
// Sự kiện trong ô ngày
eventsContainer
:
{
eventsContainer
:
{
width
:
'100%'
,
width
:
'100%'
,
flex
:
1
,
flex
:
1
,
},
},
// Thanh sự kiện nhỏ trong ô ngày
eventBar
:
{
eventBar
:
{
paddingVertical
:
2
,
paddingVertical
:
2
,
paddingHorizontal
:
5
,
paddingHorizontal
:
5
,
...
@@ -112,6 +128,7 @@ const styles = StyleSheet.create({
...
@@ -112,6 +128,7 @@ const styles = StyleSheet.create({
fontWeight
:
'400'
,
fontWeight
:
'400'
,
fontFamily
:
R
.
fonts
.
fontRegular
,
fontFamily
:
R
.
fonts
.
fontRegular
,
},
},
// Text hiển thị số sự kiện còn lại
moreEventsText
:
{
moreEventsText
:
{
fontSize
:
R
.
fontsize
.
fontSizeLabel
,
fontSize
:
R
.
fontsize
.
fontSizeLabel
,
color
:
R
.
colors
.
gray
,
color
:
R
.
colors
.
gray
,
...
@@ -119,11 +136,8 @@ const styles = StyleSheet.create({
...
@@ -119,11 +136,8 @@ const styles = StyleSheet.create({
fontFamily
:
R
.
fonts
.
fontRegular
,
fontFamily
:
R
.
fonts
.
fontRegular
,
textAlign
:
'center'
,
textAlign
:
'center'
,
},
},
containerBottomSheet
:
{
flex
:
1
,
marginBottom
:
10
,
},
// Modal bottom sheet
modalBackdrop
:
{
modalBackdrop
:
{
flex
:
1
,
flex
:
1
,
backgroundColor
:
R
.
colors
.
grayBorderInputTextHeader
,
backgroundColor
:
R
.
colors
.
grayBorderInputTextHeader
,
...
@@ -135,9 +149,12 @@ const styles = StyleSheet.create({
...
@@ -135,9 +149,12 @@ const styles = StyleSheet.create({
borderTopLeftRadius
:
20
,
borderTopLeftRadius
:
20
,
borderTopRightRadius
:
20
,
borderTopRightRadius
:
20
,
},
},
// Nội dung bottom sheet
bottomSheetContent
:
{
bottomSheetContent
:
{
height
:
BOTTOM_SHEET_HEIGHT
,
height
:
BOTTOM_SHEET_HEIGHT
,
},
},
// Thanh kéo
dragHandle
:
{
dragHandle
:
{
width
:
40
,
width
:
40
,
height
:
4
,
height
:
4
,
...
@@ -147,6 +164,7 @@ const styles = StyleSheet.create({
...
@@ -147,6 +164,7 @@ const styles = StyleSheet.create({
marginTop
:
10
,
marginTop
:
10
,
marginBottom
:
15
,
marginBottom
:
15
,
},
},
// Header của bottom sheet
bottomSheetHeader
:
{
bottomSheetHeader
:
{
flexDirection
:
'row'
,
flexDirection
:
'row'
,
alignItems
:
'center'
,
alignItems
:
'center'
,
...
@@ -160,6 +178,7 @@ const styles = StyleSheet.create({
...
@@ -160,6 +178,7 @@ const styles = StyleSheet.create({
fontWeight
:
'600'
,
fontWeight
:
'600'
,
flex
:
1
,
flex
:
1
,
},
},
// Nút đóng bottom sheet
closeButton
:
{
closeButton
:
{
width
:
30
,
width
:
30
,
height
:
30
,
height
:
30
,
...
@@ -174,9 +193,18 @@ const styles = StyleSheet.create({
...
@@ -174,9 +193,18 @@ const styles = StyleSheet.create({
fontFamily
:
R
.
fonts
.
fontRegular
,
fontFamily
:
R
.
fonts
.
fontRegular
,
fontWeight
:
'400'
,
fontWeight
:
'400'
,
},
},
// Danh sách sự kiện trong bottom sheet
// ScrollView chứa danh sách sự kiện
eventsScrollView
:
{
eventsScrollView
:
{
paddingTop
:
10
,
paddingTop
:
10
,
},
},
// Container cho từng sự kiện
containerBottomSheet
:
{
flex
:
1
,
marginBottom
:
10
,
},
// Trạng thái không có sự kiện
noEventsContainer
:
{
noEventsContainer
:
{
flex
:
1
,
flex
:
1
,
alignItems
:
'center'
,
alignItems
:
'center'
,
...
@@ -189,6 +217,8 @@ const styles = StyleSheet.create({
...
@@ -189,6 +217,8 @@ const styles = StyleSheet.create({
color
:
R
.
colors
.
gray
,
color
:
R
.
colors
.
gray
,
fontWeight
:
'400'
,
fontWeight
:
'400'
,
},
},
// Card sự kiện chi tiết
eventCard
:
{
eventCard
:
{
flexDirection
:
'row'
,
flexDirection
:
'row'
,
backgroundColor
:
R
.
colors
.
white
,
backgroundColor
:
R
.
colors
.
white
,
...
@@ -207,6 +237,7 @@ const styles = StyleSheet.create({
...
@@ -207,6 +237,7 @@ const styles = StyleSheet.create({
shadowRadius
:
1
,
shadowRadius
:
1
,
elevation
:
2
,
elevation
:
2
,
},
},
// Container thời gian sự kiện
eventTimeContainer
:
{
eventTimeContainer
:
{
minWidth
:
80
,
minWidth
:
80
,
alignItems
:
'flex-start'
,
alignItems
:
'flex-start'
,
...
@@ -219,6 +250,7 @@ const styles = StyleSheet.create({
...
@@ -219,6 +250,7 @@ const styles = StyleSheet.create({
color
:
R
.
colors
.
blue
,
color
:
R
.
colors
.
blue
,
fontWeight
:
'600'
,
fontWeight
:
'600'
,
},
},
// Container nội dung sự kiện
eventContent
:
{
eventContent
:
{
flex
:
1
,
flex
:
1
,
},
},
...
...
src/screens/class_schedule/view.js
View file @
5cfc51c6
...
@@ -6,7 +6,8 @@ import {
...
@@ -6,7 +6,8 @@ import {
ScrollView
,
ScrollView
,
Modal
,
Modal
,
Animated
,
Animated
,
LogBox
LogBox
,
PanResponder
}
from
'react-native'
;
}
from
'react-native'
;
import
R
from
'../../assets/R'
;
import
R
from
'../../assets/R'
;
import
{
styles
}
from
'./style'
;
import
{
styles
}
from
'./style'
;
...
@@ -36,6 +37,28 @@ const ClassScheduleView = ({
...
@@ -36,6 +37,28 @@ const ClassScheduleView = ({
getSelectedEvents
,
getSelectedEvents
,
})
=>
{
})
=>
{
const
navigation
=
useNavigation
();
const
navigation
=
useNavigation
();
// Tạo PanResponder cho swipe gesture điều hướng tháng
const
swipePanResponder
=
PanResponder
.
create
({
onMoveShouldSetPanResponder
:
(
evt
,
gestureState
)
=>
{
// Chỉ kích hoạt khi vuốt ngang với khoảng cách đủ lớn
return
Math
.
abs
(
gestureState
.
dx
)
>
Math
.
abs
(
gestureState
.
dy
)
&&
Math
.
abs
(
gestureState
.
dx
)
>
20
;
},
onPanResponderMove
:
(
evt
,
gestureState
)
=>
{
// Có thể thêm animation preview ở đây nếu cần
},
onPanResponderRelease
:
(
evt
,
gestureState
)
=>
{
const
swipeThreshold
=
50
;
// Ngưỡng tối thiểu để kích hoạt swipe
if
(
gestureState
.
dx
>
swipeThreshold
)
{
// Vuốt phải -> tháng trước
navigateMonth
(
'prev'
);
}
else
if
(
gestureState
.
dx
<
-
swipeThreshold
)
{
// Vuốt trái -> tháng sau
navigateMonth
(
'next'
);
}
},
});
const
renderHeader
=
()
=>
{
const
renderHeader
=
()
=>
{
const
monthNames
=
[
const
monthNames
=
[
'Tháng 1'
,
'Tháng 1'
,
...
@@ -214,6 +237,8 @@ const ClassScheduleView = ({
...
@@ -214,6 +237,8 @@ const ClassScheduleView = ({
);
);
};
};
// ===== RENDER BOTTOM SHEET - Modal bottom sheet =====
// Sử dụng styles: modalBackdrop, bottomSheet
const
renderBottomSheet
=
()
=>
{
const
renderBottomSheet
=
()
=>
{
return
(
return
(
<
Modal
<
Modal
...
@@ -242,10 +267,12 @@ const ClassScheduleView = ({
...
@@ -242,10 +267,12 @@ const ClassScheduleView = ({
);
);
};
};
// ===== MAIN RENDER - Render chính của component =====
// Sử dụng styles: container
return
(
return
(
<
View
style
=
{
styles
.
container
}
>
<
View
style
=
{
styles
.
container
}
>
<
ScrollView
showsVerticalScrollIndicator
=
{
false
}
>
<
ScrollView
showsVerticalScrollIndicator
=
{
false
}
>
<
View
style
=
{
styles
.
body
}
>
<
View
style
=
{
styles
.
body
}
{...
swipePanResponder
.
panHandlers
}
>
{
renderHeader
()}
{
renderHeader
()}
{
renderWeekDays
()}
{
renderWeekDays
()}
{
renderCalendarGrid
()}
{
renderCalendarGrid
()}
...
...
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