Skip to content

Commit

Permalink
Store GUI settings in TriblerConfig
Browse files Browse the repository at this point in the history
  • Loading branch information
egbertbouman committed Aug 20, 2024
1 parent 0b492b4 commit 56b822c
Show file tree
Hide file tree
Showing 17 changed files with 92 additions and 60 deletions.
11 changes: 9 additions & 2 deletions src/tribler/core/restapi/settings_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,16 @@ async def update_settings(self, request: web.Request) -> RESTResponse:

return RESTResponse({"modified": True})

def _recursive_merge_settings(self, existing: dict, updates: dict) -> None:
def _recursive_merge_settings(self, existing: dict, updates: dict, top: bool = True) -> None:
for key in existing:
# Ignore top-level ui entry
if top and key == "ui":
continue
value = updates.get(key, existing[key])
if isinstance(value, dict):
self._recursive_merge_settings(existing[key], value)
self._recursive_merge_settings(existing[key], value, False)
existing[key] = value

# Since the core doesn't need to be aware of the GUI settings, we just copy them.
if top and "ui" in updates:
existing["ui"].update(updates["ui"])
2 changes: 2 additions & 0 deletions src/tribler/tribler_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class ApiConfig(TypedDict):
https_enabled: bool
https_host: str
https_port: int
http_port_running: int
https_port_running: int


class ContentDiscoveryCommunityConfig(TypedDict):
Expand Down
2 changes: 1 addition & 1 deletion src/tribler/ui/src/components/add-torrent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export function AddTorrent() {
const files = Array.from(event.target.files as ArrayLike<File>);
event.target.value = '';

if (files.length === 1 && triblerService.getGuiSettings().ask_download_settings !== false) {
if (files.length === 1 && triblerService.guiSettings.ask_download_settings !== false) {
setSaveAsDialogOpen(true);
setTorrent(files[0]);
}
Expand Down
14 changes: 10 additions & 4 deletions src/tribler/ui/src/components/language-select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,24 @@ import { Button } from "./ui/button";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "./ui/dropdown-menu";
import { useTranslation } from "react-i18next";
import { triblerService } from "@/services/tribler.service";
import { useEffect } from "react";


const LanguageSelect = () => {
const { language, setLanguage } = useLanguage();
const { t, i18n } = useTranslation();

const changeLanguage = (lng: string) => {
useEffect(() => {
const lng = triblerService.guiSettings.lang ?? 'en_US';
setLanguage(lng);
i18n.changeLanguage(lng);
triblerService.setGuiSettings({
...triblerService.getGuiSettings(),
lang: lng
}, []);

const changeLanguage = async (lng: string) => {
setLanguage(lng);
i18n.changeLanguage(lng);
await triblerService.setSettings({
ui: { lang: lng }
});
};

Expand Down
2 changes: 1 addition & 1 deletion src/tribler/ui/src/config/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export const sideMenu: NavItemWithChildren[] = [
{
title: 'Debug',
icon: ExclamationTriangleIcon,
hide: () => triblerService.getGuiSettings().dev_mode !== true,
hide: () => triblerService.guiSettings.dev_mode !== true,
items: [
{
title: 'General',
Expand Down
2 changes: 1 addition & 1 deletion src/tribler/ui/src/contexts/LanguageContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface LanguageContextType {
const LanguageContext = createContext<LanguageContextType | undefined>(undefined);

export const LanguageProvider: React.FC<React.PropsWithChildren> = ({ children }) => {
const [language, setLanguage] = useState(triblerService.getGuiSettings().lang ?? 'en');
const [language, setLanguage] = useState(triblerService.guiSettings.lang ?? 'en_US');

return (
<LanguageContext.Provider value={{ language, setLanguage }}>
Expand Down
2 changes: 1 addition & 1 deletion src/tribler/ui/src/dialogs/SaveAs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ export default function SaveAs(props: SaveAsProps & JSX.IntrinsicAttributes & Di
}
}

if (props.open && props.onOpenChange && !triblerService.getGuiSettings().ask_download_settings) {
if (props.open && props.onOpenChange && triblerService.guiSettings.ask_download_settings === false) {
OnDownloadClicked();
return <></>;
}
Expand Down
2 changes: 1 addition & 1 deletion src/tribler/ui/src/i18n/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ i18n
.use(initReactI18next)
.init({
supportedLngs: ['en_US', 'es_ES', 'pt_BR', 'ru_RU', 'zh_CN'],
lng: triblerService.getGuiSettings().lang,
lng: triblerService.guiSettings.lang,
fallbackLng: 'en_US',
interpolation: {
escapeValue: false,
Expand Down
2 changes: 1 addition & 1 deletion src/tribler/ui/src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export function categoryIcon(name: category): string {
}

export function formatTimeAgo(ts: number) {
let locale = triblerService.getGuiSettings().lang ?? 'en-US';
let locale = triblerService.guiSettings.lang ?? 'en_US';
const timeAg = new TimeAgo(locale.slice(0, 2));
return timeAg.format(ts * 1000);
}
Expand Down
1 change: 1 addition & 0 deletions src/tribler/ui/src/models/settings.model.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export interface Settings {
},
state_dir: string;
memory_db: boolean;
ui: GuiSettings;
}

export interface GuiSettings {
Expand Down
5 changes: 4 additions & 1 deletion src/tribler/ui/src/pages/Settings/Anonymity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ export default function Anonimity() {
const { t } = useTranslation();
const [settings, setSettings] = useState<Settings>();

if (!settings) (async () => { setSettings(await triblerService.getSettings()) })();
if (!settings) {
(async () => { setSettings(await triblerService.getSettings()) })();
return;
}

return (
<div className="p-6 w-full">
Expand Down
5 changes: 4 additions & 1 deletion src/tribler/ui/src/pages/Settings/Bandwidth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ export default function Bandwith() {
const { t } = useTranslation();
const [settings, setSettings] = useState<Settings>();

if (!settings) (async () => { setSettings(await triblerService.getSettings()) })();
if (!settings) {
(async () => { setSettings(await triblerService.getSettings()) })();
return;
}

return (
<div className="p-6">
Expand Down
5 changes: 4 additions & 1 deletion src/tribler/ui/src/pages/Settings/Connection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ export default function Connection() {
const { t } = useTranslation();
const [settings, setSettings] = useState<Settings>();

if (!settings) (async () => { setSettings(await triblerService.getSettings()) })();
if (!settings) {
(async () => { setSettings(await triblerService.getSettings()) })();
return;
}

return (
<div className="px-6 w-full">
Expand Down
26 changes: 13 additions & 13 deletions src/tribler/ui/src/pages/Settings/Debugging.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Checkbox } from "@/components/ui/checkbox";
import { GuiSettings, Settings } from "@/models/settings.model";
import { Settings } from "@/models/settings.model";
import { triblerService } from "@/services/tribler.service";
import { useState } from "react";
import { useTranslation } from "react-i18next";
Expand All @@ -9,21 +9,25 @@ import SaveButton from "./SaveButton";
export default function Debugging() {
const { t } = useTranslation();
const [settings, setSettings] = useState<Settings>();
const [guiSettings, setGuiSettings] = useState<GuiSettings>();

if (!settings) (async () => { setSettings(await triblerService.getSettings()) })();
if (!guiSettings) setGuiSettings(triblerService.getGuiSettings());
if (!settings) {
(async () => { setSettings(await triblerService.getSettings()) })();
return;
}

return (
<div className="p-6">
<div className="flex items-center space-x-2 p-2">
<Checkbox
checked={guiSettings?.dev_mode === true}
checked={settings?.ui?.dev_mode === true}
onCheckedChange={(value) => {
if (guiSettings) {
setGuiSettings({
...guiSettings,
dev_mode: !!value
if (settings) {
setSettings({
...settings,
ui: {
...settings.ui,
dev_mode: !!value
}
})

}
Expand Down Expand Up @@ -58,12 +62,8 @@ export default function Debugging() {

<SaveButton
onClick={async () => {
const refresh = guiSettings?.dev_mode !== triblerService.getGuiSettings().dev_mode;
if (guiSettings)
triblerService.setGuiSettings(guiSettings);
if (settings)
await triblerService.setSettings(settings);
if (refresh)
window.location.reload();
}}
/>
Expand Down
38 changes: 23 additions & 15 deletions src/tribler/ui/src/pages/Settings/General.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { PathInput } from "@/components/path-input";
import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";
import { GuiSettings, Settings } from "@/models/settings.model";
import { Settings } from "@/models/settings.model";
import { triblerService } from "@/services/tribler.service";
import { useState } from "react";
import { useTranslation } from "react-i18next";
Expand All @@ -12,10 +12,11 @@ import { Input } from "@/components/ui/input";
export default function General() {
const { t } = useTranslation();
const [settings, setSettings] = useState<Settings>();
const [guiSettings, setGuiSettings] = useState<GuiSettings>();

if (!settings) (async () => { setSettings(await triblerService.getSettings()) })();
if (!guiSettings) setGuiSettings(triblerService.getGuiSettings());
if (!settings) {
(async () => { setSettings(await triblerService.getSettings()) })();
return;
}

return (
<div className="px-6 w-full">
Expand Down Expand Up @@ -70,12 +71,15 @@ export default function General() {
</div>
<div className="flex items-center space-x-2 py-2">
<Checkbox
checked={guiSettings?.ask_download_settings}
checked={settings?.ui?.ask_download_settings}
onCheckedChange={(value) => {
if (settings) {
setGuiSettings({
setSettings({
...settings,
ask_download_settings: !!value
ui: {
...settings?.ui,
ask_download_settings: !!value
}
});
}
}}
Expand Down Expand Up @@ -141,12 +145,15 @@ export default function General() {
<div className="pt-5 py-2 font-semibold">{t('FamilyFilter')}</div>
<div className="flex items-center space-x-2 py-2">
<Checkbox
checked={guiSettings?.family_filter}
checked={settings?.ui?.family_filter}
onCheckedChange={(value) => {
if (settings) {
setGuiSettings({
setSettings({
...settings,
family_filter: !!value
ui: {
...settings?.ui,
family_filter: !!value
}
});
}
}}
Expand All @@ -163,12 +170,15 @@ export default function General() {
<div className="pt-5 py-2 font-semibold">{t('Tags')}</div>
<div className="flex items-center space-x-2 py-2">
<Checkbox
checked={guiSettings?.disable_tags}
checked={settings?.ui?.disable_tags}
onCheckedChange={(value) => {
if (settings) {
setGuiSettings({
setSettings({
...settings,
disable_tags: !!value
ui: {
...settings?.ui,
disable_tags: !!value
}
});
}
}}
Expand All @@ -183,8 +193,6 @@ export default function General() {

<SaveButton
onClick={async () => {
if (guiSettings)
triblerService.setGuiSettings(guiSettings);
if (settings)
await triblerService.setSettings(settings);
}}
Expand Down
5 changes: 4 additions & 1 deletion src/tribler/ui/src/pages/Settings/Seeding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ export default function Seeding() {
const { t } = useTranslation();
const [settings, setSettings] = useState<Settings>();

if (!settings) (async () => { setSettings(await triblerService.getSettings()) })();
if (!settings) {
(async () => { setSettings(await triblerService.getSettings()) })();
return;
}

return (
<div className="p-6 w-full">
Expand Down
28 changes: 12 additions & 16 deletions src/tribler/ui/src/services/tribler.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,17 @@ export class TriblerService {
private http: AxiosInstance;
private baseURL = "/api";
private events: EventSource;
// Store a cached version of the GuiSettings to prevent from having to call the server every time we need them.
public guiSettings: GuiSettings = {};

constructor() {
this.http = axios.create({
baseURL: this.baseURL,
withCredentials: true,
});
this.events = new EventSource(this.baseURL + '/events', { withCredentials: true })
// Gets the GuiSettings
this.getSettings();
}

isOnline() {
Expand All @@ -26,11 +30,11 @@ export class TriblerService {

// Events

addEventListener(topic:string, listener: (event: MessageEvent) => void): void {
addEventListener(topic: string, listener: (event: MessageEvent) => void): void {
this.events.addEventListener(topic, listener);
}

removeEventListener(topic:string, listener: (event: MessageEvent) => void): void {
removeEventListener(topic: string, listener: (event: MessageEvent) => void): void {
this.events.removeEventListener(topic, listener);
}

Expand Down Expand Up @@ -127,7 +131,7 @@ export class TriblerService {
return (await this.http.get(`/metadata/torrents/popular?metadata_type=300&metadata_type=220&include_total=1&first=1&last=50&hide_xxx=${+hide_xxx}`)).data.results;
}

async getTorrentHealth(infohash: string): Promise<{infohash: string, num_seeders: number, num_leechers: number, last_tracker_check: number}> {
async getTorrentHealth(infohash: string): Promise<{ infohash: string, num_seeders: number, num_leechers: number, last_tracker_check: number }> {
return (await this.http.get(`/metadata/torrents/${infohash}/health`)).data;
}

Expand All @@ -146,22 +150,14 @@ export class TriblerService {
// Settings

async getSettings(): Promise<Settings> {
return (await this.http.get('/settings')).data.settings;
}

async setSettings(settings: Settings): Promise<boolean> {
return (await this.http.post('/settings', settings)).data.modified;
}

getGuiSettings(): GuiSettings {
const settings_json = localStorage.getItem("gui_settings") ?? '{"ask_download_settings": true}';
const settings: GuiSettings = JSON.parse(settings_json);
const settings = (await this.http.get('/settings')).data.settings;
this.guiSettings = {...settings?.ui, ...this.guiSettings};
return settings
}

setGuiSettings(settings: GuiSettings) {
const settings_json = JSON.stringify(settings);
localStorage.setItem("gui_settings", settings_json);
async setSettings(settings: Partial<Settings>): Promise<boolean> {
this.guiSettings = {...settings?.ui, ...this.guiSettings};
return (await this.http.post('/settings', settings)).data.modified;
}

async getLibtorrentSession(hops: number) {
Expand Down

0 comments on commit 56b822c

Please sign in to comment.