@@ -21,7 +21,18 @@ import {
21
21
} from '@freik/core-utils' ;
22
22
import { useId } from '@uifabric/react-hooks' ;
23
23
import { useEffect , useState } from 'react' ;
24
+ import { CallbackInterface , useRecoilCallback , useRecoilValue } from 'recoil' ;
24
25
import { SetMediaInfo } from '../../ipc' ;
26
+ import {
27
+ ImageFromClipboard ,
28
+ ShowOpenDialog ,
29
+ UploadFileForAlbum ,
30
+ UploadFileForSong ,
31
+ UploadImageForAlbum ,
32
+ UploadImageForSong ,
33
+ } from '../../MyWindow' ;
34
+ import { albumCoverUrlState , picCacheAvoiderState } from '../../Recoil/Local' ;
35
+ import { getAlbumKeyForSongKeyState } from '../../Recoil/ReadOnly' ;
25
36
import { onRejected } from '../../Tools' ;
26
37
27
38
const log = MakeLogger ( 'MetadataEditor' , true ) ;
@@ -148,6 +159,67 @@ export function MetadataEditor(props: MetadataProps): JSX.Element {
148
159
}
149
160
} ;
150
161
162
+ const uploadImage = async (
163
+ cbInterface : CallbackInterface ,
164
+ uploadSong : ( sk : SongKey ) => Promise < void > ,
165
+ uploadAlbum : ( ak : AlbumKey ) => Promise < void > ,
166
+ ) => {
167
+ // Easy: one song:
168
+ if ( props . forSong !== undefined ) {
169
+ await uploadSong ( props . forSong ) ;
170
+ const albumKey = await cbInterface . snapshot . getPromise (
171
+ getAlbumKeyForSongKeyState ( props . forSong ) ,
172
+ ) ;
173
+ setTimeout (
174
+ ( ) => cbInterface . set ( picCacheAvoiderState ( albumKey ) , ( p ) => p + 1 ) ,
175
+ 250 ,
176
+ ) ;
177
+ } else {
178
+ // Messy: Multiple songs
179
+ const albumsSet : Set < AlbumKey > = new Set ( ) ;
180
+ for ( const song of props . forSongs ! ) {
181
+ const albumKey = await cbInterface . snapshot . getPromise (
182
+ getAlbumKeyForSongKeyState ( song ) ,
183
+ ) ;
184
+ if ( albumsSet . has ( albumKey ) ) {
185
+ continue ;
186
+ }
187
+ albumsSet . add ( albumKey ) ;
188
+ await uploadAlbum ( albumKey ) ;
189
+ // This bonks the URL so it will be reloaded after we've uploaded the image
190
+ setTimeout (
191
+ ( ) => cbInterface . set ( picCacheAvoiderState ( albumKey ) , ( p ) => p + 1 ) ,
192
+ 250 ,
193
+ ) ;
194
+ }
195
+ }
196
+ } ;
197
+
198
+ const onImageFromClipboard = useRecoilCallback ( ( cbInterface ) => async ( ) => {
199
+ const img = ImageFromClipboard ( ) ;
200
+ if ( img !== undefined ) {
201
+ await uploadImage (
202
+ cbInterface ,
203
+ async ( sk : SongKey ) => await UploadImageForSong ( sk , img ) ,
204
+ async ( ak : AlbumKey ) => await UploadImageForAlbum ( ak , img ) ,
205
+ ) ;
206
+ }
207
+ } ) ;
208
+ const onSelectFile = useRecoilCallback ( ( cbInterface ) => async ( ) => {
209
+ const selected = ShowOpenDialog ( {
210
+ title : 'Select Cover Art image' ,
211
+ properties : [ 'openFile' ] ,
212
+ filters : [ { name : 'Images' , extensions : [ 'jpg' , 'jpeg' , 'png' ] } ] ,
213
+ } ) ;
214
+ if ( selected !== undefined ) {
215
+ await uploadImage (
216
+ cbInterface ,
217
+ async ( sk : SongKey ) => await UploadFileForSong ( sk , selected [ 0 ] ) ,
218
+ async ( ak : AlbumKey ) => await UploadFileForAlbum ( ak , selected [ 0 ] ) ,
219
+ ) ;
220
+ }
221
+ } ) ;
222
+ const coverUrl = useRecoilValue ( albumCoverUrlState ( props . albumId || '___' ) ) ;
151
223
// Nothing selected: EMPTY!
152
224
if ( ! isSingle && ! isMultiple ) {
153
225
return < Text > Not Single and not Multiple (This is a bug!)</ Text > ;
@@ -267,10 +339,16 @@ export function MetadataEditor(props: MetadataProps): JSX.Element {
267
339
</ Stack >
268
340
< Image
269
341
alt = "Album Cover"
270
- src = { `pic://album/ ${ props . albumId ? props . albumId : '____' } ` }
342
+ src = { coverUrl }
271
343
imageFit = { ImageFit . centerContain }
272
344
height = { 350 }
273
345
/>
346
+ < br />
347
+ < Stack horizontal horizontalAlign = "center" >
348
+ < DefaultButton text = "Choose File..." onClick = { onSelectFile } />
349
+
350
+ < DefaultButton text = "From Clipboard" onClick = { onImageFromClipboard } />
351
+ </ Stack >
274
352
</ >
275
353
) ;
276
354
}
0 commit comments