@@ -7,43 +7,79 @@ export interface FolderThumbData {
77 folderContentsType : FolderContentsType ;
88}
99
10+ enum CachedThumbnailType {
11+ Image = 'image' ,
12+ Icon = 'icon' ,
13+ }
14+
15+ interface CachedImage {
16+ type : CachedThumbnailType . Image ;
17+ url : string ;
18+ }
19+
20+ interface CachedIcon {
21+ type : CachedThumbnailType . Icon ;
22+ icon : FolderContentsType ;
23+ }
24+
25+ type CachedThumbnail = CachedImage | CachedIcon ;
26+
27+ function isCachedThumbnail ( entry : unknown ) : entry is CachedThumbnail {
28+ return (
29+ typeof entry === 'object' &&
30+ entry !== null &&
31+ 'type' in entry &&
32+ Object . values ( CachedThumbnailType ) . includes (
33+ ( entry as CachedImage | CachedIcon ) . type ,
34+ )
35+ ) ;
36+ }
37+
1038export class ThumbnailCache {
11- private cache : Map < number , [ string , string ] > ;
39+ // Stores `unknown` because the cache is hydrated from local storage,
40+ // which may contain entries in an old or otherwise unexpected format.
41+ private cache : Map < number , unknown > = new Map ( ) ;
1242 private readonly STORAGE_KEY : string = 'folderThumbnailCache' ;
1343
1444 constructor ( private storage : StorageService ) {
15- this . fetchCacheMapFromStorage ( ) ;
45+ this . refreshCacheFromStorage ( ) ;
1646 }
1747
1848 public saveThumbnail ( item : ItemVO , thumbs : FolderThumbData ) : void {
19- this . fetchCacheMapFromStorage ( ) ;
49+ this . refreshCacheFromStorage ( ) ;
2050 if ( thumbs . folderContentsType === FolderContentsType . NORMAL ) {
21- this . cache . set ( item . folder_linkId , [ thumbs . folderThumb , '' ] ) ;
51+ this . cache . set ( item . folder_linkId , {
52+ type : CachedThumbnailType . Image ,
53+ url : thumbs . folderThumb ,
54+ } ) ;
2255 } else {
23- this . cache . set ( item . folder_linkId , [ 'icon' , thumbs . folderContentsType ] ) ;
56+ this . cache . set ( item . folder_linkId , {
57+ type : CachedThumbnailType . Icon ,
58+ icon : thumbs . folderContentsType ,
59+ } ) ;
2460 }
25- this . saveMapToStorage ( ) ;
61+ this . commitCacheToStorage ( ) ;
2662 }
2763
2864 public getThumbnail ( item : ItemVO ) : FolderThumbData {
2965 if ( this . cache . has ( item . folder_linkId ) ) {
30- const thumbs = this . cache . get ( item . folder_linkId ) ;
31- if ( thumbs && Array . isArray ( thumbs ) && thumbs . length > 1 ) {
32- if ( thumbs [ 0 ] === 'icon' ) {
66+ const cacheEntry = this . cache . get ( item . folder_linkId ) ;
67+ if ( isCachedThumbnail ( cacheEntry ) ) {
68+ if ( cacheEntry . type === CachedThumbnailType . Image ) {
69+ return {
70+ folderThumb : cacheEntry . url ,
71+ folderContentsType : FolderContentsType . NORMAL ,
72+ } ;
73+ }
74+ if ( cacheEntry . type === CachedThumbnailType . Icon ) {
3375 return {
3476 folderThumb : '' ,
35- folderContentsType : thumbs [ 1 ] as FolderContentsType ,
77+ folderContentsType : cacheEntry . icon ,
3678 } ;
3779 }
38- // Cast to string just to be sure we actually have strings from our data structure.
39- return {
40- folderThumb : `${ thumbs [ 0 ] } ` ,
41- folderContentsType : FolderContentsType . NORMAL ,
42- } ;
43- } else {
44- this . cache . delete ( item . folder_linkId ) ;
45- this . saveMapToStorage ( ) ;
4680 }
81+ this . cache . delete ( item . folder_linkId ) ;
82+ this . commitCacheToStorage ( ) ;
4783 }
4884 return {
4985 folderThumb : '' ,
@@ -52,27 +88,34 @@ export class ThumbnailCache {
5288 }
5389
5490 public hasThumbnail ( item : ItemVO ) : boolean {
55- return this . cache . has ( item . folder_linkId ) ;
91+ if ( ! this . cache . has ( item . folder_linkId ) ) {
92+ return false ;
93+ }
94+ if ( isCachedThumbnail ( this . cache . get ( item . folder_linkId ) ) ) {
95+ return true ;
96+ }
97+ this . cache . delete ( item . folder_linkId ) ;
98+ this . commitCacheToStorage ( ) ;
99+ return false ;
56100 }
57101
58102 public invalidateFolder ( folderLinkId : number ) : void {
59103 if ( this . cache . has ( folderLinkId ) ) {
60104 this . cache . delete ( folderLinkId ) ;
61- this . saveMapToStorage ( ) ;
105+ this . commitCacheToStorage ( ) ;
62106 }
63107 }
64108
65- private fetchCacheMapFromStorage ( ) : void {
109+ private refreshCacheFromStorage ( ) : void {
66110 const cacheData = this . storage . session . get ( this . STORAGE_KEY ) ;
67111 if ( cacheData && Array . isArray ( cacheData ) ) {
68- this . cache = new Map < number , [ string , string ] > ( cacheData ) ;
112+ this . cache = new Map < number , unknown > ( cacheData ) ;
69113 } else {
70- this . cache = new Map < number , [ string , string ] > ( ) ;
71- this . saveMapToStorage ( ) ;
114+ this . cache = new Map < number , unknown > ( ) ;
72115 }
73116 }
74117
75- private saveMapToStorage ( ) : void {
118+ private commitCacheToStorage ( ) : void {
76119 this . storage . session . set (
77120 this . STORAGE_KEY ,
78121 Array . from ( this . cache . entries ( ) ) ,
0 commit comments