@@ -28,8 +28,8 @@ enum SegmentListTab {
2828 Chapter
2929}
3030
31- interface segmentWithNesting extends SponsorTime {
32- innerChapters ?: ( segmentWithNesting | SponsorTime ) [ ] ;
31+ interface SegmentWithNesting extends SponsorTime {
32+ innerChapters ?: ( SegmentWithNesting | SponsorTime ) [ ] ;
3333}
3434
3535export const SegmentListComponent = ( props : SegmentListComponentProps ) => {
@@ -58,37 +58,41 @@ export const SegmentListComponent = (props: SegmentListComponentProps) => {
5858 }
5959 } ;
6060
61- const segmentsWithNesting : segmentWithNesting [ ] = [ ] ;
62- let nbTrailingNonChapters = 0 ;
63- function nestChapters ( segments : segmentWithNesting [ ] , seg : SponsorTime , topLevel ?: boolean ) {
64- if ( seg . actionType === ActionType . Chapter && segments . length ) {
65- // trailing non-chapters can only exist at top level
66- const lastElement = segments [ segments . length - ( topLevel ? nbTrailingNonChapters + 1 : 1 ) ]
67-
68- if ( lastElement . actionType === ActionType . Chapter
69- && lastElement . segment [ 0 ] <= seg . segment [ 0 ]
70- && lastElement . segment [ 1 ] >= seg . segment [ 1 ] ) {
71- if ( lastElement . innerChapters ) {
72- nestChapters ( lastElement . innerChapters , seg ) ;
61+ const segmentsWithNesting = React . useMemo ( ( ) => {
62+ const result : SegmentWithNesting [ ] = [ ] ;
63+ let nbTrailingNonChapters = 0 ;
64+ function nestChapters ( segments : SegmentWithNesting [ ] , seg : SponsorTime , topLevel ?: boolean ) {
65+ if ( seg . actionType === ActionType . Chapter && segments . length ) {
66+ // trailing non-chapters can only exist at top level
67+ const lastElement = segments [ segments . length - ( topLevel ? nbTrailingNonChapters + 1 : 1 ) ]
68+
69+ if ( lastElement . actionType === ActionType . Chapter
70+ && lastElement . segment [ 0 ] <= seg . segment [ 0 ]
71+ && lastElement . segment [ 1 ] >= seg . segment [ 1 ] ) {
72+ if ( lastElement . innerChapters ) {
73+ nestChapters ( lastElement . innerChapters , seg ) ;
74+ } else {
75+ lastElement . innerChapters = [ seg ] ;
76+ }
7377 } else {
74- lastElement . innerChapters = [ seg ] ;
75- }
76- } else {
77- if ( topLevel ) {
78- nbTrailingNonChapters = 0 ;
79- }
78+ if ( topLevel ) {
79+ nbTrailingNonChapters = 0 ;
80+ }
8081
81- segments . push ( seg ) ;
82+ segments . push ( seg ) ;
83+ }
84+ } else {
85+ if ( seg . actionType !== ActionType . Chapter ) {
86+ nbTrailingNonChapters ++ ;
8287 }
83- } else {
84- if ( seg . actionType !== ActionType . Chapter ) {
85- nbTrailingNonChapters ++ ;
86- }
8788
88- segments . push ( seg ) ;
89+ segments . push ( seg ) ;
90+ }
8991 }
90- }
91- props . segments . forEach ( ( seg ) => nestChapters ( segmentsWithNesting , { ...seg } , true ) ) ;
92+ props . segments . forEach ( ( seg ) => nestChapters ( result , { ...seg } , true ) ) ;
93+ return result ;
94+ } , [ props . segments ] )
95+
9296
9397 return (
9498 < div id = "issueReporterContainer" >
@@ -136,7 +140,7 @@ export const SegmentListComponent = (props: SegmentListComponentProps) => {
136140} ;
137141
138142function SegmentListItem ( { segment, videoID, currentTime, isVip, loopedChapter, tabFilter, sendMessage } : {
139- segment : segmentWithNesting ;
143+ segment : SegmentWithNesting ;
140144 videoID : VideoID ;
141145 currentTime : number ;
142146 isVip : boolean ;
@@ -146,18 +150,32 @@ function SegmentListItem({ segment, videoID, currentTime, isVip, loopedChapter,
146150 sendMessage : ( request : Message ) => Promise < MessageResponse > ;
147151} ) {
148152 const [ voteMessage , setVoteMessage ] = React . useState < string | null > ( null ) ;
149- const [ hidden , setHidden ] = React . useState ( segment . hidden || SponsorHideType . Visible ) ;
153+ const [ hidden , setHidden ] = React . useState ( segment . hidden ?? SponsorHideType . Visible ) ; // undefined ?? undefined lol
150154 const [ isLooped , setIsLooped ] = React . useState ( loopedChapter === segment . UUID ) ;
151155
152- let extraInfo = "" ;
153- if ( segment . hidden === SponsorHideType . Downvoted ) {
154- // This one is downvoted
155- extraInfo = " (" + chrome . i18n . getMessage ( "hiddenDueToDownvote" ) + ")" ;
156- } else if ( segment . hidden === SponsorHideType . MinimumDuration ) {
157- // This one is too short
158- extraInfo = " (" + chrome . i18n . getMessage ( "hiddenDueToDuration" ) + ")" ;
159- } else if ( segment . hidden === SponsorHideType . Hidden ) {
160- extraInfo = " (" + chrome . i18n . getMessage ( "manuallyHidden" ) + ")" ;
156+ // Update internal state if the hidden property of the segment changes
157+ React . useEffect ( ( ) => {
158+ setHidden ( segment . hidden ?? SponsorHideType . Visible ) ;
159+ } , [ segment . hidden ] )
160+
161+ let extraInfo : string ;
162+ switch ( hidden ) {
163+ case SponsorHideType . Visible :
164+ extraInfo = "" ;
165+ break ;
166+ case SponsorHideType . Downvoted :
167+ extraInfo = " (" + chrome . i18n . getMessage ( "hiddenDueToDownvote" ) + ")" ;
168+ break ;
169+ case SponsorHideType . MinimumDuration :
170+ extraInfo = " (" + chrome . i18n . getMessage ( "hiddenDueToDuration" ) + ")" ;
171+ break ;
172+ case SponsorHideType . Hidden :
173+ extraInfo = " (" + chrome . i18n . getMessage ( "manuallyHidden" ) + ")" ;
174+ break ;
175+ default :
176+ // hidden satisfies never; // need to upgrade TS
177+ console . warn ( `[SB] Unhandled variant of SponsorHideType in SegmentListItem: ${ hidden } ` ) ;
178+ extraInfo = "" ;
161179 }
162180
163181 return (
@@ -279,7 +297,7 @@ function SegmentListItem({ segment, videoID, currentTime, isVip, loopedChapter,
279297 {
280298 ( segment . actionType === ActionType . Skip || segment . actionType === ActionType . Mute
281299 || segment . actionType === ActionType . Poi
282- && [ SponsorHideType . Visible , SponsorHideType . Hidden ] . includes ( segment . hidden ) ) &&
300+ && [ SponsorHideType . Visible , SponsorHideType . Hidden ] . includes ( hidden ) ) &&
283301 < img
284302 className = "voteButton"
285303 title = { chrome . i18n . getMessage ( "hideSegment" ) }
@@ -288,17 +306,11 @@ function SegmentListItem({ segment, videoID, currentTime, isVip, loopedChapter,
288306 const stopAnimation = AnimationUtils . applyLoadingAnimation ( e . currentTarget , 0.4 ) ;
289307 stopAnimation ( ) ;
290308
291- if ( segment . hidden === SponsorHideType . Hidden ) {
292- segment . hidden = SponsorHideType . Visible ;
293- setHidden ( SponsorHideType . Visible ) ;
294- } else {
295- segment . hidden = SponsorHideType . Hidden ;
296- setHidden ( SponsorHideType . Hidden ) ;
297- }
298-
309+ const newState = hidden === SponsorHideType . Hidden ? SponsorHideType . Visible : SponsorHideType . Hidden ;
310+ setHidden ( newState ) ;
299311 sendMessage ( {
300312 message : "hideSegment" ,
301- type : segment . hidden ,
313+ type : newState ,
302314 UUID : segment . UUID
303315 } ) ;
304316 } } />
@@ -343,7 +355,7 @@ function SegmentListItem({ segment, videoID, currentTime, isVip, loopedChapter,
343355}
344356
345357function InnerChapterList ( { chapters, videoID, currentTime, isVip, loopedChapter, tabFilter, sendMessage } : {
346- chapters : ( segmentWithNesting ) [ ] ;
358+ chapters : ( SegmentWithNesting ) [ ] ;
347359 videoID : VideoID ;
348360 currentTime : number ;
349361 isVip : boolean ;
0 commit comments