Compare commits

..

8 Commits

Author SHA1 Message Date
jeffvli 27dce55ca2 Add weblate notice 2023-10-30 19:53:31 -07:00
jeffvli 830f453642 Combine common and glossary keys 2023-10-28 15:37:19 -07:00
jeffvli 8f48824955 Add language settings and toggle 2023-10-28 04:05:10 -07:00
jeffvli fbc23d545c Add missing translations 2023-10-28 03:56:48 -07:00
jeffvli 15eb4a70aa Localize new hotkey settings 2023-10-27 18:28:57 -07:00
jeffvli 3a13301e23 Fix keys 2023-10-27 18:23:53 -07:00
jeffvli eb5ad541d9 Add initial translation keys 2023-10-27 18:23:53 -07:00
jeffvli 68df672953 Add updated i18n config and en locale 2023-10-27 18:22:58 -07:00
13 changed files with 99 additions and 88 deletions
@@ -37,10 +37,6 @@ jobs:
type=semver,pattern={{version}} type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}} type=semver,pattern={{major}}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v3
- name: Build and push Docker image - name: Build and push Docker image
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
with: with:
@@ -48,7 +44,3 @@ jobs:
push: true push: true
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
platforms: |
linux/amd64
linux/arm/v7
linux/arm64/v8
-8
View File
@@ -29,10 +29,6 @@ jobs:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: | tags: |
type=raw,value=latest,enable={{is_default_branch}} type=raw,value=latest,enable={{is_default_branch}}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v3
- name: Build and push Docker image - name: Build and push Docker image
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
with: with:
@@ -40,7 +36,3 @@ jobs:
push: true push: true
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
platforms: |
linux/amd64
linux/arm/v7
linux/arm64/v8
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "feishin", "name": "feishin",
"version": "0.5.0", "version": "0.4.1",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "feishin", "name": "feishin",
"version": "0.5.0", "version": "0.4.1",
"hasInstallScript": true, "hasInstallScript": true,
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
+1 -34
View File
@@ -2,7 +2,7 @@
"name": "feishin", "name": "feishin",
"productName": "Feishin", "productName": "Feishin",
"description": "Feishin music server", "description": "Feishin music server",
"version": "0.5.0", "version": "0.4.1",
"scripts": { "scripts": {
"build": "concurrently \"npm run build:main\" \"npm run build:renderer\" \"npm run build:remote\"", "build": "concurrently \"npm run build:main\" \"npm run build:renderer\" \"npm run build:remote\"",
"build:main": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.main.prod.ts", "build:main": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.main.prod.ts",
@@ -93,39 +93,6 @@
], ],
"icon": "assets/icons/icon.ico" "icon": "assets/icons/icon.ico"
}, },
"deb": {
"depends": [
"libgssapi_krb5.so.2",
"libavahi-common.so.3",
"libavahi-client.so.3",
"libkrb5.so.3",
"libkrb5support.so.0",
"libkeyutils.so.1",
"libcups.so.2"
]
},
"rpm": {
"depends": [
"libgssapi_krb5.so.2",
"libavahi-common.so.3",
"libavahi-client.so.3",
"libkrb5.so.3",
"libkrb5support.so.0",
"libkeyutils.so.1",
"libcups.so.2"
]
},
"freebsd": {
"depends": [
"libgssapi_krb5.so.2",
"libavahi-common.so.3",
"libavahi-client.so.3",
"libkrb5.so.3",
"libkrb5support.so.0",
"libkeyutils.so.1",
"libcups.so.2"
]
},
"linux": { "linux": {
"target": [ "target": [
"AppImage", "AppImage",
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "feishin", "name": "feishin",
"version": "0.5.0", "version": "0.4.1",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "feishin", "name": "feishin",
"version": "0.5.0", "version": "0.4.1",
"hasInstallScript": true, "hasInstallScript": true,
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "feishin", "name": "feishin",
"version": "0.5.0", "version": "0.4.1",
"description": "", "description": "",
"main": "./dist/main/main.js", "main": "./dist/main/main.js",
"author": { "author": {
+1 -2
View File
@@ -1,5 +1,5 @@
import { useCallback } from 'react'; import { useCallback } from 'react';
import { Group, Image, Text, Title } from '@mantine/core'; import { Group, Image, Rating, Text, Title } from '@mantine/core';
import { useInfo, useSend, useShowImage } from '/@/remote/store'; import { useInfo, useSend, useShowImage } from '/@/remote/store';
import { RemoteButton } from '/@/remote/components/buttons/remote-button'; import { RemoteButton } from '/@/remote/components/buttons/remote-button';
import formatDuration from 'format-duration'; import formatDuration from 'format-duration';
@@ -18,7 +18,6 @@ import {
import { PlayerRepeat, PlayerStatus } from '/@/renderer/types'; import { PlayerRepeat, PlayerStatus } from '/@/renderer/types';
import { WrapperSlider } from '/@/remote/components/wrapped-slider'; import { WrapperSlider } from '/@/remote/components/wrapped-slider';
import { Tooltip } from '/@/renderer/components/tooltip'; import { Tooltip } from '/@/renderer/components/tooltip';
import { Rating } from '/@/renderer/components';
export const RemoteContainer = () => { export const RemoteContainer = () => {
const { repeat, shuffle, song, status, volume } = useInfo(); const { repeat, shuffle, song, status, volume } = useInfo();
+18 -28
View File
@@ -1,8 +1,12 @@
/* eslint-disable jsx-a11y/no-static-element-interactions */ /* eslint-disable jsx-a11y/no-static-element-interactions */
import { useCallback } from 'react'; import { MouseEvent } from 'react';
import { Rating as MantineRating, RatingProps } from '@mantine/core'; import { Rating as MantineRating, RatingProps as MantineRatingProps } from '@mantine/core';
import debounce from 'lodash/debounce';
import styled from 'styled-components'; import styled from 'styled-components';
import { Tooltip } from '/@/renderer/components/tooltip';
interface RatingProps extends Omit<MantineRatingProps, 'onClick'> {
onClick: (e: MouseEvent<HTMLDivElement>, value: number | undefined) => void;
}
const StyledRating = styled(MantineRating)` const StyledRating = styled(MantineRating)`
& .mantine-Rating-symbolBody { & .mantine-Rating-symbolBody {
@@ -12,32 +16,18 @@ const StyledRating = styled(MantineRating)`
} }
`; `;
export const Rating = ({ onChange, ...props }: RatingProps) => { export const Rating = ({ onClick, ...props }: RatingProps) => {
const valueChange = useCallback( // const debouncedOnClick = debounce(onClick, 100);
(rating: number) => {
if (onChange) {
if (rating === props.value) {
onChange(0);
} else {
onChange(rating);
}
}
},
[onChange, props.value],
);
const debouncedOnChange = debounce(valueChange, 100);
return ( return (
<StyledRating <Tooltip
{...props} label="Double click to clear"
onChange={(e) => { openDelay={1000}
debouncedOnChange(e); >
}} <StyledRating
onClick={(e) => { {...props}
e.preventDefault(); onDoubleClick={(e) => onClick(e, props.value)}
e.stopPropagation(); />
}} </Tooltip>
/>
); );
}; };
@@ -1,4 +1,5 @@
/* eslint-disable import/no-cycle */ /* eslint-disable import/no-cycle */
import { MouseEvent } from 'react';
import type { ICellRendererParams } from '@ag-grid-community/core'; import type { ICellRendererParams } from '@ag-grid-community/core';
import { Rating } from '/@/renderer/components/rating'; import { Rating } from '/@/renderer/components/rating';
import { CellContainer } from '/@/renderer/components/virtual-table/cells/generic-cell'; import { CellContainer } from '/@/renderer/components/virtual-table/cells/generic-cell';
@@ -8,6 +9,8 @@ export const RatingCell = ({ value, node }: ICellRendererParams) => {
const updateRatingMutation = useSetRating({}); const updateRatingMutation = useSetRating({});
const handleUpdateRating = (rating: number) => { const handleUpdateRating = (rating: number) => {
if (!value) return;
updateRatingMutation.mutate( updateRatingMutation.mutate(
{ {
query: { query: {
@@ -24,12 +27,32 @@ export const RatingCell = ({ value, node }: ICellRendererParams) => {
); );
}; };
const handleClearRating = (e: MouseEvent<HTMLDivElement>) => {
e.preventDefault();
e.stopPropagation();
updateRatingMutation.mutate(
{
query: {
item: [value],
rating: 0,
},
serverId: value?.serverId,
},
{
onSuccess: () => {
node.setData({ ...node.data, userRating: 0 });
},
},
);
};
return ( return (
<CellContainer $position="center"> <CellContainer $position="center">
<Rating <Rating
size="xs" size="xs"
value={value?.userRating} value={value?.userRating}
onChange={handleUpdateRating} onChange={handleUpdateRating}
onClick={handleClearRating}
/> />
</CellContainer> </CellContainer>
); );
@@ -55,6 +55,18 @@ export const AlbumDetailHeader = forwardRef(
}); });
}; };
const handleClearRating = () => {
if (!detailQuery?.data || !detailQuery?.data.userRating) return;
updateRatingMutation.mutate({
query: {
item: [detailQuery.data],
rating: 0,
},
serverId: detailQuery.data.serverId,
});
};
const showRating = detailQuery?.data?.serverType === ServerType.NAVIDROME; const showRating = detailQuery?.data?.serverType === ServerType.NAVIDROME;
return ( return (
@@ -84,6 +96,7 @@ export const AlbumDetailHeader = forwardRef(
} }
value={detailQuery?.data?.userRating || 0} value={detailQuery?.data?.userRating || 0}
onChange={handleUpdateRating} onChange={handleUpdateRating}
onClick={handleClearRating}
/> />
</> </>
)} )}
@@ -1,4 +1,4 @@
import { forwardRef, Fragment, Ref } from 'react'; import { forwardRef, Fragment, Ref, MouseEvent } from 'react';
import { Group, Rating, Stack } from '@mantine/core'; import { Group, Rating, Stack } from '@mantine/core';
import { useParams } from 'react-router'; import { useParams } from 'react-router';
import { LibraryItem, ServerType } from '/@/renderer/api/types'; import { LibraryItem, ServerType } from '/@/renderer/api/types';
@@ -55,6 +55,21 @@ export const AlbumArtistDetailHeader = forwardRef(
}); });
}; };
const handleClearRating = (_e: MouseEvent<HTMLDivElement>, rating?: number) => {
if (!detailQuery?.data || !detailQuery?.data.userRating) return;
const isSameRatingAsPrevious = rating === detailQuery.data.userRating;
if (!isSameRatingAsPrevious) return;
updateRatingMutation.mutate({
query: {
item: [detailQuery.data],
rating: 0,
},
serverId: detailQuery.data.serverId,
});
};
const showRating = detailQuery?.data?.serverType === ServerType.NAVIDROME; const showRating = detailQuery?.data?.serverType === ServerType.NAVIDROME;
return ( return (
@@ -84,6 +99,7 @@ export const AlbumArtistDetailHeader = forwardRef(
} }
value={detailQuery?.data?.userRating || 0} value={detailQuery?.data?.userRating || 0}
onChange={handleUpdateRating} onChange={handleUpdateRating}
onClick={handleClearRating}
/> />
</> </>
)} )}
@@ -714,6 +714,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
<Rating <Rating
readOnly readOnly
value={0} value={0}
onClick={() => {}}
/> />
), ),
onClick: () => handleUpdateRating(0), onClick: () => handleUpdateRating(0),
@@ -724,6 +725,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
<Rating <Rating
readOnly readOnly
value={1} value={1}
onClick={() => {}}
/> />
), ),
onClick: () => handleUpdateRating(1), onClick: () => handleUpdateRating(1),
@@ -734,6 +736,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
<Rating <Rating
readOnly readOnly
value={2} value={2}
onClick={() => {}}
/> />
), ),
onClick: () => handleUpdateRating(2), onClick: () => handleUpdateRating(2),
@@ -744,6 +747,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
<Rating <Rating
readOnly readOnly
value={3} value={3}
onClick={() => {}}
/> />
), ),
onClick: () => handleUpdateRating(3), onClick: () => handleUpdateRating(3),
@@ -754,6 +758,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
<Rating <Rating
readOnly readOnly
value={4} value={4}
onClick={() => {}}
/> />
), ),
onClick: () => handleUpdateRating(4), onClick: () => handleUpdateRating(4),
@@ -764,6 +769,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
<Rating <Rating
readOnly readOnly
value={5} value={5}
onClick={() => {}}
/> />
), ),
onClick: () => handleUpdateRating(5), onClick: () => handleUpdateRating(5),
@@ -1,4 +1,4 @@
import { useEffect } from 'react'; import { MouseEvent, useEffect } from 'react';
import { Flex, Group } from '@mantine/core'; import { Flex, Group } from '@mantine/core';
import { useHotkeys, useMediaQuery } from '@mantine/hooks'; import { useHotkeys, useMediaQuery } from '@mantine/hooks';
import isElectron from 'is-electron'; import isElectron from 'is-electron';
@@ -84,6 +84,18 @@ export const RightControls = () => {
}); });
}; };
const handleClearRating = (_e: MouseEvent<HTMLDivElement> | null, rating?: number) => {
if (!currentSong || !rating) return;
updateRatingMutation.mutate({
query: {
item: [currentSong],
rating: 0,
},
serverId: currentSong?.serverId,
});
};
const handleRemoveFromFavorites = (song: QueueSong | undefined) => { const handleRemoveFromFavorites = (song: QueueSong | undefined) => {
if (!song?.id) return; if (!song?.id) return;
@@ -142,7 +154,7 @@ export const RightControls = () => {
bindings.favoritePreviousToggle.isGlobal ? '' : bindings.favoritePreviousToggle.hotkey, bindings.favoritePreviousToggle.isGlobal ? '' : bindings.favoritePreviousToggle.hotkey,
() => handleToggleFavorite(previousSong), () => handleToggleFavorite(previousSong),
], ],
[bindings.rate0.isGlobal ? '' : bindings.rate0.hotkey, () => handleUpdateRating(0)], [bindings.rate0.isGlobal ? '' : bindings.rate0.hotkey, () => handleClearRating(null, 0)],
[bindings.rate1.isGlobal ? '' : bindings.rate1.hotkey, () => handleUpdateRating(1)], [bindings.rate1.isGlobal ? '' : bindings.rate1.hotkey, () => handleUpdateRating(1)],
[bindings.rate2.isGlobal ? '' : bindings.rate2.hotkey, () => handleUpdateRating(2)], [bindings.rate2.isGlobal ? '' : bindings.rate2.hotkey, () => handleUpdateRating(2)],
[bindings.rate3.isGlobal ? '' : bindings.rate3.hotkey, () => handleUpdateRating(3)], [bindings.rate3.isGlobal ? '' : bindings.rate3.hotkey, () => handleUpdateRating(3)],
@@ -202,6 +214,7 @@ export const RightControls = () => {
size="sm" size="sm"
value={currentSong?.userRating || 0} value={currentSong?.userRating || 0}
onChange={handleUpdateRating} onChange={handleUpdateRating}
onClick={handleClearRating}
/> />
)} )}
</Group> </Group>