Skip to content

Commit

Permalink
fix: Game list sortable columns
Browse files Browse the repository at this point in the history
  • Loading branch information
colin969 committed Jul 30, 2024
1 parent cd03350 commit 01cbf9e
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 31 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "flashpoint-launcher",
"version": "13.0.2",
"version": "13.1.0",
"description": "A desktop application used to browse, manage and play games from Flashpoint Archive",
"main": "build/main/index.js",
"config": {
Expand Down
88 changes: 66 additions & 22 deletions src/renderer/components/GameListHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { WithPreferencesProps } from '@renderer/containers/withPreferences';
import { updatePreferencesData } from '@shared/preferences/util';
import { GameOrderBy } from 'flashpoint-launcher';
import { GameOrderBy, GameOrderDirection } from 'flashpoint-launcher';
import { useMemo } from 'react';
import { OpenIcon } from './OpenIcon';
import { useView } from '@renderer/hooks/search';
import { useDispatch } from 'react-redux';
import { searchActions } from '@renderer/store/search/slice';

export type GameListHeaderProps = WithPreferencesProps & {
showExtremeIcon: boolean;
Expand All @@ -11,37 +14,83 @@ export type GameListHeaderProps = WithPreferencesProps & {
// Header on top of the GameList. It contains the resizable columns that decide how wide each column is.
export function GameListHeader(props: GameListHeaderProps) {
const { gamesOrderBy, gamesOrder } = props.preferencesData;
const currentView = useView();
const dispatch = useDispatch();

const onToggleSort = (key: GameOrderBy) => {
if (currentView.orderBy === key) {
const newDirection = currentView.orderReverse === 'ASC' ? 'DESC' : 'ASC';
dispatch(searchActions.setOrderReverse({
view: currentView.id,
value: newDirection,
}));
} else {
dispatch(searchActions.setOrderBy({
view: currentView.id,
value: key,
}));
dispatch(searchActions.setOrderReverse({
view: currentView.id,
value: 'ASC',
}));
}
if (currentView.selectedPlaylist !== undefined && currentView.advancedFilter.playlistOrder) {
dispatch(searchActions.setAdvancedFilter({
view: currentView.id,
filter: {
...currentView.advancedFilter,
playlistOrder: false,
},
}));
}
};

const curOrderBy = (currentView.selectedPlaylist !== undefined && currentView.advancedFilter.playlistOrder) ?
undefined :
currentView.orderBy;

return useMemo(() => (
<div className='game-list-header'>
{ props.showExtremeIcon ? (
<Column modifier='icon' hideDivider={true} />
) : undefined}
<SortableColumn modifier='icon' hideDivider={true} orderBy='platform' preferencesData={props.preferencesData} />
<SortableColumn
modifier='icon'
hideDivider={true}
orderBy='platform'
onToggleSort={onToggleSort}
direction={currentView.orderReverse}
value={curOrderBy} />
<div className='game-list-header__right'>
<SortableColumn
title='Title'
modifier='title'
hideDivider={true}
orderBy='title'
preferencesData={props.preferencesData} />
onToggleSort={onToggleSort}
direction={currentView.orderReverse}
value={curOrderBy} />
<SortableColumn
title='Developer'
modifier='developer'
hideDivider={true}
orderBy='developer'
preferencesData={props.preferencesData} />
onToggleSort={onToggleSort}
direction={currentView.orderReverse}
value={curOrderBy} />
<SortableColumn
title='Publisher'
modifier='publisher'
hideDivider={true}
orderBy='publisher'
preferencesData={props.preferencesData} />
onToggleSort={onToggleSort}
direction={currentView.orderReverse}
value={curOrderBy} />
{/* <Column title='Tags' modifier='tagsStr' /> */}
</div>
<div className='game-list-header__scroll-fill' />
</div>
), [gamesOrderBy, gamesOrder]);
), [currentView.orderReverse, currentView.orderBy, currentView.selectedPlaylist, currentView.advancedFilter.playlistOrder]);
}

type ColumnProps = {
Expand All @@ -67,19 +116,25 @@ function Column(props: ColumnProps) {
);
}

type SortableColumnProps = ColumnProps & WithPreferencesProps & {
type SortableColumnProps = ColumnProps & {
/** GameOrderBy key */
orderBy: GameOrderBy;
/** Currently selected value */
value?: GameOrderBy;
/** Current selected direction */
direction: GameOrderDirection;
/** When toggled */
onToggleSort: (key: GameOrderBy) => void;
};

function SortableColumn(props: SortableColumnProps) {
const { orderBy, value, direction, onToggleSort } = props;
const className = 'game-list-header-column';
const { gamesOrderBy, gamesOrder } = props.preferencesData;
const active = gamesOrderBy === props.orderBy;
const active = orderBy === value;
const showDivider = !props.hideDivider;
// Render
return (
<div className={`${className} ${className}--${props.modifier} ${className}--sortable`} onClick={() => toggleSorting(props.orderBy)}>
<div className={`${className} ${className}--${props.modifier} ${className}--sortable`} onClick={() => onToggleSort(orderBy)}>
{ showDivider ? (
<div className='game-list-header-column__divider' />
) : undefined }
Expand All @@ -88,22 +143,11 @@ function SortableColumn(props: SortableColumnProps) {
{ active ? (
<div className='game-list-header-column__sort-icon-wrapper'>
<OpenIcon
icon={gamesOrder === 'ASC'? 'chevron-top' : 'chevron-bottom'}
icon={direction === 'DESC'? 'chevron-top' : 'chevron-bottom'}
className='game-list-header-column__sort-icon'/>
</div>
): undefined }
</div>
</div>
);

}

function toggleSorting(orderBy: GameOrderBy) {
const { gamesOrderBy, gamesOrder } = window.Shared.preferences.data;
const direction = gamesOrderBy === orderBy && gamesOrder === 'ASC'? 'DESC' : 'ASC';

updatePreferencesData({
gamesOrderBy: orderBy,
gamesOrder: direction
});
}
7 changes: 1 addition & 6 deletions src/renderer/store/search/slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,6 @@ const searchSlice = createSlice({
}
},
createViews(state: SearchState, { payload }: PayloadAction<SearchCreateViewsAction>) {
console.log(`Creating views for: ${payload}`);
const generalState = state.views[GENERAL_VIEW_ID];
// Clear existing views except general
state.views = {
Expand Down Expand Up @@ -398,7 +397,6 @@ const searchSlice = createSlice({
requestRange(state: SearchState, { payload }: PayloadAction<SearchRequestRange>) {
const view = state.views[payload.view];
const { start, count, searchId } = payload;
console.log(`Range requested - ${start} - len:${count}`);
if (view && view.data.searchId === searchId) { // Ignore outdated requests
// Iterate over requested page numbers
const end = start + count;
Expand All @@ -412,7 +410,7 @@ const searchSlice = createSlice({
offset: view.data.keyset[i-1],
page: i,
};
console.log(`requested page ${i}`);
console.log(`Requested page ${i}`);
// Fire and forget request, registered handler will properly handle response
window.Shared.back.send(BackIn.BROWSE_VIEW_PAGE, searchFilter);
}
Expand Down Expand Up @@ -531,7 +529,6 @@ const searchSlice = createSlice({
if (data.page !== undefined && data.games) {
if (data.page === 0 && data.games.length === 0) {
// No games in first page, must be empty results
console.log('no results');
view.data.total = 0;
} else {
const startIdx = VIEW_PAGE_SIZE * data.page;
Expand All @@ -543,8 +540,6 @@ const searchSlice = createSlice({
view.data.metaState = RequestState.RECEIVED;
}
}

console.log(`PERF - addData - ${Date.now() - startTime}ms`);
}
},
});
Expand Down
4 changes: 2 additions & 2 deletions static/window/styles/core.css
Original file line number Diff line number Diff line change
Expand Up @@ -3598,8 +3598,8 @@ body {

.searchable-select-dropdown-results {
overflow-y: auto;
height: 50vh;
width: 25vw;
height: 45vh;
width: 22vw;
}

.searchable-select-dropdown-item {
Expand Down

0 comments on commit 01cbf9e

Please sign in to comment.