Skip to content

Commit

Permalink
feat: new install panel with drag and drop functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
metebykl committed Oct 6, 2024
1 parent e9d8555 commit 38ea653
Show file tree
Hide file tree
Showing 22 changed files with 128 additions and 26 deletions.
Binary file modified .github/screenshot-01.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .github/screenshot-02.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .github/screenshot-03.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/screenshot-04.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,14 @@ AeroMod is a tool designed to efficiently manage Microsoft Flight Simulator mods

![](./.github/screenshot-02.png)

### Settings
### Install Mods

![](./.github/screenshot-03.png)

### Settings

![](./.github/screenshot-04.png)

## Features

- Enable/Disable mods.
Expand Down
22 changes: 15 additions & 7 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,13 +266,21 @@ func (a *App) GetModThumbnail(modName string) (string, error) {
return thumbnail, nil
}

func (a *App) InstallMod() (bool, error) {
archive, err := runtime.OpenFileDialog(a.ctx, runtime.OpenDialogOptions{
Title: "Choose Mod",
})
func (a *App) InstallMod(path string) (bool, error) {
var archive string

// open a file dialog if no path is specified
if path == "" {
var err error
archive, err = runtime.OpenFileDialog(a.ctx, runtime.OpenDialogOptions{
Title: "Choose Mod",
})

if err != nil {
return false, fmt.Errorf("failed to open directory dialog: %w", err)
if err != nil {
return false, fmt.Errorf("failed to open directory dialog: %w", err)
}
} else {
archive = path
}

if archive == "" {
Expand All @@ -286,7 +294,7 @@ func (a *App) InstallMod() (bool, error) {

archiveDest := strings.TrimSuffix(archive, ext)

err = utils.Unzip(archive, archiveDest)
err := utils.Unzip(archive, archiveDest)
if err != nil {
return false, err
}
Expand Down
2 changes: 1 addition & 1 deletion build/windows/installer/wails_tools.nsh
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
!define INFO_PRODUCTNAME "AeroMod"
!endif
!ifndef INFO_PRODUCTVERSION
!define INFO_PRODUCTVERSION "0.9.2"
!define INFO_PRODUCTVERSION "0.9.3"
!endif
!ifndef INFO_COPYRIGHT
!define INFO_COPYRIGHT "Built under GPL-3.0 license"
Expand Down
8 changes: 7 additions & 1 deletion frontend/src/components/app-bar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useEffect, useState } from "react";
import { MinusIcon, SquareIcon } from "lucide-react";
import { DownloadIcon, MinusIcon, SquareIcon } from "lucide-react";
import {
WindowIsMaximised,
WindowMinimise,
Expand All @@ -9,6 +9,7 @@ import {
import appIcon from "@/assets/images/icon.png";
import maximizeIconLight from "@/assets/icons/maximize-light.png";
import maximizeIconDark from "@/assets/icons/maximize-dark.png";
import InstallPanel from "./install-panel";

export default function AppBar() {
const [isMaximised, setIsMaximised] = useState<boolean>();
Expand Down Expand Up @@ -62,6 +63,11 @@ export default function AppBar() {
className="flex items-center"
style={{ "--wails-draggable": "no-drag" } as React.CSSProperties}
>
<InstallPanel>
<div className="mr-2 flex size-7 cursor-pointer items-center justify-center rounded-md transition hover:bg-accent">
<DownloadIcon className="size-4 text-muted-foreground" />
</div>
</InstallPanel>
<div
className="flex h-10 w-12 items-center justify-center transition hover:bg-accent"
onClick={() => handleAction("MINIMISE")}
Expand Down
69 changes: 69 additions & 0 deletions frontend/src/components/install-panel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { useEffect } from "react";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { DownloadIcon } from "lucide-react";
import { OnFileDrop, OnFileDropOff } from "@wailsjs/runtime/runtime";
import { QUERY_KEYS } from "@/constants";
import { installMod } from "@/lib/install";
import { cn } from "@/lib/utils";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";

interface InstallPanelProps {
children: React.ReactNode;
}

export default function InstallPanel({ children }: InstallPanelProps) {
const queryClient = useQueryClient();
const { mutate, isPending } = useMutation({
mutationFn: installMod,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.getAllMods] });
},
});

useEffect(() => {
OnFileDrop((_x, _y, paths) => {
if (paths.length < 1) return;

mutate(paths[0]);
}, true);

return () => {
OnFileDropOff();
};
}, []);

const preventDoubleClick = (e: React.MouseEvent<HTMLDivElement>) => {
if (e.detail === 2) {
e.stopPropagation();
}
};

return (
<Popover>
<PopoverTrigger asChild>{children}</PopoverTrigger>
<PopoverContent
onClick={preventDoubleClick}
className="flex w-[400px] flex-col gap-y-4"
>
<h1 className="font-bold">Install Mods</h1>
<div
onClick={() => mutate("")}
className={cn(
"relative flex aspect-video w-full cursor-pointer flex-col items-center justify-center gap-y-3 rounded border border-dashed data-[wails-drop-target-active]:bg-red-500",
isPending && "animate-pulse"
)}
style={{ "--wails-drop-target": "drop" } as React.CSSProperties}
>
<DownloadIcon className="size-8 text-muted-foreground" />
<p className="text-sm text-muted-foreground">
Install mods by dropping or clicking here.
</p>
</div>
</PopoverContent>
</Popover>
);
}
3 changes: 1 addition & 2 deletions frontend/src/components/mod-select.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useMemo, useState } from "react";
import { useState } from "react";
import { Check, ChevronsUpDown } from "lucide-react";
import { CommandList } from "cmdk";

Expand All @@ -16,7 +16,6 @@ import {
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { msfs } from "@wailsjs/go/models";

type ModSelectProps = {
mods?: string[];
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/setup-modal.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { useNavigate } from "react-router-dom";
import { useEffect, useState } from "react";
import { toast } from "sonner";
import { ArrowLeft, CheckCircle2, FolderOpen } from "lucide-react";
import {
CompleteSetup,
FindSimCommunityFolder,
OpenDirectoryDialog,
} from "@wailsjs/go/main/App";
import { ArrowLeft, CheckCircle2, FolderOpen } from "lucide-react";
import { Button } from "@/components/ui/button";

export default function SetupDialog() {
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { useLocation, Link } from "react-router-dom";
import { CheckCircleIcon, ListIcon, SettingsIcon } from "lucide-react";
import { BrowserOpenURL } from "@wailsjs/runtime/runtime";
import { Button } from "@/components/ui/button";
import { Hint } from "./hint";
import { cn } from "@/lib/utils";
import { GITHUB_URL } from "@/constants";
import { Button } from "@/components/ui/button";
import { Hint } from "./hint";

const routes = [
{
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
export const GITHUB_URL = "https://github.com/fly2z/aeromod";

export const QUERY_KEYS = {
getAllMods: "getAllMods",
getModNames: "getModNames",
};
4 changes: 2 additions & 2 deletions frontend/src/lib/install.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { toast } from "sonner";
import { InstallMod } from "@wailsjs/go/main/App";

export async function installMod() {
export async function installMod(path?: string) {
try {
const installed = await InstallMod();
const installed = await InstallMod(path || "");
if (!installed) return;

toast.success("Mod installed successfully!");
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ const queryClient = new QueryClient();
root.render(
<React.StrictMode>
<ThemeProvider defaultTheme="dark" storageKey="aeromod-theme">
<AppBar />
<QueryClientProvider client={queryClient}>
<AppBar />
<SettingsProvider>
<TooltipProvider>
<RouterProvider router={router} />
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/routes/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from "lucide-react";
import { GetAllMods } from "@wailsjs/go/main/App";
import { installMod } from "@/lib/install";
import { QUERY_KEYS } from "@/constants";

import {
DropdownMenu,
Expand All @@ -30,13 +31,13 @@ export default function HomePage() {
data: mods,
refetch,
} = useQuery({
queryKey: ["getAllMods"],
queryKey: [QUERY_KEYS.getAllMods],
queryFn: () => GetAllMods(),
retry: false,
});

const installMutation = useMutation({
mutationFn: installMod,
mutationFn: () => installMod(),
onSuccess: () => refetch(),
});

Expand Down
3 changes: 2 additions & 1 deletion frontend/src/routes/verify.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { toast } from "sonner";
import { CheckCircle2, CircleAlert } from "lucide-react";
import { useMutation, useQuery } from "@tanstack/react-query";
import { GetModNames, VerifyMod } from "@wailsjs/go/main/App";
import { QUERY_KEYS } from "@/constants";

import {
Tooltip,
Expand All @@ -17,7 +18,7 @@ export default function VerifyPage() {
const [selectedModName, setSelectedModName] = useState<string>();

const { data: mods } = useQuery({
queryKey: ["getModNames"],
queryKey: [QUERY_KEYS.getModNames],
queryFn: async () => GetModNames(),
});

Expand Down
2 changes: 1 addition & 1 deletion frontend/tsconfig.app.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@
}
},
"include": ["src"]
}
}
10 changes: 8 additions & 2 deletions frontend/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,11 @@
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}
],
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}
2 changes: 1 addition & 1 deletion frontend/tsconfig.node.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@
"noFallthroughCasesInSwitch": true
},
"include": ["vite.config.ts"]
}
}
3 changes: 3 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ func main() {
Bind: []interface{}{
app,
},
DragAndDrop: &options.DragAndDrop{
EnableFileDrop: true,
},
Windows: &windows.Options{
DisablePinchZoom: true,
EnableSwipeGestures: false,
Expand Down
2 changes: 1 addition & 1 deletion wails.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"info": {
"companyName": "AeroMod",
"productName": "AeroMod",
"productVersion": "0.9.2",
"productVersion": "0.9.3",
"copyright": "Built under GPL-3.0 license",
"comments": "External mod manager for MSFS"
}
Expand Down

0 comments on commit 38ea653

Please sign in to comment.