@@ -24,7 +24,7 @@ import {
2424} from "@/components/CharacterInfoCard" ;
2525import { usePlaylistStore } from "@/state/playlistStore" ;
2626import { SearchIcon , XIcon } from "lucide-react" ;
27- import { EventsOn } from "wailsjs/runtime/runtime" ;
27+ import { EventsOn , LogDebug } from "wailsjs/runtime/runtime" ;
2828import useCrossfadeNavigate from "@/hooks/useCrossfadeNavigate" ;
2929import { useDialogStore } from "@/components/appdialog" ;
3030import DB from "@/data/database" ;
@@ -45,7 +45,7 @@ const getElementPref = (game: number): GoPref<string[]> => {
4545 }
4646} ;
4747
48- const useMultiSelectState = ( cwmt : types . CharacterWithModsAndTags [ ] , refreshCharacters : ( ) => void ) => {
48+ const useMultiSelectState = ( cwmt : types . CharacterWithModsAndTags [ ] ) => {
4949
5050 const [ multiSelect , setMultiSelect ] = useState ( false )
5151 const [ selectedCardsUnfiltered , setSelectedCards ] = useState < number [ ] | undefined > ( undefined )
@@ -64,7 +64,7 @@ const useMultiSelectState = (cwmt: types.CharacterWithModsAndTags[], refreshChar
6464 c . characters . game
6565 )
6666 )
67- ) . finally ( refreshCharacters )
67+ )
6868 }
6969
7070 const multiSelectedCharacters = useMemo ( ( ) => {
@@ -175,14 +175,13 @@ interface FilterState {
175175}
176176
177177function GameScreen ( props : { dataApi : DataApi ; game : number } ) {
178+
178179 const navigate = useCrossfadeNavigate ( ) ;
179- const [ refreshTrigger , setRefreshTrigger ] = useState ( 0 ) ;
180180 const updates = usePlaylistStore ( useShallow ( ( state ) => state . updates ) ) ;
181181
182182 const setDialog = useDialogStore ( useShallow ( s => s . setDialog ) )
183183
184184 const running = useDownloadStore ( useShallow ( ( state ) => state . running ) ) ;
185- const refreshCharacters = ( ) => setRefreshTrigger ( ( prev ) => prev + 1 ) ;
186185
187186 const elements = useStateProducer < string [ ] > (
188187 [ ] ,
@@ -195,18 +194,23 @@ function GameScreen(props: { dataApi: DataApi; game: number }) {
195194 const characters = useStateProducer < types . CharacterWithModsAndTags [ ] > (
196195 [ ] ,
197196 async ( update , onDispose ) => {
198-
199- update ( await props . dataApi . charactersWithModsAndTags ( ) ) ;
197+ const unsubscribe = DB . onValueChangedListener ( [ 'characters' , 'mods' , 'tags' ] , ( ) => {
198+ props . dataApi . charactersWithModsAndTags ( ) . then ( update )
199+ } , true )
200200
201201 const cancel = EventsOn ( "sync" , ( { game } ) => {
202202 if ( game === props . game ) {
203203 props . dataApi . charactersWithModsAndTags ( ) . then ( update )
204204 }
205205 } )
206206
207- onDispose ( ( ) => cancel ( ) )
207+ onDispose ( ( ) => {
208+ LogDebug ( "disposing character state producer" )
209+ cancel ( )
210+ unsubscribe ( )
211+ } )
208212 } ,
209- [ props . dataApi , running , updates , refreshTrigger ]
213+ [ props . dataApi , running , updates ]
210214 ) ;
211215
212216 const filterState = useFilterState ( characters , props . game )
@@ -219,28 +223,28 @@ function GameScreen(props: { dataApi: DataApi; game: number }) {
219223 mutliSelectedIds,
220224 deleteCharacters,
221225 clearMultiSelected
222- } = useMultiSelectState ( characters , refreshCharacters )
226+ } = useMultiSelectState ( characters )
223227
224228 const handleUnselectAll = ( ) => {
225- DB . disableAllMods ( props . game ) . then ( refreshCharacters )
229+ DB . disableAllMods ( props . game )
226230 }
227231
228232 const handleEnableMod = ( id : number , enabled : boolean ) => {
229- DB . enableMod ( id , enabled ) . then ( refreshCharacters )
233+ DB . enableMod ( id , enabled )
230234 }
231235
232236 const handleDeleteMod = ( id : number ) => {
233- DB . deleteMod ( id ) . then ( refreshCharacters )
237+ DB . deleteMod ( id )
234238 }
235239
236240 const handleEnableTexture = ( id : number , enabled : boolean ) => {
237- DB . enableTexture ( id , enabled ) . then ( refreshCharacters )
241+ DB . enableTexture ( id , enabled )
238242 }
239243 const handleDeleteTexture = ( id : number ) => {
240- DB . deleteTexture ( id ) . then ( refreshCharacters )
244+ DB . deleteTexture ( id )
241245 }
242246 const handleSplitTexture = ( id : number ) => {
243- DB . splitTexture ( id ) . then ( refreshCharacters )
247+ DB . splitTexture ( id )
244248 }
245249
246250 return (
@@ -251,7 +255,7 @@ function GameScreen(props: { dataApi: DataApi; game: number }) {
251255 addTag = { ( ) => setDialog ( {
252256 type : "add_tag_multi" ,
253257 selectedChars : multiSelectedCharacters . map ( ( it ) => it . characters ) ,
254- refresh : refreshCharacters ,
258+ refresh : ( ) => { } ,
255259 game : props . game
256260 } ) }
257261 clearMultiSelected = { clearMultiSelected }
@@ -263,7 +267,7 @@ function GameScreen(props: { dataApi: DataApi; game: number }) {
263267 < GameActionsTopBar
264268 unselectAll = { handleUnselectAll }
265269 elements = { elements }
266- addCharacter = { ( ) => setDialog ( { type : "add_character" , game : props . game , elements : elements , refresh : refreshCharacters } ) }
270+ addCharacter = { ( ) => setDialog ( { type : "add_character" , game : props . game , elements : elements , refresh : ( ) => { } } ) }
267271 importMod = { ( ) => navigate ( "/import" , {
268272 state : { game : props . game }
269273 } ) }
@@ -273,7 +277,6 @@ function GameScreen(props: { dataApi: DataApi; game: number }) {
273277 </ div >
274278 < FloatingActionButtons
275279 dataApi = { props . dataApi }
276- refreshCharacters = { refreshCharacters }
277280 />
278281 < div className = "columns-1 sm:columns-2 lg:columns-3 gap-4 space-y-4 mb-16 mx-2" >
279282 { filterState . filteredCharacters . map ( ( c ) => (
@@ -288,10 +291,10 @@ function GameScreen(props: { dataApi: DataApi; game: number }) {
288291 cmt = { c }
289292 modDropdownMenu = { ( mwt ) => (
290293 < ModActionsDropDown
291- addTag = { ( ) => setDialog ( { type : "add_tag" , mod : mwt . mod , refresh : refreshCharacters } ) }
294+ addTag = { ( ) => setDialog ( { type : "add_tag" , mod : mwt . mod , refresh : ( ) => { } } ) }
292295 onEnable = { ( ) => handleEnableMod ( mwt . mod . id , ! mwt . mod . enabled ) }
293296 onDelete = { ( ) => handleDeleteMod ( mwt . mod . id ) }
294- onRename = { ( ) => setDialog ( { type : "rename_mod" , id : mwt . mod . id , refresh : refreshCharacters } ) }
297+ onRename = { ( ) => setDialog ( { type : "rename_mod" , id : mwt . mod . id , refresh : ( ) => { } } ) }
295298 onView = { ( ) => {
296299 if ( mwt . mod . gbId !== 0 ) {
297300 navigate ( `/mods/${ mwt . mod . gbId } ` ) ;
@@ -305,7 +308,7 @@ function GameScreen(props: { dataApi: DataApi; game: number }) {
305308 onEnable = { ( ) => handleEnableTexture ( t . id , ! t . enabled ) }
306309 onDelete = { ( ) => handleDeleteTexture ( t . id ) }
307310 onSplit = { ( ) => handleSplitTexture ( t . id ) }
308- onRename = { ( ) => setDialog ( { type : "rename_texture" , id : t . id , refresh : refreshCharacters } ) }
311+ onRename = { ( ) => setDialog ( { type : "rename_texture" , id : t . id , refresh : ( ) => { } } ) }
309312 onView = { ( ) => {
310313 if ( t . gbId !== 0 ) {
311314 navigate ( `/mods/${ t . gbId } ` ) ;
@@ -395,11 +398,9 @@ function MultiSelectTopBar(
395398}
396399
397400function FloatingActionButtons ( {
398- dataApi,
399- refreshCharacters,
401+ dataApi
400402} : {
401- dataApi : DataApi ;
402- refreshCharacters : ( ) => void ;
403+ dataApi : DataApi
403404} ) {
404405
405406 const {
@@ -410,7 +411,7 @@ function FloatingActionButtons({
410411 const {
411412 syncing,
412413 sync,
413- } = useSync ( dataApi , refreshCharacters )
414+ } = useSync ( dataApi )
414415
415416 return (
416417 < div className = "fixed bottom-4 -translate-y-1 end-6 flex flex-row z-10" >
0 commit comments