Compare commits
35 Commits
fix/dumpTa
...
v0.0.11
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b8e2ae8cf | ||
|
|
3450f39381 | ||
|
|
854887056e | ||
|
|
292e2de2dd | ||
|
|
3cda3a74b8 | ||
|
|
32215e5c03 | ||
|
|
fd4917ca7f | ||
|
|
c3d6c69d9d | ||
|
|
0774814912 | ||
|
|
20b695b1b3 | ||
|
|
e0a3b34c22 | ||
|
|
ed2a93a82f | ||
|
|
14ecde0c71 | ||
|
|
dd91dea7b1 | ||
|
|
a6ace8e234 | ||
|
|
68ee7016d1 | ||
|
|
46e70400b6 | ||
|
|
4a37528500 | ||
|
|
b36954d0a9 | ||
|
|
932ebd3b44 | ||
|
|
e18ddda81a | ||
|
|
ef592e0cf4 | ||
|
|
de5444fa04 | ||
|
|
2cf0cfa347 | ||
|
|
2f694ff0f7 | ||
|
|
3eef0397fa | ||
|
|
e8c08a18a7 | ||
|
|
5f61646cdf | ||
|
|
0f5bb3eaf1 | ||
|
|
a44e14398d | ||
|
|
592d99f645 | ||
|
|
bc4579b9f0 | ||
|
|
789e10eac4 | ||
|
|
066364e962 | ||
|
|
17955b452e |
24
.github/ISSUE_TEMPLATE/something-broken-in-poe2.md
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
name: Something Broken in PoE2
|
||||||
|
about: Use this for things that worked in PoE 1 and do not in PoE 2
|
||||||
|
title: "[PoE2]"
|
||||||
|
labels: bug
|
||||||
|
assignees: Kvan7
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the problem**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem. This is very helpful for comparing the PoE1 vs 2 problems
|
||||||
10
.github/workflows/main.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
|||||||
needs: renderer
|
needs: renderer
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [windows-2019, ubuntu-20.04, macos-12]
|
os: [windows-2019] # ubuntu-20.04, macos-14 is a missing runner
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -43,11 +43,11 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: renderer-dist
|
name: renderer-dist
|
||||||
path: ./renderer/dist
|
path: ./renderer/dist
|
||||||
- run: yarn --frozen-lockfile
|
- run: npm ci
|
||||||
working-directory: ./main
|
working-directory: ./main
|
||||||
- run: yarn build
|
- run: npm run build
|
||||||
working-directory: ./main
|
working-directory: ./main
|
||||||
- run: yarn package -p onTagOrDraft
|
- run: npm run package "--" -p onTagOrDraft
|
||||||
working-directory: ./main
|
working-directory: ./main
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -59,4 +59,4 @@ jobs:
|
|||||||
run: cat ./main/dist/latest-linux.yml
|
run: cat ./main/dist/latest-linux.yml
|
||||||
- name: Hash
|
- name: Hash
|
||||||
if: ${{ startsWith(matrix.os, 'macos') }}
|
if: ${{ startsWith(matrix.os, 'macos') }}
|
||||||
run: cat ./main/dist/latest-mac.yml
|
run: cat ./main/dist/latest-mac.yml
|
||||||
@@ -11,32 +11,32 @@ Note that these 2 both depend on each other, and one cannot run without the othe
|
|||||||
|
|
||||||
The most up-to-date instructions can always be derived from CI:
|
The most up-to-date instructions can always be derived from CI:
|
||||||
|
|
||||||
[.github/workflows/main.yml](https://github.com/SnosMe/awakened-poe-trade/blob/master/.github/workflows/main.yml)
|
[.github/workflows/main.yml](https://github.com/Kvan7/exiled-exchange-2/blob/master/.github/workflows/main.yml)
|
||||||
|
|
||||||
Here's what that looks like as of 2023-12-03.
|
Here's what that looks like as of 2023-12-03.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
cd renderer
|
cd renderer
|
||||||
yarn install
|
npm install
|
||||||
yarn make-index-files
|
npm run make-index-files
|
||||||
yarn dev
|
npm run dev
|
||||||
|
|
||||||
# In a second shell
|
# In a second shell
|
||||||
cd main
|
cd main
|
||||||
yarn install
|
npm install
|
||||||
yarn dev
|
npm run dev
|
||||||
```
|
```
|
||||||
|
|
||||||
# How to build
|
# How to build
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
cd renderer
|
cd renderer
|
||||||
yarn install
|
npm install
|
||||||
yarn make-index-files
|
npm run make-index-files
|
||||||
yarn build
|
npm run build
|
||||||
|
|
||||||
cd ../main
|
cd ../main
|
||||||
yarn build
|
npm run build
|
||||||
# We want to sign with a distribution certificate to ensure other users can
|
# We want to sign with a distribution certificate to ensure other users can
|
||||||
# install without errors
|
# install without errors
|
||||||
CSC_NAME="Certificate name in Keychain" yarn package
|
CSC_NAME="Certificate name in Keychain" yarn package
|
||||||
|
|||||||
26
README.md
@@ -1,16 +1,27 @@
|
|||||||
#  Awakened PoE Trade
|
#  Exiled Exchange 2
|
||||||
|
|
||||||
[](https://somsubhra.github.io/github-release-stats/?username=SnosMe&repository=awakened-poe-trade)
|
## Moving from POE1/Awakened PoE Trade
|
||||||
[](https://patreon.com/awakened_poe_trade)
|
|
||||||
[](https://github.com/SnosMe/awakened-poe-trade/issues/22)
|
|
||||||
|
|
||||||
|
1. Download latest release from [releases](https://github.com/Kvan7/exiled-exchange-2/releases)
|
||||||
|
- Currently only Windows is supported
|
||||||
|
- Only available as pre-release right now
|
||||||
|
2. Run installer
|
||||||
|
3. Run Exiled Exchange 2
|
||||||
|
4. Launch PoE2 to generate correct files
|
||||||
|
5. Copy `apt-data` from `%APPDATA%\awakened-poe-trade` to `%APPDATA%\exiled-exchange-2` to copy your previous settings
|
||||||
|
- Resulting directory structure should look like this:
|
||||||
|
- `%APPDATA%\exiled-exchange-2\apt-data\`
|
||||||
|
- `config.json`
|
||||||
|
6. Restart Exiled Exchange 2
|
||||||
|
|
||||||
➡ [Download for Windows & Linux](https://snosme.github.io/awakened-poe-trade/download) ⬅
|
#### Updating from 0.0.1 -> 0.0.10
|
||||||
|
|
||||||
|
Follow same steps as tranfering from PoE1, instead of copying from `%APPDATA%\awakened-poe-trade` to `%APPDATA%\exiled-exchange-2` instead copy from `%APPDATA%\awakened-poe2-trade` or `%APPDATA%\awakened-poe2-trade2` to `%APPDATA%\exiled-exchange-2`. After copying files feel free to run the uninstaller for `awakened-poe2-trade` to remove old executables, or delete `%APPDATA%\awakened-poe2-trade` and `Local\Programs\awakened-poe2-trade`
|
||||||
|
|
||||||
## Tool showcase
|
## Tool showcase
|
||||||
|
|
||||||
| Gem | Rare | Unique | Currency |
|
| Gem | Rare | Unique | Currency |
|
||||||
|-----|------|--------|----------|
|
| ------------------------------------ | ------------------------------------ | ------------------------------------ | ------------------------------------ |
|
||||||
|  |  |  |  |
|
|  |  |  |  |
|
||||||
|
|
||||||
### Development
|
### Development
|
||||||
@@ -19,6 +30,7 @@ See [DEVELOPING.md](./DEVELOPING.md)
|
|||||||
|
|
||||||
### Acknowledgments
|
### Acknowledgments
|
||||||
|
|
||||||
|
- [awakened-poe-trade](https://github.com/SnosMe/awakened-poe-trade)
|
||||||
- [libuiohook](https://github.com/kwhat/libuiohook)
|
- [libuiohook](https://github.com/kwhat/libuiohook)
|
||||||
- [RePoE](https://github.com/brather1ng/RePoE)
|
- [RePoE](https://github.com/brather1ng/RePoE)
|
||||||
- [poeprices.info](https://www.poeprices.info/)
|
- [poeprices.info](https://www.poeprices.info/)
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
{
|
|
||||||
"folders": [
|
|
||||||
{
|
|
||||||
"name": "renderer",
|
|
||||||
"path": "renderer"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "main",
|
|
||||||
"path": "main"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "docs",
|
|
||||||
"path": "docs"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "root",
|
|
||||||
"path": "."
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"settings": {
|
|
||||||
"files.exclude": {
|
|
||||||
"main/": true,
|
|
||||||
"renderer/": true,
|
|
||||||
"docs/": true,
|
|
||||||
"dist/": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import { defineConfig } from 'vitepress'
|
import { defineConfig } from 'vitepress'
|
||||||
|
|
||||||
const BASE = '/awakened-poe-trade/'
|
const BASE = '/exiled-exchange-2/'
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
title: 'Awakened PoE Trade',
|
title: 'Exiled Exchange 2',
|
||||||
description: 'App for price-checking items in Path of Exile',
|
description: 'App for price-checking items in Path of Exile 2',
|
||||||
base: BASE,
|
base: BASE,
|
||||||
mpa: true,
|
mpa: true,
|
||||||
head: [
|
head: [
|
||||||
@@ -22,14 +22,9 @@ export default defineConfig({
|
|||||||
// logo: 'TODO', https://github.com/vuejs/vitepress/issues/1401
|
// logo: 'TODO', https://github.com/vuejs/vitepress/issues/1401
|
||||||
appVersion: '3.25.101',
|
appVersion: '3.25.101',
|
||||||
github: {
|
github: {
|
||||||
releasesUrl: 'https://github.com/SnosMe/awakened-poe-trade/releases'
|
releasesUrl: 'https://github.com/Kvan7/exiled-exchange-2/releases'
|
||||||
},
|
},
|
||||||
socialLinks: [
|
socialLinks: [
|
||||||
{
|
|
||||||
text: 'Discord',
|
|
||||||
color: '#7289DA',
|
|
||||||
link: 'https://github.com/SnosMe/awakened-poe-trade/issues/22'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
text: 'Patreon',
|
text: 'Patreon',
|
||||||
color: '#FF424D',
|
color: '#FF424D',
|
||||||
@@ -38,7 +33,7 @@ export default defineConfig({
|
|||||||
{
|
{
|
||||||
text: 'GitHub',
|
text: 'GitHub',
|
||||||
color: '#181717',
|
color: '#181717',
|
||||||
link: 'https://github.com/SnosMe/awakened-poe-trade'
|
link: 'https://github.com/Kvan7/exiled-exchange-2'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
sidebar: [
|
sidebar: [
|
||||||
|
|||||||
@@ -8,15 +8,15 @@ import { useData } from 'vitepress'
|
|||||||
const { theme } = useData()
|
const { theme } = useData()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
You can download Awakened Poe Trade here. Any other mirrors are not known
|
You can download Exalted Poe Trade here. Any other mirrors are not known
|
||||||
to the developer, downloading from them may be unsafe.
|
to the developer, downloading from them may be unsafe.
|
||||||
|
|
||||||
| Download link | Automatic updates | Startup time |
|
| Download link | Automatic updates | Startup time |
|
||||||
|---------------|-------------------|--------------|
|
| -------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- | ------------ |
|
||||||
| <a :href="`${theme.github.releasesUrl}/download/v${theme.appVersion}/Awakened-PoE-Trade-Setup-${theme.appVersion}.exe`">Windows 10+ (installer)</a> | ✔ | Fast |
|
| <a :href="`${theme.github.releasesUrl}/download/v${theme.appVersion}/exiled-exchange-2-Setup-${theme.appVersion}.exe`">Windows 10+ (installer)</a> | ✔ | Fast |
|
||||||
| <a :href="`${theme.github.releasesUrl}/download/v${theme.appVersion}/Awakened-PoE-Trade-${theme.appVersion}.exe`">Windows 10+ (portable)</a> | ❌ | Slower |
|
| <a :href="`${theme.github.releasesUrl}/download/v${theme.appVersion}/exiled-exchange-2-${theme.appVersion}.exe`">Windows 10+ (portable)</a> | ❌ | Slower |
|
||||||
| <a :href="`${theme.github.releasesUrl}/download/v${theme.appVersion}/Awakened-PoE-Trade-${theme.appVersion}.AppImage`">Linux (AppImage)</a> | ✔ | n/a |
|
| <a :href="`${theme.github.releasesUrl}/download/v${theme.appVersion}/exiled-exchange-2-${theme.appVersion}.AppImage`">Linux (AppImage)</a> | ✔ | n/a |
|
||||||
| <a :href="`${theme.github.releasesUrl}/download/v${theme.appVersion}/Awakened-PoE-Trade-${theme.appVersion}-universal.dmg`">macOS (dmg)</a> | ❌ | n/a |
|
| <a :href="`${theme.github.releasesUrl}/download/v${theme.appVersion}/exiled-exchange-2-${theme.appVersion}-universal.dmg`">macOS (dmg)</a> | ❌ | n/a |
|
||||||
|
|
||||||
Latest version is <span class="bg-gray-100 border rounded px-1">{{ theme.appVersion }}</span>
|
Latest version is <span class="bg-gray-100 border rounded px-1">{{ theme.appVersion }}</span>
|
||||||
|
|
||||||
@@ -36,6 +36,6 @@ warnings on Windows and [macOS](https://support.apple.com/en-us/HT202491#openany
|
|||||||
|
|
||||||
No Administrator rights required, but\
|
No Administrator rights required, but\
|
||||||
⚠ **If you run PoE client as Admin, OS security boundaries take effect.
|
⚠ **If you run PoE client as Admin, OS security boundaries take effect.
|
||||||
In order for Awakened PoE Trade to have access to the PoE window, it must be started with Administrator rights.**
|
In order for Exiled Exchange 2 to have access to the PoE window, it must be started with Administrator rights.**
|
||||||
|
|
||||||
❌ **Not compatible with "GeForce Now" or any other cloud gaming service that do not forward clipboard data.**
|
❌ **Not compatible with "GeForce Now" or any other cloud gaming service that do not forward clipboard data.**
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ title: FAQ
|
|||||||
|
|
||||||
- **Where can I change settings, league?**
|
- **Where can I change settings, league?**
|
||||||
|
|
||||||
Open Path of Exile and press overlay key `Shift + Space`. Click on the button with cog icon there.
|
Open Path of Exile 2 and press overlay key `Shift + Space`. Click on the button with cog icon there.
|
||||||

|

|
||||||
|
|
||||||
- **Where can I find the logs?**
|
- **Where can I find the logs?**
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ title: Common issues
|
|||||||
If Awakened works for you with DirectX11/12 renderer,
|
If Awakened works for you with DirectX11/12 renderer,
|
||||||
then problem is old Vulkan drivers for sure.
|
then problem is old Vulkan drivers for sure.
|
||||||
|
|
||||||
4. Delete `%appdata%\awakened-poe-trade`
|
4. Delete `%appdata%\exiled-exchange-2`
|
||||||
|
|
||||||
If needed, backup `apt-data` folder with your configuration inside.
|
If needed, backup `apt-data` folder with your configuration inside.
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ title: Common issues
|
|||||||
|
|
||||||
Launch them later one at a time to identify **conflict**.
|
Launch them later one at a time to identify **conflict**.
|
||||||
|
|
||||||
6. Restart Awakened PoE Trade.
|
6. Restart Exiled Exchange 2.
|
||||||
|
|
||||||
*(don't forget to quit first, otherwise launching second instance will do nothing).*
|
*(don't forget to quit first, otherwise launching second instance will do nothing).*
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ title: Quick Start
|
|||||||
|
|
||||||
#### First of all, how does it work? {:style="margin-top: 0;"}
|
#### First of all, how does it work? {:style="margin-top: 0;"}
|
||||||
|
|
||||||
When you press `Ctrl + C` Path of Exile copies the item's text (under cursor, if any) to the clipboard.
|
When you press `Ctrl + C` Path of Exile 2 copies the item's text (under cursor, if any) to the clipboard.
|
||||||
All that remains is to parse text in Awakened PoE Trade and show to you in a fancy way.
|
All that remains is to parse text in Exiled Exchange 2 and show to you in a fancy way.
|
||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
|
|
||||||
|
|||||||
33
exiled-exchange-2.code-workspace
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"name": "renderer",
|
||||||
|
"path": "renderer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "main",
|
||||||
|
"path": "main"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "docs",
|
||||||
|
"path": "docs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "root",
|
||||||
|
"path": "."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"settings": {
|
||||||
|
"files.exclude": {
|
||||||
|
"main/": true,
|
||||||
|
"renderer/": true,
|
||||||
|
"docs/": true,
|
||||||
|
"dist/": true
|
||||||
|
},
|
||||||
|
"editor.tabSize": 2,
|
||||||
|
"editor.insertSpaces": true,
|
||||||
|
"conventionalCommits.scopes": [
|
||||||
|
"Update to 2"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 841 KiB After Width: | Height: | Size: 712 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 791 B After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 280 KiB After Width: | Height: | Size: 240 KiB |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 353 KiB After Width: | Height: | Size: 66 KiB |
BIN
main/build/icons/icon.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
@@ -1,6 +1,6 @@
|
|||||||
publish:
|
publish:
|
||||||
- "github"
|
- "github"
|
||||||
productName: "Awakened PoE Trade"
|
productName: "Exiled Exchange 2"
|
||||||
npmRebuild: false
|
npmRebuild: false
|
||||||
files:
|
files:
|
||||||
- "package.json"
|
- "package.json"
|
||||||
|
|||||||
5656
main/package-lock.json
generated
Normal file
@@ -1,18 +1,20 @@
|
|||||||
{
|
{
|
||||||
"name": "awakened-poe-trade",
|
"name": "exiled-exchange-2",
|
||||||
"version": "3.25.102",
|
"version": "0.0.11",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "node build/script.mjs",
|
"dev": "node build/script.mjs",
|
||||||
"build": "tsc --noEmit && node build/script.mjs --prod",
|
"build": "tsc --noEmit && node build/script.mjs --prod",
|
||||||
"package": "electron-builder build"
|
"package": "electron-builder build",
|
||||||
|
"lint": "eslint src",
|
||||||
|
"fix": "eslint src --fix"
|
||||||
},
|
},
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Alexander Drozdov"
|
"name": "Garrett Parker"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/SnosMe/awakened-poe-trade.git"
|
"url": "https://github.com/Kvan7/exiled-exchange-2.git"
|
||||||
},
|
},
|
||||||
"main": "dist/main.js",
|
"main": "dist/main.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -25,15 +27,12 @@
|
|||||||
"@types/ws": "^8.5.3",
|
"@types/ws": "^8.5.3",
|
||||||
"@wokwi/bmp-ts": "^3.0.0",
|
"@wokwi/bmp-ts": "^3.0.0",
|
||||||
"comlink": "^4.3.1",
|
"comlink": "^4.3.1",
|
||||||
"electron": "31.3.1",
|
"electron": "33.2.1",
|
||||||
"electron-builder": "24.13.3",
|
"electron-builder": "25.1.8",
|
||||||
"electron-updater": "^6.1.0",
|
"electron-updater": "^6.3.0",
|
||||||
"esbuild": "^0.23.0",
|
"esbuild": "^0.24.0",
|
||||||
"ini": "^4.0.0",
|
"ini": "^5.0.0",
|
||||||
"typescript": "5.5.x",
|
"typescript": "5.6.x",
|
||||||
"ws": "^8.16.0"
|
"ws": "^8.16.0"
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=16"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,70 +1,70 @@
|
|||||||
import path from 'path'
|
import path from "path";
|
||||||
import { app, Tray, Menu, shell, nativeImage, dialog } from 'electron'
|
import { app, Tray, Menu, shell, nativeImage, dialog } from "electron";
|
||||||
import type { ServerEvents } from './server'
|
import type { ServerEvents } from "./server";
|
||||||
|
|
||||||
export class AppTray {
|
export class AppTray {
|
||||||
public overlayKey = 'Shift + Space'
|
public overlayKey = "Shift + Space";
|
||||||
private tray: Tray
|
private tray: Tray;
|
||||||
serverPort = 0
|
serverPort = 0;
|
||||||
|
|
||||||
constructor (server: ServerEvents) {
|
constructor(server: ServerEvents) {
|
||||||
let trayImage = nativeImage.createFromPath(
|
let trayImage = nativeImage.createFromPath(
|
||||||
path.join(
|
path.join(
|
||||||
__dirname,
|
__dirname,
|
||||||
process.env.STATIC!,
|
process.env.STATIC!,
|
||||||
process.platform === "win32" ? "icon.ico" : "icon.png"
|
process.platform === "win32" ? "icon.ico" : "icon.png"
|
||||||
)
|
)
|
||||||
)
|
);
|
||||||
|
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === "darwin") {
|
||||||
// Mac image size needs to be smaller, or else it looks huge. Size
|
// Mac image size needs to be smaller, or else it looks huge. Size
|
||||||
// guideline is from https://iconhandbook.co.uk/reference/chart/osx/
|
// guideline is from https://iconhandbook.co.uk/reference/chart/osx/
|
||||||
trayImage = trayImage.resize({ width: 22, height: 22 })
|
trayImage = trayImage.resize({ width: 22, height: 22 });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tray = new Tray(trayImage)
|
this.tray = new Tray(trayImage);
|
||||||
this.tray.setToolTip(`Awakened PoE Trade v${app.getVersion()}`)
|
this.tray.setToolTip(`Exiled Exchange 2 v${app.getVersion()}`);
|
||||||
this.rebuildMenu()
|
this.rebuildMenu();
|
||||||
|
|
||||||
server.onEventAnyClient('CLIENT->MAIN::user-action', ({ action }) => {
|
server.onEventAnyClient("CLIENT->MAIN::user-action", ({ action }) => {
|
||||||
if (action === 'quit') {
|
if (action === "quit") {
|
||||||
app.quit()
|
app.quit();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
rebuildMenu () {
|
rebuildMenu() {
|
||||||
const contextMenu = Menu.buildFromTemplate([
|
const contextMenu = Menu.buildFromTemplate([
|
||||||
{
|
{
|
||||||
label: 'Settings/League',
|
label: "Settings/League",
|
||||||
click: () => {
|
click: () => {
|
||||||
dialog.showMessageBox({
|
dialog.showMessageBox({
|
||||||
title: 'Settings',
|
title: "Settings",
|
||||||
message: `Open Path of Exile and press "${this.overlayKey}". Click on the button with cog icon there.`
|
message: `Open Path of Exile 2 and press "${this.overlayKey}". Click on the button with cog icon there.`,
|
||||||
})
|
});
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Open in Browser',
|
label: "Open in Browser",
|
||||||
click: () => {
|
click: () => {
|
||||||
shell.openExternal(`http://localhost:${this.serverPort}`)
|
shell.openExternal(`http://localhost:${this.serverPort}`);
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{ type: 'separator' },
|
{ type: "separator" },
|
||||||
{
|
{
|
||||||
label: 'Open config folder',
|
label: "Open config folder",
|
||||||
click: () => {
|
click: () => {
|
||||||
shell.openPath(path.join(app.getPath('userData'), 'apt-data'))
|
shell.openPath(path.join(app.getPath("userData"), "apt-data"));
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Quit',
|
label: "Quit",
|
||||||
click: () => {
|
click: () => {
|
||||||
app.quit()
|
app.quit();
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
])
|
]);
|
||||||
|
|
||||||
this.tray.setContextMenu(contextMenu)
|
this.tray.setContextMenu(contextMenu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,100 +1,131 @@
|
|||||||
import fs from 'fs/promises'
|
import fs from "fs/promises";
|
||||||
import path from 'path'
|
import path from "path";
|
||||||
import ini from 'ini'
|
import ini from "ini";
|
||||||
import { app } from 'electron'
|
import { app } from "electron";
|
||||||
import { hotkeyToString, CodeToKey } from '../../../ipc/KeyToCode'
|
import { hotkeyToString, CodeToKey } from "../../../ipc/KeyToCode";
|
||||||
import { guessFileLocation } from './utils'
|
import { guessFileLocation } from "./utils";
|
||||||
import type { Logger } from '../RemoteLogger'
|
import type { Logger } from "../RemoteLogger";
|
||||||
import type { ServerEvents } from '../server'
|
import type { ServerEvents } from "../server";
|
||||||
|
|
||||||
const POSSIBLE_PATH =
|
const POSSIBLE_PATH =
|
||||||
(process.platform === 'win32') ? [
|
process.platform === "win32"
|
||||||
path.join(app.getPath('documents'), 'My Games\\Path of Exile\\production_Config.ini')
|
? [
|
||||||
] : (process.platform === 'linux') ? [
|
path.join(
|
||||||
path.join(app.getPath('documents'), 'My Games/Path of Exile/production_Config.ini'),
|
app.getPath("documents"),
|
||||||
path.join(app.getPath('home'), '.local/share/Steam/steamapps/compatdata/238960/pfx/drive_c/users/steamuser/Documents/My Games/Path of Exile/production_Config.ini')
|
"My Games\\Path of Exile 2\\poe2_production_Config.ini"
|
||||||
] : (process.platform === 'darwin') ? [
|
),
|
||||||
path.join(app.getPath('appData'), 'Path of Exile/Preferences/production_Config.ini')
|
]
|
||||||
] : []
|
: process.platform === "linux"
|
||||||
|
? [
|
||||||
|
path.join(
|
||||||
|
app.getPath("documents"),
|
||||||
|
"My Games/Path of Exile 2/poe2_production_Config.ini"
|
||||||
|
),
|
||||||
|
path.join(
|
||||||
|
app.getPath("home"),
|
||||||
|
".local/share/Steam/steamapps/compatdata/238960/pfx/drive_c/users/steamuser/Documents/My Games/Path of Exile 2/poe2_production_Config.ini"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
: process.platform === "darwin"
|
||||||
|
? [
|
||||||
|
path.join(
|
||||||
|
app.getPath("appData"),
|
||||||
|
"Path of Exile 2/Preferences/poe2_production_Config.ini"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
: [];
|
||||||
|
|
||||||
export class GameConfig {
|
export class GameConfig {
|
||||||
private _wantedPath: string | null = null
|
private _wantedPath: string | null = null;
|
||||||
private _actualPath: string | null = null
|
private _actualPath: string | null = null;
|
||||||
get actualPath () { return this._actualPath }
|
get actualPath() {
|
||||||
|
return this._actualPath;
|
||||||
|
}
|
||||||
|
|
||||||
private _showModsKey: string | null = null
|
private _showModsKey: string | null = null;
|
||||||
get showModsKeyNullable () { return this._showModsKey }
|
get showModsKeyNullable() {
|
||||||
get showModsKey () { return this._showModsKey ?? 'Alt' }
|
return this._showModsKey;
|
||||||
|
}
|
||||||
|
get showModsKey() {
|
||||||
|
return this._showModsKey ?? "Alt";
|
||||||
|
}
|
||||||
|
|
||||||
constructor (
|
constructor(private server: ServerEvents, private logger: Logger) {}
|
||||||
private server: ServerEvents,
|
|
||||||
private logger: Logger
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async readConfig (filePath: string) {
|
async readConfig(filePath: string) {
|
||||||
if (this._wantedPath !== filePath) {
|
if (this._wantedPath !== filePath) {
|
||||||
this._wantedPath = filePath
|
this._wantedPath = filePath;
|
||||||
this._actualPath = null
|
this._actualPath = null;
|
||||||
} else {
|
} else {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!filePath.length) {
|
if (!filePath.length) {
|
||||||
const guessedPath = await guessFileLocation(POSSIBLE_PATH)
|
const guessedPath = await guessFileLocation(POSSIBLE_PATH);
|
||||||
if (guessedPath != null) {
|
if (guessedPath != null) {
|
||||||
filePath = guessedPath
|
filePath = guessedPath;
|
||||||
} else {
|
} else {
|
||||||
this.logger.write('error [GameConfig] Failed to find game configuration file in the default location.')
|
this.logger.write(
|
||||||
return
|
"error [GameConfig] Failed to find game configuration file in the default location."
|
||||||
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let contents = await fs.readFile(filePath, { encoding: 'utf-8', flag: 'r' })
|
let contents = await fs.readFile(filePath, {
|
||||||
contents = contents.trimStart() // remove BOM
|
encoding: "utf-8",
|
||||||
const parsed = ini.parse(contents)
|
flag: "r",
|
||||||
|
});
|
||||||
|
contents = contents.trimStart(); // remove BOM
|
||||||
|
const parsed = ini.parse(contents);
|
||||||
|
|
||||||
this._showModsKey = this.parseConfigHotkey(
|
this._showModsKey = this.parseConfigHotkey(
|
||||||
parsed['ACTION_KEYS']?.['show_advanced_item_descriptions'])
|
parsed["ACTION_KEYS"]?.["show_advanced_item_descriptions"]
|
||||||
|
);
|
||||||
|
|
||||||
this._actualPath = filePath
|
this._actualPath = filePath;
|
||||||
} catch {
|
} catch {
|
||||||
this.logger.write('error [GameConfig] Failed to read game configuration file.')
|
this.logger.write(
|
||||||
|
"error [GameConfig] Failed to read game configuration file."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseConfigHotkey (cfgKey?: string): string | null {
|
private parseConfigHotkey(cfgKey?: string): string | null {
|
||||||
if (!cfgKey) return null
|
if (!cfgKey) return null;
|
||||||
|
|
||||||
const [keyMain, keyMod] = cfgKey.split(' ')
|
const [keyMain, keyMod] = cfgKey.split(" ");
|
||||||
|
|
||||||
let key1: string
|
let key1: string;
|
||||||
if (CodeToKey[keyMain]) {
|
if (CodeToKey[keyMain]) {
|
||||||
key1 = CodeToKey[keyMain]
|
key1 = CodeToKey[keyMain];
|
||||||
} else {
|
} else {
|
||||||
this.logger.write(`error [GameConfig] Failed to read key: ${cfgKey}.`)
|
this.logger.write(`error [GameConfig] Failed to read key: ${cfgKey}.`);
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let key2: string | undefined
|
let key2: string | undefined;
|
||||||
if (keyMod) {
|
if (keyMod) {
|
||||||
if (keyMod === '1') {
|
if (keyMod === "1") {
|
||||||
key2 = 'Shift'
|
key2 = "Shift";
|
||||||
} else if (keyMod === '2') {
|
} else if (keyMod === "2") {
|
||||||
key2 = 'Ctrl'
|
key2 = "Ctrl";
|
||||||
} else if (keyMod === '3') {
|
} else if (keyMod === "3") {
|
||||||
key2 = 'Alt'
|
key2 = "Alt";
|
||||||
} else {
|
} else {
|
||||||
this.logger.write(`error [GameConfig] Failed to read modifier key: ${cfgKey}.`)
|
this.logger.write(
|
||||||
return null
|
`error [GameConfig] Failed to read modifier key: ${cfgKey}.`
|
||||||
|
);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return hotkeyToString(
|
return hotkeyToString(
|
||||||
[key1],
|
[key1],
|
||||||
key2 === 'Ctrl',
|
key2 === "Ctrl",
|
||||||
key2 === 'Shift',
|
key2 === "Shift",
|
||||||
key2 === 'Alt'
|
key2 === "Alt"
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,101 +1,118 @@
|
|||||||
import { promises as fs, watchFile, unwatchFile } from 'fs'
|
import { promises as fs, watchFile, unwatchFile } from "fs";
|
||||||
import path from 'path'
|
import path from "path";
|
||||||
import { app } from 'electron'
|
import { app } from "electron";
|
||||||
import { guessFileLocation } from './utils'
|
import { guessFileLocation } from "./utils";
|
||||||
import { ServerEvents } from '../server'
|
import { ServerEvents } from "../server";
|
||||||
import { Logger } from '../RemoteLogger'
|
import { Logger } from "../RemoteLogger";
|
||||||
|
|
||||||
const POSSIBLE_PATH =
|
const POSSIBLE_PATH =
|
||||||
(process.platform === 'win32') ? [
|
process.platform === "win32"
|
||||||
'C:\\Program Files (x86)\\Grinding Gear Games\\Path of Exile\\logs\\Client.txt',
|
? [
|
||||||
'C:\\Program Files (x86)\\Steam\\steamapps\\common\\Path of Exile\\logs\\Client.txt'
|
"C:\\Program Files (x86)\\Grinding Gear Games\\Path of Exile 2\\logs\\Client.txt",
|
||||||
] : (process.platform === 'linux') ? [
|
"C:\\Program Files (x86)\\Steam\\steamapps\\common\\Path of Exile 2\\logs\\Client.txt",
|
||||||
path.join(app.getPath('home'), '.wine/drive_c/Program Files (x86)/Grinding Gear Games/Path of Exile/logs/Client.txt'),
|
]
|
||||||
path.join(app.getPath('home'), '.local/share/Steam/steamapps/common/Path of Exile/logs/Client.txt')
|
: process.platform === "linux"
|
||||||
] : (process.platform === 'darwin') ? [
|
? [
|
||||||
path.join(app.getPath('home'), 'Library/Caches/com.GGG.PathOfExile/Logs/Client.txt')
|
path.join(
|
||||||
] : []
|
app.getPath("home"),
|
||||||
|
".wine/drive_c/Program Files (x86)/Grinding Gear Games/Path of Exile 2/logs/Client.txt"
|
||||||
|
),
|
||||||
|
path.join(
|
||||||
|
app.getPath("home"),
|
||||||
|
".local/share/Steam/steamapps/common/Path of Exile 2/logs/Client.txt"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
: process.platform === "darwin"
|
||||||
|
? [
|
||||||
|
path.join(
|
||||||
|
app.getPath("home"),
|
||||||
|
"Library/Caches/com.GGG.PathOfExile/Logs/Client.txt"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
: [];
|
||||||
|
|
||||||
export class GameLogWatcher {
|
export class GameLogWatcher {
|
||||||
private _wantedPath: string | null = null
|
private _wantedPath: string | null = null;
|
||||||
get actualPath () { return this._state?.path ?? null }
|
get actualPath() {
|
||||||
|
return this._state?.path ?? null;
|
||||||
|
}
|
||||||
private _state: {
|
private _state: {
|
||||||
offset: number
|
offset: number;
|
||||||
path: string
|
path: string;
|
||||||
file: fs.FileHandle
|
file: fs.FileHandle;
|
||||||
isReading: boolean
|
isReading: boolean;
|
||||||
readBuff: Buffer
|
readBuff: Buffer;
|
||||||
} | null = null
|
} | null = null;
|
||||||
|
|
||||||
constructor (
|
constructor(private server: ServerEvents, private logger: Logger) {}
|
||||||
private server: ServerEvents,
|
|
||||||
private logger: Logger,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async restart (logFile: string) {
|
async restart(logFile: string) {
|
||||||
if (this._wantedPath !== logFile) {
|
if (this._wantedPath !== logFile) {
|
||||||
this._wantedPath = logFile
|
this._wantedPath = logFile;
|
||||||
if (this._state) {
|
if (this._state) {
|
||||||
unwatchFile(this._state.path)
|
unwatchFile(this._state.path);
|
||||||
await this._state.file.close()
|
await this._state.file.close();
|
||||||
this._state = null
|
this._state = null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!logFile.length) {
|
if (!logFile.length) {
|
||||||
const guessedPath = await guessFileLocation(POSSIBLE_PATH)
|
const guessedPath = await guessFileLocation(POSSIBLE_PATH);
|
||||||
if (guessedPath != null) {
|
if (guessedPath != null) {
|
||||||
logFile = guessedPath
|
logFile = guessedPath;
|
||||||
} else {
|
} else {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const file = await fs.open(logFile, 'r')
|
const file = await fs.open(logFile, "r");
|
||||||
const stats = await file.stat()
|
const stats = await file.stat();
|
||||||
watchFile(logFile, { interval: 450 }, this.handleFileChange.bind(this))
|
watchFile(logFile, { interval: 450 }, this.handleFileChange.bind(this));
|
||||||
this._state = {
|
this._state = {
|
||||||
path: logFile,
|
path: logFile,
|
||||||
file: file,
|
file: file,
|
||||||
offset: stats.size,
|
offset: stats.size,
|
||||||
isReading: false,
|
isReading: false,
|
||||||
readBuff: Buffer.allocUnsafe(64 * 1024),
|
readBuff: Buffer.allocUnsafe(64 * 1024),
|
||||||
}
|
};
|
||||||
} catch {
|
} catch {
|
||||||
this.logger.write('error [GameLogWatcher] Failed to watch file.')
|
this.logger.write("error [GameLogWatcher] Failed to watch file.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleFileChange () {
|
private handleFileChange() {
|
||||||
if (this._state && !this._state.isReading) {
|
if (this._state && !this._state.isReading) {
|
||||||
this._state.isReading = true
|
this._state.isReading = true;
|
||||||
this.readToEOF()
|
this.readToEOF();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async readToEOF () {
|
private async readToEOF() {
|
||||||
if (!this._state) return
|
if (!this._state) return;
|
||||||
|
|
||||||
const { file, readBuff, offset } = this._state
|
const { file, readBuff, offset } = this._state;
|
||||||
const { bytesRead } = await file.read(readBuff, 0, readBuff.length, offset)
|
const { bytesRead } = await file.read(readBuff, 0, readBuff.length, offset);
|
||||||
|
|
||||||
if (bytesRead) {
|
if (bytesRead) {
|
||||||
const str = readBuff.toString('utf8', 0, bytesRead)
|
const str = readBuff.toString("utf8", 0, bytesRead);
|
||||||
const lines = str.split('\n').map(line => line.trim()).filter(line => line.length)
|
const lines = str
|
||||||
this.server.sendEventTo('broadcast', {
|
.split("\n")
|
||||||
name: 'MAIN->CLIENT::game-log',
|
.map((line) => line.trim())
|
||||||
payload: { lines }
|
.filter((line) => line.length);
|
||||||
})
|
this.server.sendEventTo("broadcast", {
|
||||||
|
name: "MAIN->CLIENT::game-log",
|
||||||
|
payload: { lines },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytesRead) {
|
if (bytesRead) {
|
||||||
this._state.offset += bytesRead
|
this._state.offset += bytesRead;
|
||||||
this.readToEOF()
|
this.readToEOF();
|
||||||
} else {
|
} else {
|
||||||
this._state.isReading = false
|
this._state.isReading = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export class HttpProxy {
|
|||||||
|
|
||||||
const official = PROXY_HOSTS.find(entry => entry.host === host)?.official
|
const official = PROXY_HOSTS.find(entry => entry.host === host)?.official
|
||||||
if (official === undefined) return req.destroy()
|
if (official === undefined) return req.destroy()
|
||||||
|
|
||||||
for (const key in req.headers) {
|
for (const key in req.headers) {
|
||||||
if (key.startsWith('sec-') || key === 'host' || key === 'origin' || key === 'content-length') {
|
if (key.startsWith('sec-') || key === 'host' || key === 'origin' || key === 'content-length') {
|
||||||
delete req.headers[key]
|
delete req.headers[key]
|
||||||
@@ -40,7 +40,6 @@ export class HttpProxy {
|
|||||||
})
|
})
|
||||||
proxyReq.addListener('response', (proxyRes) => {
|
proxyReq.addListener('response', (proxyRes) => {
|
||||||
const resHeaders = { ...proxyRes.headers }
|
const resHeaders = { ...proxyRes.headers }
|
||||||
// `net.request` returns an already decoded body
|
|
||||||
delete resHeaders['content-encoding']
|
delete resHeaders['content-encoding']
|
||||||
res.writeHead(proxyRes.statusCode, proxyRes.statusMessage, resHeaders)
|
res.writeHead(proxyRes.statusCode, proxyRes.statusMessage, resHeaders)
|
||||||
;(proxyRes as unknown as NodeJS.ReadableStream).pipe(res)
|
;(proxyRes as unknown as NodeJS.ReadableStream).pipe(res)
|
||||||
@@ -49,6 +48,7 @@ export class HttpProxy {
|
|||||||
logger.write(`error [cors-proxy] ${err.message} (${host})`)
|
logger.write(`error [cors-proxy] ${err.message} (${host})`)
|
||||||
res.destroy(err)
|
res.destroy(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
req.pipe(proxyReq as unknown as NodeJS.WritableStream)
|
req.pipe(proxyReq as unknown as NodeJS.WritableStream)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ export async function startServer (
|
|||||||
socket.on('close', () => {
|
socket.on('close', () => {
|
||||||
const clients = websocketServer.clients
|
const clients = websocketServer.clients
|
||||||
if (clients.size === 1) {
|
if (clients.size === 1) {
|
||||||
lastActiveClient = clients.values().next().value
|
lastActiveClient = clients.values().next().value!
|
||||||
evBus.emit('CLIENT->MAIN::used-recently', { isOverlay: true })
|
evBus.emit('CLIENT->MAIN::used-recently', { isOverlay: true })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,172 +1,188 @@
|
|||||||
import path from 'path'
|
import path from "path";
|
||||||
import { BrowserWindow, dialog, shell, Menu, WebContents } from 'electron'
|
import { BrowserWindow, dialog, shell, Menu, WebContents } from "electron";
|
||||||
import { OverlayController, OVERLAY_WINDOW_OPTS } from 'electron-overlay-window'
|
import {
|
||||||
import type { ServerEvents } from '../server'
|
OverlayController,
|
||||||
import type { Logger } from '../RemoteLogger'
|
OVERLAY_WINDOW_OPTS,
|
||||||
import type { GameWindow } from './GameWindow'
|
} from "electron-overlay-window";
|
||||||
|
import type { ServerEvents } from "../server";
|
||||||
|
import type { Logger } from "../RemoteLogger";
|
||||||
|
import type { GameWindow } from "./GameWindow";
|
||||||
|
|
||||||
export class OverlayWindow {
|
export class OverlayWindow {
|
||||||
public isInteractable = false
|
public isInteractable = false;
|
||||||
public wasUsedRecently = true
|
public wasUsedRecently = true;
|
||||||
private window?: BrowserWindow
|
private window?: BrowserWindow;
|
||||||
private overlayKey: string = 'Shift + Space'
|
private overlayKey: string = "Shift + Space";
|
||||||
private isOverlayKeyUsed = false
|
private isOverlayKeyUsed = false;
|
||||||
|
|
||||||
constructor (
|
constructor(
|
||||||
private server: ServerEvents,
|
private server: ServerEvents,
|
||||||
private logger: Logger,
|
private logger: Logger,
|
||||||
private poeWindow: GameWindow,
|
private poeWindow: GameWindow
|
||||||
) {
|
) {
|
||||||
this.server.onEventAnyClient('OVERLAY->MAIN::focus-game', this.assertGameActive)
|
this.server.onEventAnyClient(
|
||||||
this.poeWindow.on('active-change', this.handlePoeWindowActiveChange)
|
"OVERLAY->MAIN::focus-game",
|
||||||
this.poeWindow.onAttach(this.handleOverlayAttached)
|
this.assertGameActive
|
||||||
|
);
|
||||||
|
this.poeWindow.on("active-change", this.handlePoeWindowActiveChange);
|
||||||
|
this.poeWindow.onAttach(this.handleOverlayAttached);
|
||||||
|
|
||||||
this.server.onEventAnyClient('CLIENT->MAIN::used-recently', (e) => {
|
this.server.onEventAnyClient("CLIENT->MAIN::used-recently", (e) => {
|
||||||
this.wasUsedRecently = e.isOverlay
|
this.wasUsedRecently = e.isOverlay;
|
||||||
})
|
});
|
||||||
|
|
||||||
if (process.argv.includes('--no-overlay')) return
|
if (process.argv.includes("--no-overlay")) return;
|
||||||
|
|
||||||
this.window = new BrowserWindow({
|
this.window = new BrowserWindow({
|
||||||
icon: path.join(__dirname, process.env.STATIC!, 'icon.png'),
|
icon: path.join(__dirname, process.env.STATIC!, "icon.png"),
|
||||||
...OVERLAY_WINDOW_OPTS,
|
...OVERLAY_WINDOW_OPTS,
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
allowRunningInsecureContent: false,
|
allowRunningInsecureContent: false,
|
||||||
webviewTag: true,
|
webviewTag: true,
|
||||||
spellcheck: false
|
spellcheck: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
this.window.setMenu(
|
||||||
|
Menu.buildFromTemplate([
|
||||||
|
{ role: "editMenu" },
|
||||||
|
{ role: "reload" },
|
||||||
|
{ role: "toggleDevTools" },
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
this.window.webContents.on("before-input-event", this.handleExtraCommands);
|
||||||
|
this.window.webContents.on(
|
||||||
|
"did-attach-webview",
|
||||||
|
(_, webviewWebContents) => {
|
||||||
|
webviewWebContents.on("before-input-event", this.handleExtraCommands);
|
||||||
}
|
}
|
||||||
})
|
);
|
||||||
|
|
||||||
this.window.setMenu(Menu.buildFromTemplate([
|
|
||||||
{ role: 'editMenu' },
|
|
||||||
{ role: 'reload' },
|
|
||||||
{ role: 'toggleDevTools' }
|
|
||||||
]))
|
|
||||||
|
|
||||||
this.window.webContents.on('before-input-event', this.handleExtraCommands)
|
|
||||||
this.window.webContents.on('did-attach-webview', (_, webviewWebContents) => {
|
|
||||||
webviewWebContents.on('before-input-event', this.handleExtraCommands)
|
|
||||||
})
|
|
||||||
|
|
||||||
this.window.webContents.setWindowOpenHandler((details) => {
|
this.window.webContents.setWindowOpenHandler((details) => {
|
||||||
shell.openExternal(details.url)
|
shell.openExternal(details.url);
|
||||||
return { action: 'deny' }
|
return { action: "deny" };
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
loadAppPage (port: number) {
|
loadAppPage(port: number) {
|
||||||
const url = process.env.VITE_DEV_SERVER_URL ||
|
const url =
|
||||||
`http://localhost:${port}/index.html`
|
process.env.VITE_DEV_SERVER_URL || `http://localhost:${port}/index.html`;
|
||||||
|
|
||||||
if (!this.window) {
|
if (!this.window) {
|
||||||
shell.openExternal(url)
|
shell.openExternal(url);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.VITE_DEV_SERVER_URL) {
|
if (process.env.VITE_DEV_SERVER_URL) {
|
||||||
this.window.loadURL(url)
|
this.window.loadURL(url);
|
||||||
this.window.webContents.openDevTools({ mode: 'detach', activate: false })
|
this.window.webContents.openDevTools({ mode: "detach", activate: false });
|
||||||
} else {
|
} else {
|
||||||
this.window.loadURL(url)
|
this.window.loadURL(url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assertOverlayActive = () => {
|
assertOverlayActive = () => {
|
||||||
if (!this.isInteractable) {
|
if (!this.isInteractable) {
|
||||||
this.isInteractable = true
|
this.isInteractable = true;
|
||||||
OverlayController.activateOverlay()
|
OverlayController.activateOverlay();
|
||||||
this.poeWindow.isActive = false
|
this.poeWindow.isActive = false;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
assertGameActive = () => {
|
assertGameActive = () => {
|
||||||
if (this.isInteractable) {
|
if (this.isInteractable) {
|
||||||
this.isInteractable = false
|
this.isInteractable = false;
|
||||||
OverlayController.focusTarget()
|
OverlayController.focusTarget();
|
||||||
this.poeWindow.isActive = true
|
this.poeWindow.isActive = true;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
toggleActiveState = () => {
|
toggleActiveState = () => {
|
||||||
this.isOverlayKeyUsed = true
|
this.isOverlayKeyUsed = true;
|
||||||
if (this.isInteractable) {
|
if (this.isInteractable) {
|
||||||
this.assertGameActive()
|
this.assertGameActive();
|
||||||
} else {
|
} else {
|
||||||
this.assertOverlayActive()
|
this.assertOverlayActive();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
updateOpts(overlayKey: string, windowTitle: string) {
|
||||||
|
this.overlayKey = overlayKey;
|
||||||
|
this.poeWindow.attach(this.window, windowTitle);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateOpts (overlayKey: string, windowTitle: string) {
|
private handleExtraCommands = (
|
||||||
this.overlayKey = overlayKey
|
event: Electron.Event,
|
||||||
this.poeWindow.attach(this.window, windowTitle)
|
input: Electron.Input
|
||||||
}
|
) => {
|
||||||
|
if (input.type !== "keyDown") return;
|
||||||
|
|
||||||
private handleExtraCommands = (event: Electron.Event, input: Electron.Input) => {
|
let { code, control: ctrlKey, shift: shiftKey, alt: altKey } = input;
|
||||||
if (input.type !== 'keyDown') return
|
|
||||||
|
|
||||||
let { code, control: ctrlKey, shift: shiftKey, alt: altKey } = input
|
if (code.startsWith("Key")) {
|
||||||
|
code = code.slice("Key".length);
|
||||||
if (code.startsWith('Key')) {
|
} else if (code.startsWith("Digit")) {
|
||||||
code = code.slice('Key'.length)
|
code = code.slice("Digit".length);
|
||||||
} else if (code.startsWith('Digit')) {
|
|
||||||
code = code.slice('Digit'.length)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shiftKey && altKey) code = `Shift + Alt + ${code}`
|
if (shiftKey && altKey) code = `Shift + Alt + ${code}`;
|
||||||
else if (ctrlKey && shiftKey) code = `Ctrl + Shift + ${code}`
|
else if (ctrlKey && shiftKey) code = `Ctrl + Shift + ${code}`;
|
||||||
else if (ctrlKey && altKey) code = `Ctrl + Alt + ${code}`
|
else if (ctrlKey && altKey) code = `Ctrl + Alt + ${code}`;
|
||||||
else if (altKey) code = `Alt + ${code}`
|
else if (altKey) code = `Alt + ${code}`;
|
||||||
else if (ctrlKey) code = `Ctrl + ${code}`
|
else if (ctrlKey) code = `Ctrl + ${code}`;
|
||||||
else if (shiftKey) code = `Shift + ${code}`
|
else if (shiftKey) code = `Shift + ${code}`;
|
||||||
|
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case 'Escape':
|
case "Escape":
|
||||||
case 'Ctrl + W': {
|
case "Ctrl + W": {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
process.nextTick(this.assertGameActive)
|
process.nextTick(this.assertGameActive);
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
case this.overlayKey: {
|
case this.overlayKey: {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
process.nextTick(this.toggleActiveState)
|
process.nextTick(this.toggleActiveState);
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
private handleOverlayAttached = (hasAccess?: boolean) => {
|
private handleOverlayAttached = (hasAccess?: boolean) => {
|
||||||
if (hasAccess === false) {
|
if (hasAccess === false) {
|
||||||
this.logger.write('error [Overlay] PoE is running with administrator rights')
|
this.logger.write(
|
||||||
|
"error [Overlay] PoE is running with administrator rights"
|
||||||
|
);
|
||||||
|
|
||||||
dialog.showErrorBox(
|
dialog.showErrorBox(
|
||||||
'PoE window - No access',
|
"PoE window - No access",
|
||||||
// ----------------------
|
// ----------------------
|
||||||
'Path of Exile is running with administrator rights.\n' +
|
"Path of Exile 2 is running with administrator rights.\n" +
|
||||||
'\n' +
|
"\n" +
|
||||||
'You need to restart Awakened PoE Trade with administrator rights.'
|
"You need to restart Exiled Exchange 2 with administrator rights."
|
||||||
)
|
);
|
||||||
} else {
|
} else {
|
||||||
this.server.sendEventTo('broadcast', {
|
this.server.sendEventTo("broadcast", {
|
||||||
name: 'MAIN->OVERLAY::overlay-attached',
|
name: "MAIN->OVERLAY::overlay-attached",
|
||||||
payload: undefined
|
payload: undefined,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
private handlePoeWindowActiveChange = (isActive: boolean) => {
|
private handlePoeWindowActiveChange = (isActive: boolean) => {
|
||||||
if (isActive && this.isInteractable) {
|
if (isActive && this.isInteractable) {
|
||||||
this.isInteractable = false
|
this.isInteractable = false;
|
||||||
}
|
}
|
||||||
this.server.sendEventTo('broadcast', {
|
this.server.sendEventTo("broadcast", {
|
||||||
name: 'MAIN->OVERLAY::focus-change',
|
name: "MAIN->OVERLAY::focus-change",
|
||||||
payload: {
|
payload: {
|
||||||
game: isActive,
|
game: isActive,
|
||||||
overlay: this.isInteractable,
|
overlay: this.isInteractable,
|
||||||
usingHotkey: this.isOverlayKeyUsed
|
usingHotkey: this.isOverlayKeyUsed,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
this.isOverlayKeyUsed = false
|
this.isOverlayKeyUsed = false;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
1956
main/yarn.lock
@@ -4,12 +4,12 @@ module.exports = {
|
|||||||
node: true
|
node: true
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
'@typescript-eslint'
|
'@typescript-eslint',
|
||||||
// 'only-warn'
|
// 'only-warn'
|
||||||
],
|
],
|
||||||
extends: [
|
extends: [
|
||||||
'plugin:vue/base',
|
'plugin:vue/base',
|
||||||
'standard-with-typescript'
|
'standard-with-typescript',
|
||||||
],
|
],
|
||||||
rules: {
|
rules: {
|
||||||
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||||
@@ -36,7 +36,7 @@ module.exports = {
|
|||||||
'import/no-duplicates': 'off',
|
'import/no-duplicates': 'off',
|
||||||
'func-call-spacing': 'off',
|
'func-call-spacing': 'off',
|
||||||
// TODO: refactor IPC and enable
|
// TODO: refactor IPC and enable
|
||||||
'@typescript-eslint/consistent-type-assertions': 'off'
|
'@typescript-eslint/consistent-type-assertions': 'off',
|
||||||
},
|
},
|
||||||
overrides: [{
|
overrides: [{
|
||||||
files: ['src/main/**/*'],
|
files: ['src/main/**/*'],
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
<head>
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="color-scheme" content="dark">
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
<link rel="icon" href="/icon.ico">
|
<meta name="color-scheme" content="dark">
|
||||||
<title>Awakened PoE Trade</title>
|
<link rel="icon" href="/icon.ico">
|
||||||
</head>
|
<title>Exiled Exchange 2</title>
|
||||||
<body>
|
</head>
|
||||||
<div id="app"></div>
|
|
||||||
<script type="module" src="/src/main.ts"></script>
|
<body>
|
||||||
</body>
|
<div id="app"></div>
|
||||||
</html>
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
12786
renderer/package-lock.json
generated
@@ -1,62 +1,63 @@
|
|||||||
{
|
{
|
||||||
"name": "awakened-poe-trade",
|
"name": "exiled-exchange-2",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"lint": "eslint --ext .ts,.vue src",
|
"lint": "eslint --ext .ts,.vue src",
|
||||||
"build": "vue-tsc --noEmit && vite build",
|
"lint-fix": "eslint --ext .ts,.vue src --fix",
|
||||||
"make-index-files": "node src/assets/make-index-files.mjs"
|
"build": "vue-tsc --noEmit && vite build",
|
||||||
},
|
"make-index-files": "node src/assets/make-index-files.mjs"
|
||||||
"dependencies": {
|
},
|
||||||
"@fortawesome/fontawesome-free": "6.x.x",
|
"dependencies": {
|
||||||
"@sindresorhus/fnv1a": "^3.0.0",
|
"@fortawesome/fontawesome-free": "6.x.x",
|
||||||
"@vueuse/core": "^11.0.0",
|
"@sindresorhus/fnv1a": "^3.0.0",
|
||||||
"animate.css": "^4.1.1",
|
"@vueuse/core": "^11.0.0",
|
||||||
"apexcharts": "^4.0.0",
|
"animate.css": "^4.1.1",
|
||||||
"dot-prop": "9.x.x",
|
"apexcharts": "^4.0.0",
|
||||||
"fast-deep-equal": "^3.1.3",
|
"dot-prop": "9.x.x",
|
||||||
"fastest-levenshtein": "^1.0.16",
|
"fast-deep-equal": "^3.1.3",
|
||||||
"luxon": "3.x.x",
|
"fastest-levenshtein": "^1.0.16",
|
||||||
"neverthrow": "^8.0.0",
|
"luxon": "3.x.x",
|
||||||
"object-hash": "^3.0.0",
|
"neverthrow": "^8.0.0",
|
||||||
"sockette": "^2.0.6",
|
"object-hash": "^3.0.0",
|
||||||
"tailwindcss": "3.x.x",
|
"sockette": "^2.0.6",
|
||||||
"tippy.js": "^6.2.7",
|
"tailwindcss": "3.x.x",
|
||||||
"vue": "3.2.37",
|
"tippy.js": "^6.2.7",
|
||||||
"vue-i18n": "^10.0.0",
|
"vue": "3.2.37",
|
||||||
"vue3-apexcharts": "^1.1.1",
|
"vue-i18n": "^10.0.0",
|
||||||
"vuedraggable": "4.1.0"
|
"vue3-apexcharts": "^1.1.1",
|
||||||
},
|
"vuedraggable": "4.1.0"
|
||||||
"devDependencies": {
|
},
|
||||||
"@types/luxon": "^3.0.0",
|
"devDependencies": {
|
||||||
"@types/node": "^20.0.0",
|
"@types/luxon": "^3.0.0",
|
||||||
"@types/object-hash": "^3.0.0",
|
"@types/node": "^20.0.0",
|
||||||
"@vitejs/plugin-vue": "^4.0.0",
|
"@types/object-hash": "^3.0.0",
|
||||||
"autoprefixer": "^10.0.2",
|
"@vitejs/plugin-vue": "^4.0.0",
|
||||||
"postcss": "^8.2.14",
|
"autoprefixer": "^10.0.2",
|
||||||
"typescript": "5.6.x",
|
"postcss": "^8.2.14",
|
||||||
"vite": "^5.0.0",
|
"typescript": "5.6.x",
|
||||||
"vue-tsc": "^2.0.0"
|
"vite": "^5.0.0",
|
||||||
},
|
"vue-tsc": "^2.0.0"
|
||||||
"optionalDependencies": {
|
},
|
||||||
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
"optionalDependencies": {
|
||||||
"@typescript-eslint/parser": "^5.0.0",
|
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
||||||
"eslint": "^8.21.0",
|
"@typescript-eslint/parser": "^5.0.0",
|
||||||
"eslint-config-standard-with-typescript": "^31.0.0",
|
"eslint": "^8.21.0",
|
||||||
"eslint-plugin-import": "^2.20.2",
|
"eslint-config-standard-with-typescript": "^31.0.0",
|
||||||
"eslint-plugin-n": "^15.0.0",
|
"eslint-plugin-import": "^2.20.2",
|
||||||
"eslint-plugin-promise": "^6.0.0",
|
"eslint-plugin-n": "^15.0.0",
|
||||||
"eslint-plugin-vue": "^9.1.1"
|
"eslint-plugin-promise": "^6.0.0",
|
||||||
},
|
"eslint-plugin-vue": "^9.1.1"
|
||||||
"postcss": {
|
},
|
||||||
"plugins": {
|
"postcss": {
|
||||||
"tailwindcss/nesting": {},
|
"plugins": {
|
||||||
"tailwindcss": {},
|
"tailwindcss/nesting": {},
|
||||||
"autoprefixer": {}
|
"tailwindcss": {},
|
||||||
}
|
"autoprefixer": {}
|
||||||
},
|
}
|
||||||
"browserslist": [
|
},
|
||||||
"chrome >= 101"
|
"browserslist": [
|
||||||
]
|
"chrome >= 101"
|
||||||
}
|
]
|
||||||
|
}
|
||||||
@@ -7,7 +7,6 @@
|
|||||||
"league": "League",
|
"league": "League",
|
||||||
"realm": "Realm",
|
"realm": "Realm",
|
||||||
"realm_intl": "International",
|
"realm_intl": "International",
|
||||||
|
|
||||||
"app": {
|
"app": {
|
||||||
"leagues_loading": "Loading leagues\u2026",
|
"leagues_loading": "Loading leagues\u2026",
|
||||||
"leagues_failed": "Failed to load leagues",
|
"leagues_failed": "Failed to load leagues",
|
||||||
@@ -21,12 +20,10 @@
|
|||||||
"report_bug": "Report a bug on GitHub",
|
"report_bug": "Report a bug on GitHub",
|
||||||
"quit": "Quit"
|
"quit": "Quit"
|
||||||
},
|
},
|
||||||
|
|
||||||
"map.mods.heist": "heist",
|
"map.mods.heist": "heist",
|
||||||
"map.mods.uber": "T17",
|
"map.mods.uber": "T17",
|
||||||
"map.mods.outdated": "outdated",
|
"map.mods.outdated": "outdated",
|
||||||
"Support development on": "Support development\u00A0on",
|
"Support development on": "Support development\u00A0on",
|
||||||
|
|
||||||
"Blighted": "Blighted",
|
"Blighted": "Blighted",
|
||||||
"Blight-ravaged": "Blight-ravaged",
|
"Blight-ravaged": "Blight-ravaged",
|
||||||
"Magic": "Magic",
|
"Magic": "Magic",
|
||||||
@@ -40,7 +37,6 @@
|
|||||||
"Anomalous": "Anomalous",
|
"Anomalous": "Anomalous",
|
||||||
"Divergent": "Divergent",
|
"Divergent": "Divergent",
|
||||||
"Phantasmal": "Phantasmal",
|
"Phantasmal": "Phantasmal",
|
||||||
|
|
||||||
"item": {
|
"item": {
|
||||||
"prop_quality": "Q {0}%",
|
"prop_quality": "Q {0}%",
|
||||||
"base_percentile": "Base Percentile: {0}%",
|
"base_percentile": "Base Percentile: {0}%",
|
||||||
@@ -153,7 +149,6 @@
|
|||||||
"hide_anointment": "Buyer will likely change anointment",
|
"hide_anointment": "Buyer will likely change anointment",
|
||||||
"hide_for_crafting": "Select only if price-checking as base item for crafting",
|
"hide_for_crafting": "Select only if price-checking as base item for crafting",
|
||||||
"hide_empty_mod": "Select only if item has 6 modifiers (1 of which is crafted) or if it has 5 modifiers",
|
"hide_empty_mod": "Select only if item has 6 modifiers (1 of which is crafted) or if it has 5 modifiers",
|
||||||
|
|
||||||
"tag_implicit": "implicit",
|
"tag_implicit": "implicit",
|
||||||
"tag_fractured": "fractured",
|
"tag_fractured": "fractured",
|
||||||
"tag_crafted": "crafted",
|
"tag_crafted": "crafted",
|
||||||
@@ -254,15 +249,15 @@
|
|||||||
"new_mods_icon": "Show icon for new mods"
|
"new_mods_icon": "Show icon for new mods"
|
||||||
},
|
},
|
||||||
"trade_result": {
|
"trade_result": {
|
||||||
"error" :"Trade site request failed",
|
"error": "Trade site request failed",
|
||||||
"matched" :"Matched: {0}",
|
"matched": "Matched: {0}",
|
||||||
"trade" :"Trade",
|
"trade": "Trade",
|
||||||
"price" :"Price",
|
"price": "Price",
|
||||||
"bulk" :"bulk",
|
"bulk": "bulk",
|
||||||
"stock" :"Stock",
|
"stock": "Stock",
|
||||||
"fulfill" :"Fulfill",
|
"fulfill": "Fulfill",
|
||||||
"listed" :"Listed",
|
"listed": "Listed",
|
||||||
"seller" :"Seller",
|
"seller": "Seller",
|
||||||
"item_level": "iLvl",
|
"item_level": "iLvl",
|
||||||
"gem_level": "Level",
|
"gem_level": "Level",
|
||||||
"quality": "Quality",
|
"quality": "Quality",
|
||||||
@@ -274,7 +269,7 @@
|
|||||||
"stack": "Stack"
|
"stack": "Stack"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"title": "Settings - Awakened PoE Trade",
|
"title": "Settings - Exiled Exchange 2",
|
||||||
"language": "Language",
|
"language": "Language",
|
||||||
"private_league": "or Private League",
|
"private_league": "or Private League",
|
||||||
"account_name": "Account name",
|
"account_name": "Account name",
|
||||||
@@ -283,9 +278,9 @@
|
|||||||
"chat_cmd_send": "press Enter",
|
"chat_cmd_send": "press Enter",
|
||||||
"no_key": "Not Set",
|
"no_key": "Not Set",
|
||||||
"clear_hotkey": "You can clear hotkey by pressing Backspace",
|
"clear_hotkey": "You can clear hotkey by pressing Backspace",
|
||||||
"overlay" :"Overlay",
|
"overlay": "Overlay",
|
||||||
"stash_scroll" :"Stash tab scrolling",
|
"stash_scroll": "Stash tab scrolling",
|
||||||
"delve_grid" :"Grid for Delve Chart",
|
"delve_grid": "Grid for Delve Chart",
|
||||||
"window_title": "PoE window title",
|
"window_title": "PoE window title",
|
||||||
"thank_you": "App development continues thanks to:",
|
"thank_you": "App development continues thanks to:",
|
||||||
"hotkeys": "Hotkeys",
|
"hotkeys": "Hotkeys",
|
||||||
@@ -293,20 +288,20 @@
|
|||||||
"general": "General",
|
"general": "General",
|
||||||
"debug": "Debug",
|
"debug": "Debug",
|
||||||
"about": "About",
|
"about": "About",
|
||||||
"font_size" :"Font size",
|
"font_size": "Font size",
|
||||||
"overlay_bg" :"Background when the Overlay is clickable",
|
"overlay_bg": "Background when the Overlay is clickable",
|
||||||
"overlay_bg_none" :"Transparent",
|
"overlay_bg_none": "Transparent",
|
||||||
"overlay_bg_focus_game" :"Clicking on the background focuses the game",
|
"overlay_bg_focus_game": "Clicking on the background focuses the game",
|
||||||
"poe_log_file" :"PoE log file",
|
"poe_log_file": "PoE log file",
|
||||||
"poe_cfg_file" :"PoE config file",
|
"poe_cfg_file": "PoE config file",
|
||||||
"restore_clipboard" :"Restore clipboard",
|
"restore_clipboard": "Restore clipboard",
|
||||||
"show_overlay_ready" :"Show a notification when the Overlay detects a PoE window",
|
"show_overlay_ready": "Show a notification when the Overlay detects a PoE window",
|
||||||
"debug_hotkeys": "Record all key presses"
|
"debug_hotkeys": "Record all key presses"
|
||||||
},
|
},
|
||||||
"price_check": {
|
"price_check": {
|
||||||
"name": "Price check",
|
"name": "Price check",
|
||||||
"hotkey" :"Auto-hide Mode",
|
"hotkey": "Auto-hide Mode",
|
||||||
"hotkey_locked" :"Open without auto-hide",
|
"hotkey_locked": "Open without auto-hide",
|
||||||
"enable_browser": "Enable builtin browser",
|
"enable_browser": "Enable builtin browser",
|
||||||
"builtin_browser_warning": "I am aware that future releases can potentially contain malicious code that can steal my POESESSID.",
|
"builtin_browser_warning": "I am aware that future releases can potentially contain malicious code that can steal my POESESSID.",
|
||||||
"highlight_hint": "Your items will be highlighted even if this setting is off",
|
"highlight_hint": "Your items will be highlighted even if this setting is off",
|
||||||
@@ -322,4 +317,4 @@
|
|||||||
"show_prediction": "Show price prediction",
|
"show_prediction": "Show price prediction",
|
||||||
"remember_currency": "Remember the Buyout Currency filter"
|
"remember_currency": "Remember the Buyout Currency filter"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,6 @@
|
|||||||
"reopen_settings": "{0}을 눌러서 편집을 계속하세요.",
|
"reopen_settings": "{0}을 눌러서 편집을 계속하세요.",
|
||||||
"seconds": "초",
|
"seconds": "초",
|
||||||
"league": "리그",
|
"league": "리그",
|
||||||
|
|
||||||
"app": {
|
"app": {
|
||||||
"leagues_loading": "리그를 불러오는 중\u2026",
|
"leagues_loading": "리그를 불러오는 중\u2026",
|
||||||
"leagues_failed": "리그 불러오기를 실패하였습니다",
|
"leagues_failed": "리그 불러오기를 실패하였습니다",
|
||||||
@@ -19,11 +18,9 @@
|
|||||||
"report_bug": "버그 발생 시 GitHub에 보고해주세요",
|
"report_bug": "버그 발생 시 GitHub에 보고해주세요",
|
||||||
"quit": "종료"
|
"quit": "종료"
|
||||||
},
|
},
|
||||||
|
|
||||||
"map.mods.heist": "강탈",
|
"map.mods.heist": "강탈",
|
||||||
"map.mods.outdated": "사용X",
|
"map.mods.outdated": "사용X",
|
||||||
"Support development on": "개발을 지원하세요",
|
"Support development on": "개발을 지원하세요",
|
||||||
|
|
||||||
"Blighted": "역병 걸린",
|
"Blighted": "역병 걸린",
|
||||||
"Blight-ravaged": "역병에 유린당한",
|
"Blight-ravaged": "역병에 유린당한",
|
||||||
"Magic": "매직",
|
"Magic": "매직",
|
||||||
@@ -37,7 +34,6 @@
|
|||||||
"Anomalous": "기묘한",
|
"Anomalous": "기묘한",
|
||||||
"Divergent": "상이한",
|
"Divergent": "상이한",
|
||||||
"Phantasmal": "몽환적인",
|
"Phantasmal": "몽환적인",
|
||||||
|
|
||||||
"item": {
|
"item": {
|
||||||
"prop_quality": "{0}% 퀄리티",
|
"prop_quality": "{0}% 퀄리티",
|
||||||
"base_percentile": "기본 백분위수: {0}%",
|
"base_percentile": "기본 백분위수: {0}%",
|
||||||
@@ -150,7 +146,6 @@
|
|||||||
"hide_anointment": "Buyer will likely change anointment",
|
"hide_anointment": "Buyer will likely change anointment",
|
||||||
"hide_for_crafting": "Select only if price-checking as base item for crafting",
|
"hide_for_crafting": "Select only if price-checking as base item for crafting",
|
||||||
"hide_empty_mod": "Select only if item has 6 modifiers (1 of which is crafted) or if it has 5 modifiers",
|
"hide_empty_mod": "Select only if item has 6 modifiers (1 of which is crafted) or if it has 5 modifiers",
|
||||||
|
|
||||||
"tag_implicit": "고정 속성",
|
"tag_implicit": "고정 속성",
|
||||||
"tag_fractured": "분열된",
|
"tag_fractured": "분열된",
|
||||||
"tag_crafted": "제작된",
|
"tag_crafted": "제작된",
|
||||||
@@ -271,7 +266,7 @@
|
|||||||
"stack": "스택"
|
"stack": "스택"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"title": "세팅 - Awakened PoE Trade",
|
"title": "세팅 - Exiled Exchange 2",
|
||||||
"language": "언어",
|
"language": "언어",
|
||||||
"private_league": "개인리그",
|
"private_league": "개인리그",
|
||||||
"account_name": "계정명",
|
"account_name": "계정명",
|
||||||
@@ -302,8 +297,8 @@
|
|||||||
},
|
},
|
||||||
"price_check": {
|
"price_check": {
|
||||||
"name": "Price check",
|
"name": "Price check",
|
||||||
"hotkey" :"Auto-hide Mode",
|
"hotkey": "Auto-hide Mode",
|
||||||
"hotkey_locked" :"Open without auto-hide",
|
"hotkey_locked": "Open without auto-hide",
|
||||||
"enable_browser": "Enable builtin browser",
|
"enable_browser": "Enable builtin browser",
|
||||||
"builtin_browser_warning": "I am aware that future releases can potentially contain malicious code that can steal my POESESSID.",
|
"builtin_browser_warning": "I am aware that future releases can potentially contain malicious code that can steal my POESESSID.",
|
||||||
"highlight_hint": "Your items will be highlighted even if this setting is off",
|
"highlight_hint": "Your items will be highlighted even if this setting is off",
|
||||||
|
|||||||
@@ -19,14 +19,12 @@
|
|||||||
"Select": "Выбрать",
|
"Select": "Выбрать",
|
||||||
"Not recognized modifier": "Нераспознанное свойство",
|
"Not recognized modifier": "Нераспознанное свойство",
|
||||||
"Refresh": "Обновить",
|
"Refresh": "Обновить",
|
||||||
|
|
||||||
"please_wait": "Пожалуйста, подождите\u2026",
|
"please_wait": "Пожалуйста, подождите\u2026",
|
||||||
"choose_file": "Выберите файл",
|
"choose_file": "Выберите файл",
|
||||||
"app_is_ready": "Запущен и работает в фоновом режиме",
|
"app_is_ready": "Запущен и работает в фоновом режиме",
|
||||||
"reopen_settings": "Нажмите {0} чтобы продолжить редактирование.",
|
"reopen_settings": "Нажмите {0} чтобы продолжить редактирование.",
|
||||||
"seconds": "секунды",
|
"seconds": "секунды",
|
||||||
"league": "Лига",
|
"league": "Лига",
|
||||||
|
|
||||||
"app": {
|
"app": {
|
||||||
"leagues_loading": "Загрузка лиг\u2026",
|
"leagues_loading": "Загрузка лиг\u2026",
|
||||||
"leagues_failed": "Не удалось загрузить лиги",
|
"leagues_failed": "Не удалось загрузить лиги",
|
||||||
@@ -40,11 +38,9 @@
|
|||||||
"report_bug": "Сообщить о баге на GitHub",
|
"report_bug": "Сообщить о баге на GitHub",
|
||||||
"quit": "Выход"
|
"quit": "Выход"
|
||||||
},
|
},
|
||||||
|
|
||||||
"map.mods.heist": "кража",
|
"map.mods.heist": "кража",
|
||||||
"map.mods.outdated": "устарело",
|
"map.mods.outdated": "устарело",
|
||||||
"Support development on": "Поддержите разработку\u00A0на",
|
"Support development on": "Поддержите разработку\u00A0на",
|
||||||
|
|
||||||
"Blighted": "Заражённая",
|
"Blighted": "Заражённая",
|
||||||
"Blight-ravaged": "Разорённая Скверной",
|
"Blight-ravaged": "Разорённая Скверной",
|
||||||
"Shaper": "Создатель",
|
"Shaper": "Создатель",
|
||||||
@@ -57,7 +53,6 @@
|
|||||||
"Anomalous": "Аномальный",
|
"Anomalous": "Аномальный",
|
||||||
"Divergent": "Искривлённый",
|
"Divergent": "Искривлённый",
|
||||||
"Phantasmal": "Фантомный",
|
"Phantasmal": "Фантомный",
|
||||||
|
|
||||||
"item": {
|
"item": {
|
||||||
"prop_quality": "К-во: {0}%",
|
"prop_quality": "К-во: {0}%",
|
||||||
"base_percentile": "Ролл значений базы: {0}%",
|
"base_percentile": "Ролл значений базы: {0}%",
|
||||||
@@ -168,7 +163,6 @@
|
|||||||
"hide_anointment": "Покупатель, скорее всего, поменяет зачарование",
|
"hide_anointment": "Покупатель, скорее всего, поменяет зачарование",
|
||||||
"hide_for_crafting": "Отмечайте, если проверяете цену в качестве базового предмета для крафта",
|
"hide_for_crafting": "Отмечайте, если проверяете цену в качестве базового предмета для крафта",
|
||||||
"hide_empty_mod": "Выбирайте, только если у предмета 6 свойств (1 из которых ремесленное) или если у него 5 свойств",
|
"hide_empty_mod": "Выбирайте, только если у предмета 6 свойств (1 из которых ремесленное) или если у него 5 свойств",
|
||||||
|
|
||||||
"tag_crafted": "мастер",
|
"tag_crafted": "мастер",
|
||||||
"tag_fractured": "расколотый",
|
"tag_fractured": "расколотый",
|
||||||
"tag_scourge": "преображен",
|
"tag_scourge": "преображен",
|
||||||
@@ -268,15 +262,15 @@
|
|||||||
"new_mods_icon": "Иконка у новых модов"
|
"new_mods_icon": "Иконка у новых модов"
|
||||||
},
|
},
|
||||||
"trade_result": {
|
"trade_result": {
|
||||||
"error" :"Запрос к сайту не удался",
|
"error": "Запрос к сайту не удался",
|
||||||
"matched" :"Найдено: {0}",
|
"matched": "Найдено: {0}",
|
||||||
"trade" :"Трейд",
|
"trade": "Трейд",
|
||||||
"price" :"Цена",
|
"price": "Цена",
|
||||||
"bulk" :"опт",
|
"bulk": "опт",
|
||||||
"stock" :"Запас",
|
"stock": "Запас",
|
||||||
"fulfill" :"Сделки",
|
"fulfill": "Сделки",
|
||||||
"listed" :"Выставлен",
|
"listed": "Выставлен",
|
||||||
"seller" :"Продавец",
|
"seller": "Продавец",
|
||||||
"item_level": "Ур.",
|
"item_level": "Ур.",
|
||||||
"gem_level": "Уровень",
|
"gem_level": "Уровень",
|
||||||
"quality": "К-во",
|
"quality": "К-во",
|
||||||
@@ -288,7 +282,7 @@
|
|||||||
"stack": "Стак"
|
"stack": "Стак"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"title": "Настройки - Awakened PoE Trade",
|
"title": "Настройки - Exiled Exchange 2",
|
||||||
"language": "Язык",
|
"language": "Язык",
|
||||||
"private_league": "или Приватная лига",
|
"private_league": "или Приватная лига",
|
||||||
"account_name": "Имя учетной записи",
|
"account_name": "Имя учетной записи",
|
||||||
@@ -297,9 +291,9 @@
|
|||||||
"chat_cmd_send": "нажимать Enter",
|
"chat_cmd_send": "нажимать Enter",
|
||||||
"no_key": "Не назначено",
|
"no_key": "Не назначено",
|
||||||
"clear_hotkey": "Вы можете отключить сочетание, нажав клавишу Backspace",
|
"clear_hotkey": "Вы можете отключить сочетание, нажав клавишу Backspace",
|
||||||
"overlay" :"Оверлей",
|
"overlay": "Оверлей",
|
||||||
"stash_scroll" :"Прокрутка вкладок тайника",
|
"stash_scroll": "Прокрутка вкладок тайника",
|
||||||
"delve_grid" :"Сетка для \"Спуска\"",
|
"delve_grid": "Сетка для \"Спуска\"",
|
||||||
"window_title": "Заголовок окна игры",
|
"window_title": "Заголовок окна игры",
|
||||||
"thank_you": "Разработка приложения продолжается благодаря:",
|
"thank_you": "Разработка приложения продолжается благодаря:",
|
||||||
"hotkeys": "Быстрые клавиши",
|
"hotkeys": "Быстрые клавиши",
|
||||||
@@ -307,20 +301,20 @@
|
|||||||
"general": "Общие",
|
"general": "Общие",
|
||||||
"debug": "Debug",
|
"debug": "Debug",
|
||||||
"about": "О программе",
|
"about": "О программе",
|
||||||
"font_size" :"Размер шрифта",
|
"font_size": "Размер шрифта",
|
||||||
"overlay_bg" :"Фон, когда окно APT кликабельно",
|
"overlay_bg": "Фон, когда окно APT кликабельно",
|
||||||
"overlay_bg_none" :"Прозрачный",
|
"overlay_bg_none": "Прозрачный",
|
||||||
"overlay_bg_focus_game" :"Нажатие по фону активирует окно игры",
|
"overlay_bg_focus_game": "Нажатие по фону активирует окно игры",
|
||||||
"poe_log_file" :"Файл логов PoE",
|
"poe_log_file": "Файл логов PoE",
|
||||||
"poe_cfg_file" :"Файл настроек PoE",
|
"poe_cfg_file": "Файл настроек PoE",
|
||||||
"restore_clipboard" :"Восстанавливать буфер обмена",
|
"restore_clipboard": "Восстанавливать буфер обмена",
|
||||||
"show_overlay_ready" :"Показывать уведомление при открытии PoE",
|
"show_overlay_ready": "Показывать уведомление при открытии PoE",
|
||||||
"debug_hotkeys": "Запись всех нажатий клавиш"
|
"debug_hotkeys": "Запись всех нажатий клавиш"
|
||||||
},
|
},
|
||||||
"price_check": {
|
"price_check": {
|
||||||
"name": "Прайс-чек",
|
"name": "Прайс-чек",
|
||||||
"hotkey" :"Режим авто-скрытия",
|
"hotkey": "Режим авто-скрытия",
|
||||||
"hotkey_locked" :"Открыть без авто-скрытия",
|
"hotkey_locked": "Открыть без авто-скрытия",
|
||||||
"enable_browser": "Включить встроенный браузер",
|
"enable_browser": "Включить встроенный браузер",
|
||||||
"builtin_browser_warning": "Я осознаю, что в будущие релизы могут потенциально содержать вредоносный код, который может украсть мой POESESSID.",
|
"builtin_browser_warning": "Я осознаю, что в будущие релизы могут потенциально содержать вредоносный код, который может украсть мой POESESSID.",
|
||||||
"highlight_hint": "Ваши предметы будут подсвечены, даже если эта настройка выключена",
|
"highlight_hint": "Ваши предметы будут подсвечены, даже если эта настройка выключена",
|
||||||
@@ -336,4 +330,4 @@
|
|||||||
"show_prediction": "Показывать приблизительную цену",
|
"show_prediction": "Показывать приблизительную цену",
|
||||||
"remember_currency": "Запоминать фильтр \"Валюты выкупа\""
|
"remember_currency": "Запоминать фильтр \"Валюты выкупа\""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 353 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 14 KiB |
@@ -299,8 +299,8 @@ function parseNamePlate (section: string[]) {
|
|||||||
const item: ParserState = {
|
const item: ParserState = {
|
||||||
rarity: undefined,
|
rarity: undefined,
|
||||||
category: undefined,
|
category: undefined,
|
||||||
name: name,
|
name,
|
||||||
baseType: baseType,
|
baseType,
|
||||||
isUnidentified: false,
|
isUnidentified: false,
|
||||||
isCorrupted: false,
|
isCorrupted: false,
|
||||||
newMods: [],
|
newMods: [],
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ export enum ItemCategory {
|
|||||||
SanctumRelic = 'Sanctum Relic',
|
SanctumRelic = 'Sanctum Relic',
|
||||||
Tincture = 'Tincture',
|
Tincture = 'Tincture',
|
||||||
Charm = 'Charm',
|
Charm = 'Charm',
|
||||||
|
Crossbow = 'Crossbow',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WEAPON_ONE_HANDED_MELEE = new Set([
|
export const WEAPON_ONE_HANDED_MELEE = new Set([
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ export function translateStatWithRoll (
|
|||||||
calc.sources.some(s => s.stat.stat.ref === calc.stat.ref && s.stat.roll!.dp)
|
calc.sources.some(s => s.stat.stat.ref === calc.stat.ref && s.stat.roll!.dp)
|
||||||
: undefined
|
: undefined
|
||||||
|
|
||||||
return { string: translation.string, negate: translation.negate || false, dp: dp }
|
return { string: translation.string, negate: translation.negate || false, dp }
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ModifierType {
|
export enum ModifierType {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export function AppConfig (type?: string) {
|
|||||||
if (!type) {
|
if (!type) {
|
||||||
return _config.value!
|
return _config.value!
|
||||||
} else {
|
} else {
|
||||||
return _config.value!.widgets.find(w => w.wmType === type)
|
return _config.value!.widgets.find((w) => w.wmType === type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,7 +27,11 @@ export function updateConfig (updates: Config) {
|
|||||||
|
|
||||||
export function saveConfig (opts?: { isTemporary: boolean }) {
|
export function saveConfig (opts?: { isTemporary: boolean }) {
|
||||||
const rawConfig = toRaw(_config.value!)
|
const rawConfig = toRaw(_config.value!)
|
||||||
if (rawConfig.widgets.some(w => w.wmZorder === 'exclusive' && w.wmWants === 'show')) {
|
if (
|
||||||
|
rawConfig.widgets.some(
|
||||||
|
(w) => w.wmZorder === 'exclusive' && w.wmWants === 'show'
|
||||||
|
)
|
||||||
|
) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,9 +76,9 @@ export async function initConfig () {
|
|||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
// dialog.showErrorBox(
|
// dialog.showErrorBox(
|
||||||
// 'Awakened PoE Trade - Incompatible configuration',
|
// 'Exiled Exchange 2 - Incompatible configuration',
|
||||||
// // ----------------------
|
// // ----------------------
|
||||||
// 'You are trying to use an older version of Awakened PoE Trade with a newer incompatible configuration file.\n' +
|
// 'You are trying to use an older version of Exiled Exchange 2 with a newer incompatible configuration file.\n' +
|
||||||
// 'You need to install the latest version to continue using it.'
|
// 'You need to install the latest version to continue using it.'
|
||||||
// )
|
// )
|
||||||
}
|
}
|
||||||
@@ -85,12 +89,14 @@ export async function initConfig () {
|
|||||||
export function poeWebApi () {
|
export function poeWebApi () {
|
||||||
const { language, realm } = AppConfig()
|
const { language, realm } = AppConfig()
|
||||||
switch (language) {
|
switch (language) {
|
||||||
case 'en': return 'www.pathofexile.com'
|
case 'en':
|
||||||
case 'ru': return 'ru.pathofexile.com'
|
return 'www.pathofexile.com'
|
||||||
case 'cmn-Hant': return (realm === 'pc-garena')
|
case 'ru':
|
||||||
? 'pathofexile.tw'
|
return 'ru.pathofexile.com'
|
||||||
: 'www.pathofexile.com'
|
case 'cmn-Hant':
|
||||||
case 'ko': return 'poe.game.daum.net'
|
return realm === 'pc-garena' ? 'pathofexile.tw' : 'www.pathofexile.com'
|
||||||
|
case 'ko':
|
||||||
|
return 'poe.game.daum.net'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,34 +132,41 @@ export const defaultConfig = (): Config => ({
|
|||||||
overlayBackgroundClose: true,
|
overlayBackgroundClose: true,
|
||||||
restoreClipboard: false,
|
restoreClipboard: false,
|
||||||
showAttachNotification: true,
|
showAttachNotification: true,
|
||||||
commands: [{
|
commands: [
|
||||||
text: '/hideout',
|
{
|
||||||
hotkey: 'F5',
|
text: '/hideout',
|
||||||
send: true
|
hotkey: 'F5',
|
||||||
}, {
|
send: true
|
||||||
text: '/exit',
|
},
|
||||||
hotkey: 'F9',
|
{
|
||||||
send: true
|
text: '/exit',
|
||||||
}, {
|
hotkey: 'F9',
|
||||||
text: '@last ty',
|
send: true
|
||||||
hotkey: null,
|
},
|
||||||
send: true
|
{
|
||||||
}, {
|
text: '@last ty',
|
||||||
text: '/invite @last',
|
hotkey: null,
|
||||||
hotkey: null,
|
send: true
|
||||||
send: true
|
},
|
||||||
}, {
|
{
|
||||||
text: '/tradewith @last',
|
text: '/invite @last',
|
||||||
hotkey: null,
|
hotkey: null,
|
||||||
send: true
|
send: true
|
||||||
}, {
|
},
|
||||||
text: '/hideout @last',
|
{
|
||||||
hotkey: null,
|
text: '/tradewith @last',
|
||||||
send: true
|
hotkey: null,
|
||||||
}],
|
send: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '/hideout @last',
|
||||||
|
hotkey: null,
|
||||||
|
send: true
|
||||||
|
}
|
||||||
|
],
|
||||||
clientLog: null,
|
clientLog: null,
|
||||||
gameConfig: null,
|
gameConfig: null,
|
||||||
windowTitle: 'Path of Exile',
|
windowTitle: 'Path of Exile 2',
|
||||||
logKeys: false,
|
logKeys: false,
|
||||||
accountName: '',
|
accountName: '',
|
||||||
stashScroll: true,
|
stashScroll: true,
|
||||||
@@ -301,7 +314,12 @@ export const defaultConfig = (): Config => ({
|
|||||||
{ id: 2, name: '', text: '"Divination Card"', hotkey: null },
|
{ id: 2, name: '', text: '"Divination Card"', hotkey: null },
|
||||||
{ id: 3, name: '', text: 'Fossil', hotkey: null },
|
{ id: 3, name: '', text: 'Fossil', hotkey: null },
|
||||||
{ id: 4, name: '', text: '"Map Tier"', hotkey: null },
|
{ id: 4, name: '', text: '"Map Tier"', hotkey: null },
|
||||||
{ id: 5, name: '', text: '"Map Device" "Rarity: Normal"', hotkey: null },
|
{
|
||||||
|
id: 5,
|
||||||
|
name: '',
|
||||||
|
text: '"Map Device" "Rarity: Normal"',
|
||||||
|
hotkey: null
|
||||||
|
},
|
||||||
{ id: 6, name: '', text: 'Tane Laboratory', hotkey: null }
|
{ id: 6, name: '', text: 'Tane Laboratory', hotkey: null }
|
||||||
]
|
]
|
||||||
} as StashSearchWidget,
|
} as StashSearchWidget,
|
||||||
@@ -317,47 +335,47 @@ export const defaultConfig = (): Config => ({
|
|||||||
x: 50,
|
x: 50,
|
||||||
y: 10
|
y: 10
|
||||||
},
|
},
|
||||||
images: [
|
images: [{ id: 1, url: 'syndicate.jpg' }]
|
||||||
{ id: 1, url: 'syndicate.jpg' }
|
|
||||||
]
|
|
||||||
} as widget.ImageStripWidget
|
} as widget.ImageStripWidget
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
function upgradeConfig (_config: Config): Config {
|
function upgradeConfig (_config: Config): Config {
|
||||||
const config = _config as Omit<Config, 'widgets'> & { widgets: Array<Record<string, any>> }
|
const config = _config as Omit<Config, 'widgets'> & {
|
||||||
|
widgets: Array<Record<string, any>>
|
||||||
|
}
|
||||||
|
|
||||||
if (config.configVersion < 3) {
|
if (config.configVersion < 3) {
|
||||||
config.widgets.push({
|
config.widgets.push({
|
||||||
...defaultConfig().widgets.find(w => w.wmType === 'image-strip')!,
|
...defaultConfig().widgets.find((w) => w.wmType === 'image-strip')!,
|
||||||
wmId: Math.max(0, ...config.widgets.map(_ => _.wmId)) + 1,
|
wmId: Math.max(0, ...config.widgets.map((_) => _.wmId)) + 1,
|
||||||
wmZorder: null
|
wmZorder: null
|
||||||
})
|
})
|
||||||
|
|
||||||
config.widgets.push({
|
config.widgets.push({
|
||||||
...defaultConfig().widgets.find(w => w.wmType === 'delve-grid')!,
|
...defaultConfig().widgets.find((w) => w.wmType === 'delve-grid')!,
|
||||||
wmId: Math.max(0, ...config.widgets.map(_ => _.wmId)) + 1,
|
wmId: Math.max(0, ...config.widgets.map((_) => _.wmId)) + 1,
|
||||||
wmZorder: null
|
wmZorder: null
|
||||||
})
|
})
|
||||||
|
|
||||||
config.widgets.find(w => w.wmType === 'menu')!
|
config.widgets.find((w) => w.wmType === 'menu')!.alwaysShow = false
|
||||||
.alwaysShow = false
|
|
||||||
|
|
||||||
config.configVersion = 3
|
config.configVersion = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.configVersion < 4) {
|
if (config.configVersion < 4) {
|
||||||
config.widgets.find(w => w.wmType === 'price-check')!
|
config.widgets.find(
|
||||||
.chaosPriceThreshold = 0.05
|
(w) => w.wmType === 'price-check'
|
||||||
|
)!.chaosPriceThreshold = 0.05
|
||||||
|
|
||||||
const mapCheck = config.widgets.find(w => w.wmType === 'map-check')!
|
const mapCheck = config.widgets.find((w) => w.wmType === 'map-check')!;
|
||||||
;(mapCheck as any).selectedStats.forEach((e: any) => {
|
(mapCheck as any).selectedStats.forEach((e: any) => {
|
||||||
e.matcher = e.matchRef
|
e.matcher = e.matchRef
|
||||||
e.matchRef = undefined
|
e.matchRef = undefined
|
||||||
})
|
})
|
||||||
|
|
||||||
{
|
{
|
||||||
const widgets = config.widgets.filter(w => w.wmType === 'image-strip')!
|
const widgets = config.widgets.filter((w) => w.wmType === 'image-strip')!
|
||||||
widgets.forEach((imgStrip: any) => {
|
widgets.forEach((imgStrip: any) => {
|
||||||
imgStrip.images.forEach((e: any, idx: number) => {
|
imgStrip.images.forEach((e: any, idx: number) => {
|
||||||
e.id = idx
|
e.id = idx
|
||||||
@@ -369,7 +387,7 @@ function upgradeConfig (_config: Config): Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (config.configVersion < 5) {
|
if (config.configVersion < 5) {
|
||||||
config.commands.forEach(cmd => {
|
config.commands.forEach((cmd) => {
|
||||||
cmd.send = true
|
cmd.send = true
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -377,63 +395,68 @@ function upgradeConfig (_config: Config): Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (config.configVersion < 6) {
|
if (config.configVersion < 6) {
|
||||||
config.widgets.find(w => w.wmType === 'price-check')!
|
config.widgets.find((w) => w.wmType === 'price-check')!.showRateLimitState =
|
||||||
.showRateLimitState = ((config as any).logLevel === 'debug')
|
(config as any).logLevel === 'debug'
|
||||||
config.widgets.find(w => w.wmType === 'price-check')!
|
config.widgets.find((w) => w.wmType === 'price-check')!.apiLatencySeconds =
|
||||||
.apiLatencySeconds = 2
|
2
|
||||||
|
|
||||||
config.configVersion = 6
|
config.configVersion = 6
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.configVersion < 7) {
|
if (config.configVersion < 7) {
|
||||||
const mapCheck = config.widgets.find(w => w.wmType === 'map-check')!
|
const mapCheck = config.widgets.find((w) => w.wmType === 'map-check')!
|
||||||
mapCheck.wmType = 'item-check'
|
mapCheck.wmType = 'item-check'
|
||||||
mapCheck.maps = { selectedStats: mapCheck.selectedStats }
|
mapCheck.maps = { selectedStats: mapCheck.selectedStats }
|
||||||
mapCheck.selectedStats = undefined
|
mapCheck.selectedStats = undefined;
|
||||||
|
(config as any).itemCheckKey = (config as any).mapCheckKey || null;
|
||||||
;(config as any).itemCheckKey = (config as any).mapCheckKey || null
|
(config as any).mapCheckKey = undefined
|
||||||
;(config as any).mapCheckKey = undefined
|
|
||||||
|
|
||||||
config.configVersion = 7
|
config.configVersion = 7
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.configVersion < 8) {
|
if (config.configVersion < 8) {
|
||||||
const itemCheck = config.widgets.find(w => w.wmType === 'item-check')!
|
const itemCheck = config.widgets.find((w) => w.wmType === 'item-check')!;
|
||||||
;(itemCheck as ItemCheckWidget).maps.showNewStats = false
|
(itemCheck as ItemCheckWidget).maps.showNewStats = false
|
||||||
itemCheck.maps.selectedStats = (itemCheck as ItemCheckWidget).maps.selectedStats.map(entry => ({
|
itemCheck.maps.selectedStats = (
|
||||||
|
itemCheck as ItemCheckWidget
|
||||||
|
).maps.selectedStats.map((entry) => ({
|
||||||
matcher: entry.matcher,
|
matcher: entry.matcher,
|
||||||
decision:
|
decision: (entry as any).valueDanger
|
||||||
(entry as any).valueDanger ? 'danger'
|
? 'danger'
|
||||||
: (entry as any).valueWarning ? 'warning'
|
: (entry as any).valueWarning
|
||||||
: (entry as any).valueDesirable ? 'desirable'
|
? 'warning'
|
||||||
: 'seen'
|
: (entry as any).valueDesirable
|
||||||
|
? 'desirable'
|
||||||
|
: 'seen'
|
||||||
}))
|
}))
|
||||||
|
|
||||||
config.configVersion = 8
|
config.configVersion = 8
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.configVersion < 9) {
|
if (config.configVersion < 9) {
|
||||||
config.widgets.find(w => w.wmType === 'price-check')!
|
config.widgets.find((w) => w.wmType === 'price-check')!.collapseListings =
|
||||||
.collapseListings = 'api'
|
'api'
|
||||||
|
|
||||||
config.widgets.find(w => w.wmType === 'price-check')!
|
config.widgets.find((w) => w.wmType === 'price-check')!.smartInitialSearch =
|
||||||
.smartInitialSearch = true
|
true
|
||||||
config.widgets.find(w => w.wmType === 'price-check')!
|
config.widgets.find(
|
||||||
.lockedInitialSearch = true
|
(w) => w.wmType === 'price-check'
|
||||||
|
)!.lockedInitialSearch = true
|
||||||
|
|
||||||
config.widgets.find(w => w.wmType === 'price-check')!
|
config.widgets.find(
|
||||||
.activateStockFilter = false
|
(w) => w.wmType === 'price-check'
|
||||||
|
)!.activateStockFilter = false
|
||||||
|
|
||||||
config.configVersion = 9
|
config.configVersion = 9
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.configVersion < 10) {
|
if (config.configVersion < 10) {
|
||||||
config.widgets.push({
|
config.widgets.push({
|
||||||
...defaultConfig().widgets.find(w => w.wmType === 'settings')!,
|
...defaultConfig().widgets.find((w) => w.wmType === 'settings')!,
|
||||||
wmId: Math.max(0, ...config.widgets.map(_ => _.wmId)) + 1
|
wmId: Math.max(0, ...config.widgets.map((_) => _.wmId)) + 1
|
||||||
})
|
})
|
||||||
|
|
||||||
const priceCheck = config.widgets.find(w => w.wmType === 'price-check')!
|
const priceCheck = config.widgets.find((w) => w.wmType === 'price-check')!
|
||||||
priceCheck.hotkey = (config as any).priceCheckKey
|
priceCheck.hotkey = (config as any).priceCheckKey
|
||||||
priceCheck.hotkeyHold = (config as any).priceCheckKeyHold
|
priceCheck.hotkeyHold = (config as any).priceCheckKeyHold
|
||||||
priceCheck.hotkeyLocked = (config as any).priceCheckLocked
|
priceCheck.hotkeyLocked = (config as any).priceCheckLocked
|
||||||
@@ -449,22 +472,25 @@ function upgradeConfig (_config: Config): Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (config.configVersion < 11) {
|
if (config.configVersion < 11) {
|
||||||
config.widgets.find(w => w.wmType === 'price-check')!
|
config.widgets.find(
|
||||||
.requestPricePrediction = false
|
(w) => w.wmType === 'price-check'
|
||||||
|
)!.requestPricePrediction = false
|
||||||
|
|
||||||
config.configVersion = 11
|
config.configVersion = 11
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.configVersion < 12) {
|
if (config.configVersion < 12) {
|
||||||
const afterSettings = config.widgets.findIndex(w => w.wmType === 'settings')
|
const afterSettings = config.widgets.findIndex(
|
||||||
|
(w) => w.wmType === 'settings'
|
||||||
|
)
|
||||||
config.widgets.splice(afterSettings + 1, 0, {
|
config.widgets.splice(afterSettings + 1, 0, {
|
||||||
...defaultConfig().widgets.find(w => w.wmType === 'item-search')!,
|
...defaultConfig().widgets.find((w) => w.wmType === 'item-search')!,
|
||||||
wmWants: 'show',
|
wmWants: 'show',
|
||||||
wmId: Math.max(0, ...config.widgets.map(_ => _.wmId)) + 1
|
wmId: Math.max(0, ...config.widgets.map((_) => _.wmId)) + 1
|
||||||
})
|
})
|
||||||
|
|
||||||
config.realm = 'pc-ggg'
|
config.realm = 'pc-ggg'
|
||||||
if (config.language === 'zh_TW' as string) {
|
if (config.language === ('zh_TW' as string)) {
|
||||||
config.language = 'cmn-Hant'
|
config.language = 'cmn-Hant'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,7 +504,9 @@ function upgradeConfig (_config: Config): Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (config.configVersion < 14) {
|
if (config.configVersion < 14) {
|
||||||
const imgWidgets = config.widgets.filter(w => w.wmType === 'image-strip') as widget.ImageStripWidget[]
|
const imgWidgets = config.widgets.filter(
|
||||||
|
(w) => w.wmType === 'image-strip'
|
||||||
|
) as widget.ImageStripWidget[]
|
||||||
imgWidgets.forEach((imgStrip) => {
|
imgWidgets.forEach((imgStrip) => {
|
||||||
imgStrip.images.forEach((e) => {
|
imgStrip.images.forEach((e) => {
|
||||||
e.url = e.url.startsWith('app-file://')
|
e.url = e.url.startsWith('app-file://')
|
||||||
@@ -487,7 +515,9 @@ function upgradeConfig (_config: Config): Config {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const itemCheck = config.widgets.find(w => w.wmType === 'item-check') as ItemCheckWidget
|
const itemCheck = config.widgets.find(
|
||||||
|
(w) => w.wmType === 'item-check'
|
||||||
|
) as ItemCheckWidget
|
||||||
itemCheck.wikiKey = (config as any).wikiKey
|
itemCheck.wikiKey = (config as any).wikiKey
|
||||||
itemCheck.poedbKey = null
|
itemCheck.poedbKey = null
|
||||||
itemCheck.craftOfExileKey = (config as any).craftOfExileKey
|
itemCheck.craftOfExileKey = (config as any).craftOfExileKey
|
||||||
@@ -497,19 +527,29 @@ function upgradeConfig (_config: Config): Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (config.configVersion < 15) {
|
if (config.configVersion < 15) {
|
||||||
const priceCheck = config.widgets.find(w => w.wmType === 'price-check') as widget.PriceCheckWidget
|
const priceCheck = config.widgets.find(
|
||||||
|
(w) => w.wmType === 'price-check'
|
||||||
|
) as widget.PriceCheckWidget
|
||||||
priceCheck.builtinBrowser = false
|
priceCheck.builtinBrowser = false
|
||||||
|
|
||||||
const itemSearch = config.widgets.find(w => w.wmType === 'item-search') as ItemSearchWidget
|
const itemSearch = config.widgets.find(
|
||||||
|
(w) => w.wmType === 'item-search'
|
||||||
|
) as ItemSearchWidget
|
||||||
itemSearch.ocrGemsKey = null
|
itemSearch.ocrGemsKey = null
|
||||||
|
|
||||||
const itemCheck = config.widgets.find(w => w.wmType === 'item-check') as ItemCheckWidget
|
const itemCheck = config.widgets.find(
|
||||||
|
(w) => w.wmType === 'item-check'
|
||||||
|
) as ItemCheckWidget
|
||||||
itemCheck.maps.profile = 1
|
itemCheck.maps.profile = 1
|
||||||
for (const stat of itemCheck.maps.selectedStats) {
|
for (const stat of itemCheck.maps.selectedStats) {
|
||||||
const p1decision =
|
const p1decision =
|
||||||
(stat.decision === 'danger') ? 'd'
|
stat.decision === 'danger'
|
||||||
: (stat.decision === 'warning') ? 'w'
|
? 'd'
|
||||||
: (stat.decision === 'desirable') ? 'g' : 's'
|
: stat.decision === 'warning'
|
||||||
|
? 'w'
|
||||||
|
: stat.decision === 'desirable'
|
||||||
|
? 'g'
|
||||||
|
: 's'
|
||||||
|
|
||||||
stat.decision = `${p1decision}--`
|
stat.decision = `${p1decision}--`
|
||||||
}
|
}
|
||||||
@@ -518,10 +558,14 @@ function upgradeConfig (_config: Config): Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (config.configVersion < 16) {
|
if (config.configVersion < 16) {
|
||||||
const delve = config.widgets.find(w => w.wmType === 'delve-grid') as widget.DelveGridWidget
|
const delve = config.widgets.find(
|
||||||
|
(w) => w.wmType === 'delve-grid'
|
||||||
|
) as widget.DelveGridWidget
|
||||||
delve.toggleKey = (config as any).delveGridKey
|
delve.toggleKey = (config as any).delveGridKey
|
||||||
|
|
||||||
const itemCheck = config.widgets.find(w => w.wmType === 'item-check') as ItemCheckWidget
|
const itemCheck = config.widgets.find(
|
||||||
|
(w) => w.wmType === 'item-check'
|
||||||
|
) as ItemCheckWidget
|
||||||
itemCheck.hotkey = (config as any).itemCheckKey
|
itemCheck.hotkey = (config as any).itemCheckKey
|
||||||
|
|
||||||
if (itemCheck.maps.profile === undefined) {
|
if (itemCheck.maps.profile === undefined) {
|
||||||
@@ -536,7 +580,9 @@ function upgradeConfig (_config: Config): Config {
|
|||||||
config.logKeys = false
|
config.logKeys = false
|
||||||
}
|
}
|
||||||
|
|
||||||
const priceCheck = config.widgets.find(w => w.wmType === 'price-check') as widget.PriceCheckWidget
|
const priceCheck = config.widgets.find(
|
||||||
|
(w) => w.wmType === 'price-check'
|
||||||
|
) as widget.PriceCheckWidget
|
||||||
if (priceCheck.rememberCurrency === undefined) {
|
if (priceCheck.rememberCurrency === undefined) {
|
||||||
priceCheck.rememberCurrency = false
|
priceCheck.rememberCurrency = false
|
||||||
}
|
}
|
||||||
@@ -616,7 +662,11 @@ function getConfigForHost (): HostConfig {
|
|||||||
if (command.hotkey) {
|
if (command.hotkey) {
|
||||||
actions.push({
|
actions.push({
|
||||||
shortcut: command.hotkey,
|
shortcut: command.hotkey,
|
||||||
action: { type: 'paste-in-chat', text: command.text, send: command.send }
|
action: {
|
||||||
|
type: 'paste-in-chat',
|
||||||
|
text: command.text,
|
||||||
|
send: command.send
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { computed, shallowRef, readonly } from 'vue'
|
import { computed, shallowRef, readonly } from 'vue'
|
||||||
import { createGlobalState } from '@vueuse/core'
|
import { createGlobalState } from '@vueuse/core'
|
||||||
import { AppConfig, poeWebApi } from '@/web/Config'
|
import { AppConfig } from '@/web/Config'
|
||||||
import { Host } from './IPC'
|
|
||||||
|
|
||||||
// pc-ggg, pc-garena
|
// pc-ggg, pc-garena
|
||||||
// const PERMANENT_SC = ['Standard', '標準模式']
|
// const PERMANENT_SC = ['Standard', '標準模式']
|
||||||
@@ -23,11 +22,21 @@ export const useLeagues = createGlobalState(() => {
|
|||||||
const error = shallowRef<string | null>(null)
|
const error = shallowRef<string | null>(null)
|
||||||
const tradeLeagues = shallowRef<League[]>([])
|
const tradeLeagues = shallowRef<League[]>([])
|
||||||
|
|
||||||
|
const DEFAULT_POE2_LEAGUES: ApiLeague[] = [
|
||||||
|
{ id: 'Standard', rules: [] },
|
||||||
|
{
|
||||||
|
id: 'Hardcore',
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
id: 'Hardcore'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
const selectedId = computed<string | undefined>({
|
const selectedId = computed<string | undefined>({
|
||||||
get () {
|
get () {
|
||||||
return (tradeLeagues.value.length)
|
return tradeLeagues.value.length ? AppConfig().leagueId : undefined
|
||||||
? AppConfig().leagueId
|
|
||||||
: undefined
|
|
||||||
},
|
},
|
||||||
set (id) {
|
set (id) {
|
||||||
AppConfig().leagueId = id
|
AppConfig().leagueId = id
|
||||||
@@ -37,7 +46,7 @@ export const useLeagues = createGlobalState(() => {
|
|||||||
const selected = computed(() => {
|
const selected = computed(() => {
|
||||||
const { leagueId } = AppConfig()
|
const { leagueId } = AppConfig()
|
||||||
if (!tradeLeagues.value || !leagueId) return undefined
|
if (!tradeLeagues.value || !leagueId) return undefined
|
||||||
const listed = tradeLeagues.value.find(league => league.id === leagueId)
|
const listed = tradeLeagues.value.find((league) => league.id === leagueId)
|
||||||
return {
|
return {
|
||||||
id: leagueId,
|
id: leagueId,
|
||||||
realm: AppConfig().realm,
|
realm: AppConfig().realm,
|
||||||
@@ -50,19 +59,30 @@ export const useLeagues = createGlobalState(() => {
|
|||||||
error.value = null
|
error.value = null
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await Host.proxy(`${poeWebApi()}/api/leagues?type=main&realm=pc`)
|
// const response = await Host.proxy(
|
||||||
if (!response.ok) throw new Error(JSON.stringify(Object.fromEntries(response.headers)))
|
// `${poeWebApi()}/api/leagues?type=main&realm=pc`
|
||||||
const leagues: ApiLeague[] = await response.json()
|
// );
|
||||||
|
// if (!response.ok)
|
||||||
|
// throw new Error(JSON.stringify(Object.fromEntries(response.headers)));
|
||||||
|
// const leagues: ApiLeague[] = await response.json();
|
||||||
|
const leagues: ApiLeague[] = DEFAULT_POE2_LEAGUES
|
||||||
tradeLeagues.value = leagues
|
tradeLeagues.value = leagues
|
||||||
.filter(league =>
|
.filter(
|
||||||
!PERMANENT_HC.includes(league.id) &&
|
(league) =>
|
||||||
!league.rules.some(rule => rule.id === 'NoParties' ||
|
!PERMANENT_HC.includes(league.id) &&
|
||||||
(rule.id === 'HardMode' && !league.event)))
|
!league.rules.some(
|
||||||
.map(league => {
|
(rule) =>
|
||||||
|
rule.id === 'NoParties' ||
|
||||||
|
(rule.id === 'HardMode' && !league.event)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.map((league) => {
|
||||||
return { id: league.id, isPopular: true }
|
return { id: league.id, isPopular: true }
|
||||||
})
|
})
|
||||||
|
|
||||||
const leagueIsAlive = tradeLeagues.value.some(league => league.id === selectedId.value)
|
const leagueIsAlive = tradeLeagues.value.some(
|
||||||
|
(league) => league.id === selectedId.value
|
||||||
|
)
|
||||||
if (!leagueIsAlive && !isPrivateLeague(selectedId.value ?? '')) {
|
if (!leagueIsAlive && !isPrivateLeague(selectedId.value ?? '')) {
|
||||||
if (tradeLeagues.value.length > 1) {
|
if (tradeLeagues.value.length > 1) {
|
||||||
const TMP_CHALLENGE = 1
|
const TMP_CHALLENGE = 1
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
<div class="bg-orange-400 text-gray-900 text-center text-sm font-bold text-shadow-lg">
|
||||||
|
This is in BETA for POE2, things do not work as expected. Please report any issues.
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<Widget :config="{ ...config, anchor }" move-handles="none" :removable="false" :inline-edit="false">
|
<Widget :config="{ ...config, anchor }" move-handles="none" :removable="false" :inline-edit="false">
|
||||||
<template v-if="item">
|
<template v-if="item">
|
||||||
<MapCheck v-if="isMapLike"
|
<ConversionWarningBanner />
|
||||||
:item="item" :config="config.maps" />
|
<MapCheck v-if="isMapLike" :item="item" :config="config.maps" />
|
||||||
<ItemInfo v-else
|
<ItemInfo v-else :item="item" />
|
||||||
:item="item" />
|
|
||||||
</template>
|
</template>
|
||||||
</Widget>
|
</Widget>
|
||||||
</template>
|
</template>
|
||||||
@@ -20,6 +19,7 @@ import type { ItemCheckWidget } from './widget.js'
|
|||||||
import Widget from '../overlay/Widget.vue'
|
import Widget from '../overlay/Widget.vue'
|
||||||
import MapCheck from '../map-check/MapCheck.vue'
|
import MapCheck from '../map-check/MapCheck.vue'
|
||||||
import ItemInfo from './ItemInfo.vue'
|
import ItemInfo from './ItemInfo.vue'
|
||||||
|
import ConversionWarningBanner from '../conversion-warn-banner/ConversionWarningBanner.vue'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
config: ItemCheckWidget
|
config: ItemCheckWidget
|
||||||
|
|||||||
@@ -6,7 +6,14 @@ const POEDB_LANGS = { 'en': 'us', 'ru': 'ru', 'cmn-Hant': 'tw', 'ko': 'kr' }
|
|||||||
|
|
||||||
export function registerActions () {
|
export function registerActions () {
|
||||||
Host.onEvent('MAIN->CLIENT::item-text', (e) => {
|
Host.onEvent('MAIN->CLIENT::item-text', (e) => {
|
||||||
if (!['open-wiki', 'open-craft-of-exile', 'open-poedb', 'search-similar'].includes(e.target)) return
|
if (
|
||||||
|
![
|
||||||
|
'open-wiki',
|
||||||
|
'open-craft-of-exile',
|
||||||
|
'open-poedb',
|
||||||
|
'search-similar'
|
||||||
|
].includes(e.target)
|
||||||
|
) { return }
|
||||||
const parsed = parseClipboard(e.clipboard)
|
const parsed = parseClipboard(e.clipboard)
|
||||||
if (!parsed.isOk()) return
|
if (!parsed.isOk()) return
|
||||||
|
|
||||||
@@ -23,14 +30,18 @@ export function registerActions () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function openWiki (item: ParsedItem) {
|
export function openWiki (item: ParsedItem) {
|
||||||
window.open(`https://www.poewiki.net/wiki/${item.info.refName}`)
|
window.open(`https://www.poe2wiki.net/wiki/${item.info.refName}`)
|
||||||
}
|
}
|
||||||
export function openPoedb (item: ParsedItem) {
|
export function openPoedb (item: ParsedItem) {
|
||||||
window.open(`https://poedb.tw/${POEDB_LANGS[AppConfig().language]}/search?q=${item.info.refName}`)
|
window.open(
|
||||||
|
`https://poe2db.tw/${POEDB_LANGS[AppConfig().language]}/search?q=${item.info.refName}`
|
||||||
|
)
|
||||||
}
|
}
|
||||||
export function openCoE (item: ParsedItem) {
|
export function openCoE (item: ParsedItem) {
|
||||||
const encodedClipboard = encodeURIComponent(item.rawText)
|
const encodedClipboard = encodeURIComponent(item.rawText)
|
||||||
window.open(`https://craftofexile.com/?eimport=${encodedClipboard}`)
|
window.open(
|
||||||
|
`https://craftofexile.com/?game=poe2&eimport=${encodedClipboard}`
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findSimilarItems (item: ParsedItem) {
|
export function findSimilarItems (item: ParsedItem) {
|
||||||
|
|||||||
@@ -5,12 +5,8 @@
|
|||||||
<div class="flex-1 text-center">{{ mapName }}</div>
|
<div class="flex-1 text-center">{{ mapName }}</div>
|
||||||
<div class="ml-8 text-gray-400">{{ t('map_check.profile') }}</div>
|
<div class="ml-8 text-gray-400">{{ t('map_check.profile') }}</div>
|
||||||
<div class="flex gap-0.5">
|
<div class="flex gap-0.5">
|
||||||
<button
|
<button v-for="profile in profiles" :key="profile.text" @click="profile.select"
|
||||||
v-for="profile in profiles" :key="profile.text"
|
:class="{ 'border border-gray-600': profile.active }" class="w-6 bg-gray-800">{{ profile.text }}</button>
|
||||||
@click="profile.select"
|
|
||||||
:class="{ 'border border-gray-600': profile.active }"
|
|
||||||
class="w-6 bg-gray-800"
|
|
||||||
>{{ profile.text }}</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<FullscreenImage v-if="image" :src="image" style="height: auto;" />
|
<FullscreenImage v-if="image" :src="image" style="height: auto;" />
|
||||||
@@ -18,10 +14,8 @@
|
|||||||
{{ t('map_check.no_mods') }}
|
{{ t('map_check.no_mods') }}
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="py-2 flex flex-col">
|
<div v-else class="py-2 flex flex-col">
|
||||||
<MapStatButton v-for="stat in mapStats" :key="stat.matcher"
|
<MapStatButton v-for="stat in mapStats" :key="stat.matcher" :stat="stat" :config="config" />
|
||||||
:stat="stat" :config="config" />
|
<div v-for="stat of item.unknownModifiers" :key="stat.type + '/' + stat.text" class="py-1 px-8">
|
||||||
<div v-for="stat of item.unknownModifiers" :key="stat.type + '/' + stat.text"
|
|
||||||
class="py-1 px-8">
|
|
||||||
<span class="text-orange-400">{{ t('Not recognized modifier') }} —</span> {{ stat.text }}
|
<span class="text-orange-400">{{ t('Not recognized modifier') }} —</span> {{ stat.text }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<transition
|
<transition enter-active-class="animate__animated animate__fadeIn"
|
||||||
enter-active-class="animate__animated animate__fadeIn"
|
|
||||||
leave-active-class="animate__animated animate__backOutDown">
|
leave-active-class="animate__animated animate__backOutDown">
|
||||||
<div :class="$style.widget" v-if="show">
|
<div :class="$style.widget" v-if="show">
|
||||||
<div :class="$style.box">
|
<div :class="$style.box">
|
||||||
<div class="py-2 px-4">
|
<div class="py-2 px-4">
|
||||||
<div class="text-base">Awakened PoE Trade</div>
|
<div class="text-base">Exiled Exchange 2</div>
|
||||||
<p>{{ t('app_is_ready') }}</p>
|
<p>{{ t('app_is_ready') }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -26,7 +25,9 @@ const show = shallowRef(false)
|
|||||||
Host.onEvent('MAIN->OVERLAY::overlay-attached', () => {
|
Host.onEvent('MAIN->OVERLAY::overlay-attached', () => {
|
||||||
if (!show.value && AppConfig().showAttachNotification) {
|
if (!show.value && AppConfig().showAttachNotification) {
|
||||||
show.value = true
|
show.value = true
|
||||||
setTimeout(() => { show.value = false }, 2500)
|
setTimeout(() => {
|
||||||
|
show.value = false
|
||||||
|
}, 2500)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@@ -52,7 +53,7 @@ Host.onEvent('MAIN->OVERLAY::overlay-attached', () => {
|
|||||||
.box::before {
|
.box::before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
content: '';
|
content: '';
|
||||||
background: url('/images/TransferOrb.png') no-repeat top right/contain;
|
background: url('/images/exa.png') no-repeat top right/contain;
|
||||||
right: 100%;
|
right: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<widget :config="config" :hideable="false" :removable="false" move-handles="corners" v-slot="{ isEditing }">
|
<widget :config="config" :hideable="false" :removable="false" move-handles="corners" v-slot="{ isEditing }">
|
||||||
<div class="widget-default-style">
|
<div class="widget-default-style">
|
||||||
|
<ConversionWarningBanner />
|
||||||
<div class="p-1 flex gap-1 items-center text-base">
|
<div class="p-1 flex gap-1 items-center text-base">
|
||||||
<template v-for="widget in widgets" :key="widget.wmId">
|
<template v-for="widget in widgets" :key="widget.wmId">
|
||||||
<button @click="toggle(widget)"
|
<button @click="toggle(widget)" :class="widget.wmWants === 'show' ? 'border-gray-500' : 'border-gray-800'"
|
||||||
:class="widget.wmWants === 'show' ? 'border-gray-500' : 'border-gray-800'"
|
class="bg-gray-800 rounded text-gray-100 p-2 leading-none whitespace-nowrap border">
|
||||||
class="bg-gray-800 rounded text-gray-100 p-2 leading-none whitespace-nowrap border"
|
|
||||||
>
|
|
||||||
<i v-if="widget.wmType === 'settings'" class="fas fa-cog align-bottom" />
|
<i v-if="widget.wmType === 'settings'" class="fas fa-cog align-bottom" />
|
||||||
<i v-else-if="widget.wmType === 'item-search'" class="fas fa-search align-bottom" />
|
<i v-else-if="widget.wmType === 'item-search'" class="fas fa-search align-bottom" />
|
||||||
<template v-else>{{ widget.wmTitle || `#${widget.wmId}` }}</template>
|
<template v-else>{{ widget.wmTitle || `#${widget.wmId}` }}</template>
|
||||||
@@ -22,9 +21,12 @@
|
|||||||
<!-- <button class="text-left hover:bg-gray-400 rounded px-1 whitespace-nowrap">Screen saver</button> -->
|
<!-- <button class="text-left hover:bg-gray-400 rounded px-1 whitespace-nowrap">Screen saver</button> -->
|
||||||
<!-- add widget -->
|
<!-- add widget -->
|
||||||
<div class="text-gray-600 text-sm px-1 select-none whitespace-nowrap">{{ t(':add') }}</div>
|
<div class="text-gray-600 text-sm px-1 select-none whitespace-nowrap">{{ t(':add') }}</div>
|
||||||
<button class="text-left hover:bg-gray-400 rounded px-1 whitespace-nowrap" @click="createOfType('timer')">{{ t('stopwatch.name') }}</button>
|
<button class="text-left hover:bg-gray-400 rounded px-1 whitespace-nowrap"
|
||||||
<button class="text-left hover:bg-gray-400 rounded px-1 whitespace-nowrap" @click="createOfType('stash-search')">{{ t('stash_search.name') }}</button>
|
@click="createOfType('timer')">{{ t('stopwatch.name') }}</button>
|
||||||
<button class="text-left hover:bg-gray-400 rounded px-1 whitespace-nowrap" @click="createOfType('image-strip')">{{ t('image_strip.name') }}</button>
|
<button class="text-left hover:bg-gray-400 rounded px-1 whitespace-nowrap"
|
||||||
|
@click="createOfType('stash-search')">{{ t('stash_search.name') }}</button>
|
||||||
|
<button class="text-left hover:bg-gray-400 rounded px-1 whitespace-nowrap"
|
||||||
|
@click="createOfType('image-strip')">{{ t('image_strip.name') }}</button>
|
||||||
<!-- <button class="text-left hover:bg-gray-400 rounded px-1 whitespace-nowrap" @click="createOfType('TODO')">Image</button> -->
|
<!-- <button class="text-left hover:bg-gray-400 rounded px-1 whitespace-nowrap" @click="createOfType('TODO')">Image</button> -->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -34,8 +36,7 @@
|
|||||||
<ui-toggle v-model="config.alwaysShow">{{ t(':always_show') }}</ui-toggle>
|
<ui-toggle v-model="config.alwaysShow">{{ t(':always_show') }}</ui-toggle>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="px-1 pb-1">
|
<div v-else class="px-1 pb-1">
|
||||||
<textarea class="px-2 py-1.5 bg-gray-700 rounded resize-none block"
|
<textarea class="px-2 py-1.5 bg-gray-700 rounded resize-none block" rows="1" spellcheck="false"
|
||||||
rows="1" spellcheck="false"
|
|
||||||
:placeholder="t(':price_check')" @input="handleItemPaste"></textarea>
|
:placeholder="t(':price_check')" @input="handleItemPaste"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -50,9 +51,10 @@ import { Widget as IWidget, WidgetManager, WidgetMenu } from './interfaces'
|
|||||||
import { Host } from '@/web/background/IPC'
|
import { Host } from '@/web/background/IPC'
|
||||||
import Widget from './Widget.vue'
|
import Widget from './Widget.vue'
|
||||||
import { useI18nNs } from '@/web/i18n'
|
import { useI18nNs } from '@/web/i18n'
|
||||||
|
import ConversionWarningBanner from '../conversion-warn-banner/ConversionWarningBanner.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { Widget, UiToggle, UiPopover },
|
components: { Widget, UiToggle, UiPopover, ConversionWarningBanner },
|
||||||
props: {
|
props: {
|
||||||
config: {
|
config: {
|
||||||
type: Object as PropType<WidgetMenu>,
|
type: Object as PropType<WidgetMenu>,
|
||||||
|
|||||||
@@ -1,42 +1,24 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="show" class="p-4 layout-column min-h-0">
|
<div v-if="show" class="p-4 layout-column min-h-0">
|
||||||
<filter-name
|
<filter-name :filters="itemFilters" :item="item" />
|
||||||
:filters="itemFilters"
|
<price-prediction v-if="showPredictedPrice" class="mb-4" :item="item" />
|
||||||
:item="item" />
|
<price-trend v-else :item="item" :filters="itemFilters" />
|
||||||
<price-prediction v-if="showPredictedPrice" class="mb-4"
|
<filters-block ref="filtersComponent" :filters="itemFilters" :stats="itemStats" :item="item" :presets="presets"
|
||||||
:item="item" />
|
@preset="selectPreset" @submit="doSearch = true" />
|
||||||
<price-trend v-else
|
<trade-listing v-if="tradeAPI === 'trade' && doSearch" ref="tradeService" :filters="itemFilters" :stats="itemStats"
|
||||||
:item="item"
|
|
||||||
:filters="itemFilters" />
|
|
||||||
<filters-block
|
|
||||||
ref="filtersComponent"
|
|
||||||
:filters="itemFilters"
|
|
||||||
:stats="itemStats"
|
|
||||||
:item="item"
|
|
||||||
:presets="presets"
|
|
||||||
@preset="selectPreset"
|
|
||||||
@submit="doSearch = true" />
|
|
||||||
<trade-listing
|
|
||||||
v-if="tradeAPI === 'trade' && doSearch"
|
|
||||||
ref="tradeService"
|
|
||||||
:filters="itemFilters"
|
|
||||||
:stats="itemStats"
|
|
||||||
:item="item" />
|
|
||||||
<trade-bulk
|
|
||||||
v-if="tradeAPI === 'bulk' && doSearch"
|
|
||||||
ref="tradeService"
|
|
||||||
:filters="itemFilters"
|
|
||||||
:item="item" />
|
:item="item" />
|
||||||
|
<trade-bulk v-if="tradeAPI === 'bulk' && doSearch" ref="tradeService" :filters="itemFilters" :item="item" />
|
||||||
<div v-if="!doSearch" class="flex justify-between items-center">
|
<div v-if="!doSearch" class="flex justify-between items-center">
|
||||||
<div class="flex w-40" @mouseenter="handleSearchMouseenter">
|
<div class="flex w-40" @mouseenter="handleSearchMouseenter">
|
||||||
<button class="btn" @click="doSearch = true" style="min-width: 5rem;">{{ t('Search') }}</button>
|
<button class="btn" @click="doSearch = true" style="min-width: 5rem;">{{ t('Search') }}</button>
|
||||||
</div>
|
</div>
|
||||||
<trade-links v-if="tradeAPI === 'trade'"
|
<trade-links v-if="tradeAPI === 'trade'" :get-link="makeTradeLink" />
|
||||||
:get-link="makeTradeLink" />
|
|
||||||
</div>
|
</div>
|
||||||
<stack-value :filters="itemFilters" :item="item"/>
|
<stack-value :filters="itemFilters" :item="item" />
|
||||||
<div v-if="showSupportLinks" class="mt-auto border border-dashed p-2">
|
<div v-if="showSupportLinks" class="mt-auto border border-dashed p-2">
|
||||||
<div class="mb-1">{{ t('Support development on') }} <a href="https://patreon.com/awakened_poe_trade" class="inline-flex align-middle animate__animated animate__fadeInRight" target="_blank"><img class="inline h-5" src="/images/Patreon.svg"></a></div>
|
<div class="mb-1">{{ t('Support development on') }} <a href="https://patreon.com/awakened_poe_trade"
|
||||||
|
class="inline-flex align-middle animate__animated animate__fadeInRight" target="_blank"><img
|
||||||
|
class="inline h-5" src="/images/Patreon.svg"></a></div>
|
||||||
<i18n-t keypath="app.thanks_3rd_party" tag="div">
|
<i18n-t keypath="app.thanks_3rd_party" tag="div">
|
||||||
<a href="https://poeprices.info" target="_blank" class="bg-gray-900 px-1 rounded">poeprices.info</a>
|
<a href="https://poeprices.info" target="_blank" class="bg-gray-900 px-1 rounded">poeprices.info</a>
|
||||||
<a href="https://poe.ninja/support" target="_blank" class="bg-gray-900 px-1 rounded">poe.ninja</a>
|
<a href="https://poe.ninja/support" target="_blank" class="bg-gray-900 px-1 rounded">poe.ninja</a>
|
||||||
@@ -120,7 +102,7 @@ export default defineComponent({
|
|||||||
})
|
})
|
||||||
|
|
||||||
if ((!props.advancedCheck && !widget.value.smartInitialSearch) ||
|
if ((!props.advancedCheck && !widget.value.smartInitialSearch) ||
|
||||||
(props.advancedCheck && !widget.value.lockedInitialSearch)) {
|
(props.advancedCheck && !widget.value.lockedInitialSearch)) {
|
||||||
doSearch.value = false
|
doSearch.value = false
|
||||||
} else {
|
} else {
|
||||||
doSearch.value = Boolean(
|
doSearch.value = Boolean(
|
||||||
@@ -174,8 +156,8 @@ export default defineComponent({
|
|||||||
|
|
||||||
const showPredictedPrice = computed(() => {
|
const showPredictedPrice = computed(() => {
|
||||||
if (!widget.value.requestPricePrediction ||
|
if (!widget.value.requestPricePrediction ||
|
||||||
AppConfig().language !== 'en' ||
|
AppConfig().language !== 'en' ||
|
||||||
!leagues.selected.value!.isPopular) return false
|
!leagues.selected.value!.isPopular) return false
|
||||||
|
|
||||||
if (presets.value.active === 'filters.preset_base_item') return false
|
if (presets.value.active === 'filters.preset_base_item') return false
|
||||||
|
|
||||||
@@ -238,7 +220,7 @@ export default defineComponent({
|
|||||||
presets.value.active = id
|
presets.value.active = id
|
||||||
},
|
},
|
||||||
makeTradeLink () {
|
makeTradeLink () {
|
||||||
return `https://${getTradeEndpoint()}/trade/search/${itemFilters.value.trade.league}?q=${JSON.stringify(createTradeRequest(itemFilters.value, itemStats.value, props.item))}`
|
return `https://${getTradeEndpoint()}/trade2/search/poe2/${itemFilters.value.trade.league}?q=${JSON.stringify(createTradeRequest(itemFilters.value, itemStats.value, props.item))}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,52 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
style="top: 0; left: 0; height: 100%; width: 100%; position: absolute;"
|
style="top: 0; left: 0; height: 100%; width: 100%; position: absolute"
|
||||||
class="flex grow h-full pointer-events-none" :class="{
|
class="flex grow h-full pointer-events-none"
|
||||||
'flex-row': clickPosition === 'stash',
|
:class="{
|
||||||
'flex-row-reverse': clickPosition === 'inventory',
|
'flex-row': clickPosition === 'stash',
|
||||||
}">
|
'flex-row-reverse': clickPosition === 'inventory',
|
||||||
<div v-if="!isBrowserShown" class="layout-column shrink-0"
|
}"
|
||||||
style="width: var(--game-panel);">
|
>
|
||||||
</div>
|
<div
|
||||||
<div id="price-window" class="layout-column shrink-0 text-gray-200 pointer-events-auto" style="width: 28.75rem;">
|
v-if="!isBrowserShown"
|
||||||
<AppTitleBar @close="closePriceCheck" @click="openLeagueSelection" :title="title">
|
class="layout-column shrink-0"
|
||||||
<ui-popover v-if="stableOrbCost" trigger="click" boundary="#price-window">
|
style="width: var(--game-panel)"
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
id="price-window"
|
||||||
|
class="layout-column shrink-0 text-gray-200 pointer-events-auto"
|
||||||
|
style="width: 28.75rem"
|
||||||
|
>
|
||||||
|
<ConversionWarningBanner />
|
||||||
|
<AppTitleBar
|
||||||
|
@close="closePriceCheck"
|
||||||
|
@click="openLeagueSelection"
|
||||||
|
:title="title"
|
||||||
|
>
|
||||||
|
<ui-popover
|
||||||
|
v-if="stableOrbCost"
|
||||||
|
trigger="click"
|
||||||
|
boundary="#price-window"
|
||||||
|
>
|
||||||
<template #target>
|
<template #target>
|
||||||
<button><i class="fas fa-exchange-alt" /> {{ stableOrbCost }}</button>
|
<button>
|
||||||
|
<i class="fas fa-exchange-alt" /> {{ stableOrbCost }}
|
||||||
|
</button>
|
||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #content>
|
||||||
<item-quick-price class="text-base"
|
<item-quick-price
|
||||||
:price="{ min: stableOrbCost, max: stableOrbCost, currency: 'chaos' }"
|
class="text-base"
|
||||||
|
:price="{
|
||||||
|
min: stableOrbCost,
|
||||||
|
max: stableOrbCost,
|
||||||
|
currency: 'chaos',
|
||||||
|
}"
|
||||||
item-img="/images/divine.png"
|
item-img="/images/divine.png"
|
||||||
/>
|
/>
|
||||||
<div v-for="i in 9" :key="i">
|
<div v-for="i in 9" :key="i">
|
||||||
<div class="pl-1">{{ i / 10 }} div ⇒ {{ Math.round(stableOrbCost * i / 10) }} c</div>
|
<div class="pl-1">
|
||||||
|
{{ i / 10 }} div ⇒ {{ Math.round((stableOrbCost * i) / 10) }} c
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</ui-popover>
|
</ui-popover>
|
||||||
@@ -29,37 +55,61 @@
|
|||||||
</AppTitleBar>
|
</AppTitleBar>
|
||||||
<div class="grow layout-column min-h-0 bg-gray-800">
|
<div class="grow layout-column min-h-0 bg-gray-800">
|
||||||
<background-info />
|
<background-info />
|
||||||
<check-position-circle v-if="showCheckPos"
|
<check-position-circle
|
||||||
:position="checkPosition" style="z-index: -1;" />
|
v-if="showCheckPos"
|
||||||
|
:position="checkPosition"
|
||||||
|
style="z-index: -1"
|
||||||
|
/>
|
||||||
<template v-if="item?.isErr()">
|
<template v-if="item?.isErr()">
|
||||||
<ui-error-box class="m-4">
|
<ui-error-box class="m-4">
|
||||||
<template #name>{{ t(item.error.name) }}</template>
|
<template #name>{{ t(item.error.name) }}</template>
|
||||||
<p>{{ t(item.error.message) }}</p>
|
<p>{{ t(item.error.message) }}</p>
|
||||||
</ui-error-box>
|
</ui-error-box>
|
||||||
<pre class="bg-gray-900 rounded m-4 overflow-x-hidden p-2">{{ item.error.rawText }}</pre>
|
<pre class="bg-gray-900 rounded m-4 overflow-x-hidden p-2">{{
|
||||||
|
item.error.rawText
|
||||||
|
}}</pre>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="item?.isOk()">
|
<template v-else-if="item?.isOk()">
|
||||||
<unidentified-resolver :item="item.value" @identify="handleIdentification($event)" />
|
<unidentified-resolver
|
||||||
<checked-item v-if="isLeagueSelected"
|
:item="item.value"
|
||||||
:item="item.value" :advanced-check="advancedCheck" />
|
@identify="handleIdentification($event)"
|
||||||
|
/>
|
||||||
|
<checked-item
|
||||||
|
v-if="isLeagueSelected"
|
||||||
|
:item="item.value"
|
||||||
|
:advanced-check="advancedCheck"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<div v-if="isBrowserShown" class="bg-gray-900 px-6 py-2 truncate">
|
<div v-if="isBrowserShown" class="bg-gray-900 px-6 py-2 truncate">
|
||||||
<i18n-t keypath="app.toggle_browser_hint" tag="div">
|
<i18n-t keypath="app.toggle_browser_hint" tag="div">
|
||||||
<span class="bg-gray-400 text-gray-900 rounded px-1">{{ overlayKey }}</span>
|
<span class="bg-gray-400 text-gray-900 rounded px-1">{{
|
||||||
|
overlayKey
|
||||||
|
}}</span>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<webview v-if="isBrowserShown" ref="iframeEl"
|
<webview
|
||||||
|
v-if="isBrowserShown"
|
||||||
|
ref="iframeEl"
|
||||||
class="pointer-events-auto flex-1"
|
class="pointer-events-auto flex-1"
|
||||||
width="100%" height="100%" />
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
/>
|
||||||
<div v-else class="layout-column flex-1 min-w-0">
|
<div v-else class="layout-column flex-1 min-w-0">
|
||||||
<div class="flex" :class="{
|
<div
|
||||||
'flex-row': clickPosition === 'stash',
|
class="flex"
|
||||||
'flex-row-reverse': clickPosition === 'inventory'
|
:class="{
|
||||||
}">
|
'flex-row': clickPosition === 'stash',
|
||||||
<related-items v-if="item?.isOk()" class="pointer-events-auto"
|
'flex-row-reverse': clickPosition === 'inventory',
|
||||||
:item="item.value" :click-position="clickPosition" />
|
}"
|
||||||
|
>
|
||||||
|
<related-items
|
||||||
|
v-if="item?.isOk()"
|
||||||
|
class="pointer-events-auto"
|
||||||
|
:item="item.value"
|
||||||
|
:click-position="clickPosition"
|
||||||
|
/>
|
||||||
<rate-limiter-state class="pointer-events-auto" />
|
<rate-limiter-state class="pointer-events-auto" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -86,8 +136,13 @@ import CheckPositionCircle from './CheckPositionCircle.vue'
|
|||||||
import AppTitleBar from '@/web/ui/AppTitlebar.vue'
|
import AppTitleBar from '@/web/ui/AppTitlebar.vue'
|
||||||
import ItemQuickPrice from '@/web/ui/ItemQuickPrice.vue'
|
import ItemQuickPrice from '@/web/ui/ItemQuickPrice.vue'
|
||||||
import { PriceCheckWidget, WidgetManager } from '../overlay/interfaces'
|
import { PriceCheckWidget, WidgetManager } from '../overlay/interfaces'
|
||||||
|
import ConversionWarningBanner from '../conversion-warn-banner/ConversionWarningBanner.vue'
|
||||||
|
|
||||||
type ParseError = { name: string; message: string; rawText: ParsedItem['rawText'] }
|
type ParseError = {
|
||||||
|
name: string;
|
||||||
|
message: string;
|
||||||
|
rawText: ParsedItem['rawText'];
|
||||||
|
};
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
@@ -100,7 +155,8 @@ export default defineComponent({
|
|||||||
CheckPositionCircle,
|
CheckPositionCircle,
|
||||||
ItemQuickPrice,
|
ItemQuickPrice,
|
||||||
UiErrorBox,
|
UiErrorBox,
|
||||||
UiPopover
|
UiPopover,
|
||||||
|
ConversionWarningBanner
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
config: {
|
config: {
|
||||||
@@ -127,9 +183,13 @@ export default defineComponent({
|
|||||||
if (Host.isElectron && !e.focusOverlay) {
|
if (Host.isElectron && !e.focusOverlay) {
|
||||||
// everything in CSS pixels
|
// everything in CSS pixels
|
||||||
const width = 28.75 * AppConfig().fontSize
|
const width = 28.75 * AppConfig().fontSize
|
||||||
const screenX = ((e.position.x - window.screenX) > window.innerWidth / 2)
|
const screenX =
|
||||||
? (window.screenX + window.innerWidth) - wm.poePanelWidth.value - width
|
e.position.x - window.screenX > window.innerWidth / 2
|
||||||
: window.screenX + wm.poePanelWidth.value
|
? window.screenX +
|
||||||
|
window.innerWidth -
|
||||||
|
wm.poePanelWidth.value -
|
||||||
|
width
|
||||||
|
: window.screenX + wm.poePanelWidth.value
|
||||||
MainProcess.sendEvent({
|
MainProcess.sendEvent({
|
||||||
name: 'OVERLAY->MAIN::track-area',
|
name: 'OVERLAY->MAIN::track-area',
|
||||||
payload: {
|
payload: {
|
||||||
@@ -151,13 +211,18 @@ export default defineComponent({
|
|||||||
checkPosition.value = e.position
|
checkPosition.value = e.position
|
||||||
advancedCheck.value = e.focusOverlay
|
advancedCheck.value = e.focusOverlay
|
||||||
|
|
||||||
item.value = (e.item ? ok(e.item as ParsedItem) : parseClipboard(e.clipboard))
|
item.value = (
|
||||||
.andThen(item => (
|
e.item ? ok(e.item as ParsedItem) : parseClipboard(e.clipboard)
|
||||||
(item.category === ItemCategory.HeistContract && item.rarity !== ItemRarity.Unique) ||
|
)
|
||||||
(item.category === ItemCategory.Sentinel && item.rarity !== ItemRarity.Unique))
|
.andThen((item) =>
|
||||||
? err('item.unknown')
|
(item.category === ItemCategory.HeistContract &&
|
||||||
: ok(item))
|
item.rarity !== ItemRarity.Unique) ||
|
||||||
.mapErr(err => ({
|
(item.category === ItemCategory.Sentinel &&
|
||||||
|
item.rarity !== ItemRarity.Unique)
|
||||||
|
? err('item.unknown')
|
||||||
|
: ok(item)
|
||||||
|
)
|
||||||
|
.mapErr((err) => ({
|
||||||
name: `${err}`,
|
name: `${err}`,
|
||||||
message: `${err}_help`,
|
message: `${err}_help`,
|
||||||
rawText: e.clipboard
|
rawText: e.clipboard
|
||||||
@@ -176,14 +241,17 @@ export default defineComponent({
|
|||||||
wm.hide(props.config.wmId)
|
wm.hide(props.config.wmId)
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(() => props.config.wmWants, (state) => {
|
watch(
|
||||||
if (state === 'hide') {
|
() => props.config.wmWants,
|
||||||
closeBrowser()
|
(state) => {
|
||||||
|
if (state === 'hide') {
|
||||||
|
closeBrowser()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
)
|
||||||
|
|
||||||
const leagues = useLeagues()
|
const leagues = useLeagues()
|
||||||
const title = computed(() => leagues.selectedId.value || 'Awakened PoE Trade')
|
const title = computed(() => leagues.selectedId.value || 'Exiled Exchange 2')
|
||||||
const stableOrbCost = computed(() => (xchgRate.value) ? Math.round(xchgRate.value) : null)
|
const stableOrbCost = computed(() => (xchgRate.value) ? Math.round(xchgRate.value) : null)
|
||||||
const isBrowserShown = computed(() => props.config.wmFlags.includes('has-browser'))
|
const isBrowserShown = computed(() => props.config.wmFlags.includes('has-browser'))
|
||||||
const overlayKey = computed(() => AppConfig().overlayKey)
|
const overlayKey = computed(() => AppConfig().overlayKey)
|
||||||
@@ -196,7 +264,7 @@ export default defineComponent({
|
|||||||
return checkPosition.value.x > (window.screenX + window.innerWidth / 2)
|
return checkPosition.value.x > (window.screenX + window.innerWidth / 2)
|
||||||
? 'inventory'
|
? 'inventory'
|
||||||
: 'stash'
|
: 'stash'
|
||||||
// or {chat, vendor, center of screen}
|
// or {chat, vendor, center of screen}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ const stats = computed(() => {
|
|||||||
if (!parsed.roll) {
|
if (!parsed.roll) {
|
||||||
return {
|
return {
|
||||||
text: parsed.translation.string,
|
text: parsed.translation.string,
|
||||||
contribution: contribution,
|
contribution,
|
||||||
contributes: true
|
contributes: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ export function createFilters (
|
|||||||
}
|
}
|
||||||
filters.searchRelaxed = {
|
filters.searchRelaxed = {
|
||||||
category: item.category,
|
category: item.category,
|
||||||
disabled: disabled
|
disabled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ export function calculatedStatToFilter (
|
|||||||
? FilterTag.Enchant
|
? FilterTag.Enchant
|
||||||
: FilterTag.Variant,
|
: FilterTag.Variant,
|
||||||
oils: decodeOils(calc),
|
oils: decodeOils(calc),
|
||||||
sources: sources,
|
sources,
|
||||||
option: {
|
option: {
|
||||||
value: sources[0].contributes!.value
|
value: sources[0].contributes!.value
|
||||||
},
|
},
|
||||||
@@ -197,7 +197,7 @@ export function calculatedStatToFilter (
|
|||||||
text: translation.string,
|
text: translation.string,
|
||||||
tag: (type as unknown) as FilterTag,
|
tag: (type as unknown) as FilterTag,
|
||||||
oils: decodeOils(calc),
|
oils: decodeOils(calc),
|
||||||
sources: sources,
|
sources,
|
||||||
roll: undefined,
|
roll: undefined,
|
||||||
disabled: true
|
disabled: true
|
||||||
}
|
}
|
||||||
@@ -288,7 +288,7 @@ export function calculatedStatToFilter (
|
|||||||
bounds: (item.rarity === ItemRarity.Unique && roll.min !== roll.max && calc.stat.better !== StatBetter.NotComparable)
|
bounds: (item.rarity === ItemRarity.Unique && roll.min !== roll.max && calc.stat.better !== StatBetter.NotComparable)
|
||||||
? filterBounds
|
? filterBounds
|
||||||
: undefined,
|
: undefined,
|
||||||
dp: dp,
|
dp,
|
||||||
isNegated: false,
|
isNegated: false,
|
||||||
tradeInvert: calc.stat.trade.inverted
|
tradeInvert: calc.stat.trade.inverted
|
||||||
}
|
}
|
||||||
@@ -427,10 +427,10 @@ function applyClusterJewelRules (filters: StatFilter[]) {
|
|||||||
// 4 is [_, 5]
|
// 4 is [_, 5]
|
||||||
if (filter.roll!.value === 4) {
|
if (filter.roll!.value === 4) {
|
||||||
filter.roll!.max = 5
|
filter.roll!.max = 5
|
||||||
// 5 is [5, 5]
|
// 5 is [5, 5]
|
||||||
} else if (filter.roll!.value === 5) {
|
} else if (filter.roll!.value === 5) {
|
||||||
filter.roll!.min = filter.roll!.default.min
|
filter.roll!.min = filter.roll!.default.min
|
||||||
// 3, 6, 10, 11, 12 are [n, _]
|
// 3, 6, 10, 11, 12 are [n, _]
|
||||||
} else if (
|
} else if (
|
||||||
filter.roll!.value === 3 ||
|
filter.roll!.value === 3 ||
|
||||||
filter.roll!.value === 6 ||
|
filter.roll!.value === 6 ||
|
||||||
|
|||||||
@@ -335,7 +335,7 @@ export function filterPseudo (ctx: FiltersCreationContext) {
|
|||||||
const filter = calculatedStatToFilter({
|
const filter = calculatedStatToFilter({
|
||||||
stat: STAT_BY_REF(rule.pseudo)!,
|
stat: STAT_BY_REF(rule.pseudo)!,
|
||||||
type: ModifierType.Pseudo,
|
type: ModifierType.Pseudo,
|
||||||
sources: sources
|
sources
|
||||||
}, ctx.searchInRange, ctx.item)
|
}, ctx.searchInRange, ctx.item)
|
||||||
|
|
||||||
filter.disabled = rule.disabled ?? true
|
filter.disabled = rule.disabled ?? true
|
||||||
|
|||||||
@@ -257,7 +257,7 @@ function propToFilter (opts: {
|
|||||||
better: StatBetter.PositiveRoll
|
better: StatBetter.PositiveRoll
|
||||||
}
|
}
|
||||||
const filter = calculatedStatToFilter({
|
const filter = calculatedStatToFilter({
|
||||||
stat: stat,
|
stat,
|
||||||
type: ModifierType.Pseudo,
|
type: ModifierType.Pseudo,
|
||||||
sources: [{
|
sources: [{
|
||||||
modifier: {
|
modifier: {
|
||||||
@@ -265,7 +265,7 @@ function propToFilter (opts: {
|
|||||||
stats: []
|
stats: []
|
||||||
},
|
},
|
||||||
stat: {
|
stat: {
|
||||||
stat: stat,
|
stat,
|
||||||
translation: stat.matchers[0],
|
translation: stat.matchers[0],
|
||||||
roll: {
|
roll: {
|
||||||
dp: opts.dp ?? false,
|
dp: opts.dp ?? false,
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import { usePoeninja } from '@/web/background/Prices'
|
|||||||
|
|
||||||
const cache = new Cache()
|
const cache = new Cache()
|
||||||
|
|
||||||
interface PoepricesApiResponse { /* eslint-disable camelcase */
|
interface PoepricesApiResponse {
|
||||||
currency: 'chaos' | 'divine' | 'exalt'
|
/* eslint-disable camelcase */ currency: 'chaos' | 'divine' | 'exalt'
|
||||||
error: number
|
error: number
|
||||||
error_msg: string
|
error_msg: string
|
||||||
warning_msg: string
|
warning_msg: string
|
||||||
@@ -28,20 +28,24 @@ export interface RareItemPrice {
|
|||||||
}>
|
}>
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function requestPoeprices (item: ParsedItem): Promise<RareItemPrice> {
|
export async function requestPoeprices (
|
||||||
|
item: ParsedItem
|
||||||
|
): Promise<RareItemPrice> {
|
||||||
const query = querystring({
|
const query = querystring({
|
||||||
i: utf8ToBase64(transformItemText(item.rawText)),
|
i: utf8ToBase64(transformItemText(item.rawText)),
|
||||||
l: useLeagues().selectedId.value,
|
l: useLeagues().selectedId.value,
|
||||||
s: 'awakened-poe-trade'
|
s: 'awakened-poe-trade' // might be required name here
|
||||||
})
|
})
|
||||||
|
|
||||||
let data = cache.get<PoepricesApiResponse>(query)
|
let data = cache.get<PoepricesApiResponse>(query)
|
||||||
if (!data) {
|
if (!data) {
|
||||||
const response = await Host.proxy(`www.poeprices.info/api?${query}`)
|
const response = await Host.proxy(`www.poeprices.info/api?${query}`)
|
||||||
try {
|
try {
|
||||||
data = await response.json() as PoepricesApiResponse
|
data = (await response.json()) as PoepricesApiResponse
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(`${response.status}, poeprices.info API is under load or down.`)
|
throw new Error(
|
||||||
|
`${response.status}, poeprices.info API is under load or down.`
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.error !== 0) {
|
if (data.error !== 0) {
|
||||||
@@ -53,24 +57,31 @@ export async function requestPoeprices (item: ParsedItem): Promise<RareItemPrice
|
|||||||
|
|
||||||
if (data.currency === 'exalt') {
|
if (data.currency === 'exalt') {
|
||||||
const { findPriceByQuery, autoCurrency } = usePoeninja()
|
const { findPriceByQuery, autoCurrency } = usePoeninja()
|
||||||
const xchgExalted = findPriceByQuery({ ns: 'ITEM', name: 'Exalted Orb', variant: undefined })
|
const xchgExalted = findPriceByQuery({
|
||||||
|
ns: 'ITEM',
|
||||||
|
name: 'Exalted Orb',
|
||||||
|
variant: undefined
|
||||||
|
})
|
||||||
if (!xchgExalted) {
|
if (!xchgExalted) {
|
||||||
throw new Error('poeprices.info gave the price in Exalted Orbs.')
|
throw new Error('poeprices.info gave the price in Exalted Orbs.')
|
||||||
}
|
}
|
||||||
const converted = autoCurrency([data.min * xchgExalted.chaos, data.max * xchgExalted.chaos])
|
const converted = autoCurrency([
|
||||||
|
data.min * xchgExalted.chaos,
|
||||||
|
data.max * xchgExalted.chaos
|
||||||
|
])
|
||||||
data.min = converted.min
|
data.min = converted.min
|
||||||
data.max = converted.max
|
data.max = converted.max
|
||||||
data.currency = (converted.currency === 'div') ? 'divine' : 'chaos'
|
data.currency = converted.currency === 'div' ? 'divine' : 'chaos'
|
||||||
} else if (data.currency !== 'divine' && data.currency !== 'chaos') {
|
} else if (data.currency !== 'divine' && data.currency !== 'chaos') {
|
||||||
throw new Error('poeprices.info gave the price in unknown currency.')
|
throw new Error('poeprices.info gave the price in unknown currency.')
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
currency: (data.currency === 'divine') ? 'div' : 'chaos',
|
currency: data.currency === 'divine' ? 'div' : 'chaos',
|
||||||
min: data.min,
|
min: data.min,
|
||||||
max: data.max,
|
max: data.max,
|
||||||
confidence: Math.round(data.pred_confidence_score),
|
confidence: Math.round(data.pred_confidence_score),
|
||||||
explanation: data.pred_explanation.map(expl => ({
|
explanation: data.pred_explanation.map((expl) => ({
|
||||||
name: expl[0],
|
name: expl[0],
|
||||||
contrib: Math.round(expl[1] * 100)
|
contrib: Math.round(expl[1] * 100)
|
||||||
}))
|
}))
|
||||||
@@ -118,7 +129,7 @@ function utf8ToBase64 (value: string) {
|
|||||||
|
|
||||||
function querystring (q: Record<string, any>) {
|
function querystring (q: Record<string, any>) {
|
||||||
return Object.entries(q)
|
return Object.entries(q)
|
||||||
.map(pair => pair.map(encodeURIComponent).join('='))
|
.map((pair) => pair.map(encodeURIComponent).join('='))
|
||||||
.join('&')
|
.join('&')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,14 @@
|
|||||||
<span class="mr-1">{{ t(':matched') }}</span>
|
<span class="mr-1">{{ t(':matched') }}</span>
|
||||||
<span v-if="!result" class="text-gray-600">...</span>
|
<span v-if="!result" class="text-gray-600">...</span>
|
||||||
<div v-else class="flex items-center">
|
<div v-else class="flex items-center">
|
||||||
<button class="btn flex items-center mr-1" :style="{ background: selectedCurr !== 'xchgChaos' ? 'transparent' : undefined }"
|
<button class="btn flex items-center mr-1"
|
||||||
|
:style="{ background: selectedCurr !== 'xchgChaos' ? 'transparent' : undefined }"
|
||||||
@click="selectedCurr = 'xchgChaos'">
|
@click="selectedCurr = 'xchgChaos'">
|
||||||
<img src="/images/chaos.png" class="trade-bulk-currency-icon">
|
<img src="/images/chaos.png" class="trade-bulk-currency-icon">
|
||||||
<span>{{ result.xchgChaos.listed.value?.total ?? '?' }}</span>
|
<span>{{ result.xchgChaos.listed.value?.total ?? '?' }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn flex items-center mr-1" :style="{ background: selectedCurr !== 'xchgStable' ? 'transparent' : undefined }"
|
<button class="btn flex items-center mr-1"
|
||||||
|
:style="{ background: selectedCurr !== 'xchgStable' ? 'transparent' : undefined }"
|
||||||
@click="selectedCurr = 'xchgStable'">
|
@click="selectedCurr = 'xchgStable'">
|
||||||
<img src="/images/divine.png" class="trade-bulk-currency-icon">
|
<img src="/images/divine.png" class="trade-bulk-currency-icon">
|
||||||
<span>{{ result.xchgStable.listed.value?.total ?? '?' }}</span>
|
<span>{{ result.xchgStable.listed.value?.total ?? '?' }}</span>
|
||||||
@@ -19,8 +21,7 @@
|
|||||||
<span class="ml-1"><online-filter :filters="filters" /></span>
|
<span class="ml-1"><online-filter :filters="filters" /></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<trade-links v-if="result"
|
<trade-links v-if="result" :get-link="makeTradeLink" />
|
||||||
:get-link="makeTradeLink" />
|
|
||||||
</div>
|
</div>
|
||||||
<div class="layout-column overflow-y-auto overflow-x-hidden">
|
<div class="layout-column overflow-y-auto overflow-x-hidden">
|
||||||
<table class="table-stripped w-full">
|
<table class="table-stripped w-full">
|
||||||
@@ -30,7 +31,10 @@
|
|||||||
<div class="px-2">{{ t(':price') }}</div>
|
<div class="px-2">{{ t(':price') }}</div>
|
||||||
</th>
|
</th>
|
||||||
<th class="trade-table-heading">
|
<th class="trade-table-heading">
|
||||||
<div class="pl-1 pr-2 flex text-xs" style="line-height: 1.3125rem;"><span class="w-8 inline-block text-right -ml-px mr-px">{{ (selectedCurr === 'xchgChaos') ? 'chaos' : 'div' }}</span><span>{{ '\u2009' }}/{{ '\u2009' }}</span><span class="w-8 inline-block">{{ t(':bulk') }}</span></div>
|
<div class="pl-1 pr-2 flex text-xs" style="line-height: 1.3125rem;"><span
|
||||||
|
class="w-8 inline-block text-right -ml-px mr-px">{{ (selectedCurr === 'xchgChaos') ? 'chaos' : 'div'
|
||||||
|
}}</span><span>{{ '\u2009' }}/{{ '\u2009' }}</span><span class="w-8 inline-block">{{ t(':bulk')
|
||||||
|
}}</span></div>
|
||||||
</th>
|
</th>
|
||||||
<th class="trade-table-heading">
|
<th class="trade-table-heading">
|
||||||
<div class="px-1">{{ t(':stock') }}</div>
|
<div class="px-1">{{ t(':stock') }}</div>
|
||||||
@@ -55,19 +59,25 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr v-else :key="result.id">
|
<tr v-else :key="result.id">
|
||||||
<td class="px-2">{{ Number((result.exchangeAmount / result.itemAmount).toFixed(4)) }}</td>
|
<td class="px-2">{{ Number((result.exchangeAmount / result.itemAmount).toFixed(4)) }}</td>
|
||||||
<td class="pl-1 whitespace-nowrap"><span class="w-8 inline-block text-right">{{ result.exchangeAmount }}</span><span>{{ '\u2009' }}/{{ '\u2009' }}</span><span class="w-8 inline-block">{{ result.itemAmount }}</span></td>
|
<td class="pl-1 whitespace-nowrap"><span class="w-8 inline-block text-right">{{ result.exchangeAmount
|
||||||
|
}}</span><span>{{ '\u2009' }}/{{ '\u2009' }}</span><span class="w-8 inline-block">{{ result.itemAmount
|
||||||
|
}}</span></td>
|
||||||
<td class="px-1 text-right">{{ result.stock }}</td>
|
<td class="px-1 text-right">{{ result.stock }}</td>
|
||||||
<td class="px-1 text-right"><i v-if="result.stock < result.itemAmount" class="fas fa-exclamation-triangle mr-1 text-gray-500"></i>{{ Math.floor(result.stock / result.itemAmount) }}</td>
|
<td class="px-1 text-right"><i v-if="result.stock < result.itemAmount"
|
||||||
|
class="fas fa-exclamation-triangle mr-1 text-gray-500"></i>{{ Math.floor(result.stock /
|
||||||
|
result.itemAmount) }}</td>
|
||||||
<td class="pr-2 pl-4 whitespace-nowrap">
|
<td class="pr-2 pl-4 whitespace-nowrap">
|
||||||
<div class="inline-flex items-center">
|
<div class="inline-flex items-center">
|
||||||
<div class="account-status" :class="result.accountStatus"></div>
|
<div class="account-status" :class="result.accountStatus"></div>
|
||||||
<div class="ml-1 font-sans text-xs">{{ result.relativeDate }}</div>
|
<div class="ml-1 font-sans text-xs">{{ result.relativeDate }}</div>
|
||||||
</div>
|
</div>
|
||||||
<span v-if="!showSeller && result.isMine" class="rounded px-1 text-gray-800 bg-gray-400 ml-1">{{ t('You') }}</span>
|
<span v-if="!showSeller && result.isMine" class="rounded px-1 text-gray-800 bg-gray-400 ml-1">{{
|
||||||
|
t('You') }}</span>
|
||||||
</td>
|
</td>
|
||||||
<td v-if="showSeller" class="px-2 whitespace-nowrap">
|
<td v-if="showSeller" class="px-2 whitespace-nowrap">
|
||||||
<span v-if="result.isMine" class="rounded px-1 text-gray-800 bg-gray-400">{{ t('You') }}</span>
|
<span v-if="result.isMine" class="rounded px-1 text-gray-800 bg-gray-400">{{ t('You') }}</span>
|
||||||
<span v-else class="font-sans text-xs">{{ showSeller === 'ign' ? result.ign : result.accountName }}</span>
|
<span v-else class="font-sans text-xs">{{ showSeller === 'ign' ? result.ign : result.accountName
|
||||||
|
}}</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</template>
|
</template>
|
||||||
@@ -154,7 +164,7 @@ function useBulkApi () {
|
|||||||
|
|
||||||
const listedLazy = computed(() => {
|
const listedLazy = computed(() => {
|
||||||
if (!requested) {
|
if (!requested) {
|
||||||
;(async function () {
|
; (async function () {
|
||||||
try {
|
try {
|
||||||
requested = true
|
requested = true
|
||||||
_result.value = shallowReactive((await execBulkSearch(
|
_result.value = shallowReactive((await execBulkSearch(
|
||||||
@@ -230,7 +240,7 @@ export default defineComponent({
|
|||||||
const have = _have ?? ((selectedCurr.value === 'xchgStable') ? ['divine'] : ['chaos'])
|
const have = _have ?? ((selectedCurr.value === 'xchgStable') ? ['divine'] : ['chaos'])
|
||||||
const httpPostBody = createTradeRequest(props.filters, props.item, have)
|
const httpPostBody = createTradeRequest(props.filters, props.item, have)
|
||||||
const httpGetQuery = { exchange: httpPostBody.query }
|
const httpGetQuery = { exchange: httpPostBody.query }
|
||||||
return `https://${getTradeEndpoint()}/trade/exchange/${props.filters.trade.league}?q=${JSON.stringify(httpGetQuery)}`
|
return `https://${getTradeEndpoint()}/trade2/exchange/poe2/${props.filters.trade.league}?q=${JSON.stringify(httpGetQuery)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
const { t } = useI18nNs('trade_result')
|
const { t } = useI18nNs('trade_result')
|
||||||
|
|||||||
@@ -8,8 +8,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<online-filter v-if="list" :by-time="true" :filters="filters" />
|
<online-filter v-if="list" :by-time="true" :filters="filters" />
|
||||||
<div class="flex-1"></div>
|
<div class="flex-1"></div>
|
||||||
<trade-links v-if="list"
|
<trade-links v-if="list" :get-link="makeTradeLink" />
|
||||||
:get-link="makeTradeLink" />
|
|
||||||
</div>
|
</div>
|
||||||
<div class="layout-column overflow-y-auto overflow-x-hidden">
|
<div class="layout-column overflow-y-auto overflow-x-hidden">
|
||||||
<table class="table-stripped w-full">
|
<table class="table-stripped w-full">
|
||||||
@@ -46,21 +45,28 @@
|
|||||||
<td colspan="100" class="text-transparent">***</td>
|
<td colspan="100" class="text-transparent">***</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-else :key="result.id">
|
<tr v-else :key="result.id">
|
||||||
<td class="px-2 whitespace-nowrap"><span :class="{ 'line-through': result.priceCurrency === 'exalted' }">{{ result.priceAmount }} {{ result.priceCurrency }}</span> <span v-if="result.listedTimes > 2" class="rounded px-1 text-gray-800 bg-gray-400 -mr-2"><span class="font-sans">×</span> {{ result.listedTimes }}</span><i v-else-if="!result.hasNote" class="fas fa-question" /></td>
|
<td class="px-2 whitespace-nowrap"><span
|
||||||
|
:class="{ 'line-through': result.priceCurrency === 'exalted' }">{{ result.priceAmount }} {{
|
||||||
|
result.priceCurrency }}</span> <span v-if="result.listedTimes > 2"
|
||||||
|
class="rounded px-1 text-gray-800 bg-gray-400 -mr-2"><span class="font-sans">×</span> {{
|
||||||
|
result.listedTimes }}</span><i v-else-if="!result.hasNote" class="fas fa-question" /></td>
|
||||||
<td v-if="item.stackSize" class="px-2 text-right">{{ result.stackSize }}</td>
|
<td v-if="item.stackSize" class="px-2 text-right">{{ result.stackSize }}</td>
|
||||||
<td v-if="filters.itemLevel" class="px-2 whitespace-nowrap text-right">{{ result.itemLevel }}</td>
|
<td v-if="filters.itemLevel" class="px-2 whitespace-nowrap text-right">{{ result.itemLevel }}</td>
|
||||||
<td v-if="item.category === 'Gem'" class="pl-2 whitespace-nowrap">{{ result.level }}</td>
|
<td v-if="item.category === 'Gem'" class="pl-2 whitespace-nowrap">{{ result.level }}</td>
|
||||||
<td v-if="filters.quality || item.category === 'Gem'" class="px-2 whitespace-nowrap text-blue-400 text-right">{{ result.quality }}</td>
|
<td v-if="filters.quality || item.category === 'Gem'"
|
||||||
|
class="px-2 whitespace-nowrap text-blue-400 text-right">{{ result.quality }}</td>
|
||||||
<td class="pr-2 pl-4 whitespace-nowrap">
|
<td class="pr-2 pl-4 whitespace-nowrap">
|
||||||
<div class="inline-flex items-center">
|
<div class="inline-flex items-center">
|
||||||
<div class="account-status" :class="result.accountStatus"></div>
|
<div class="account-status" :class="result.accountStatus"></div>
|
||||||
<div class="ml-1 font-sans text-xs">{{ result.relativeDate }}</div>
|
<div class="ml-1 font-sans text-xs">{{ result.relativeDate }}</div>
|
||||||
</div>
|
</div>
|
||||||
<span v-if="!showSeller && result.isMine" class="rounded px-1 text-gray-800 bg-gray-400 ml-1">{{ t('You') }}</span>
|
<span v-if="!showSeller && result.isMine" class="rounded px-1 text-gray-800 bg-gray-400 ml-1">{{
|
||||||
|
t('You') }}</span>
|
||||||
</td>
|
</td>
|
||||||
<td v-if="showSeller" class="px-2 whitespace-nowrap">
|
<td v-if="showSeller" class="px-2 whitespace-nowrap">
|
||||||
<span v-if="result.isMine" class="rounded px-1 text-gray-800 bg-gray-400">{{ t('You') }}</span>
|
<span v-if="result.isMine" class="rounded px-1 text-gray-800 bg-gray-400">{{ t('You') }}</span>
|
||||||
<span v-else class="font-sans text-xs">{{ showSeller === 'ign' ? result.ign : result.accountName }}</span>
|
<span v-else class="font-sans text-xs">{{ showSeller === 'ign' ? result.ign : result.accountName
|
||||||
|
}}</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</template>
|
</template>
|
||||||
@@ -222,8 +228,8 @@ export default defineComponent({
|
|||||||
|
|
||||||
function makeTradeLink () {
|
function makeTradeLink () {
|
||||||
return (searchResult.value)
|
return (searchResult.value)
|
||||||
? `https://${getTradeEndpoint()}/trade/search/${props.filters.trade.league}/${searchResult.value.id}`
|
? `https://${getTradeEndpoint()}/trade2/search/poe2/${props.filters.trade.league}/${searchResult.value.id}`
|
||||||
: `https://${getTradeEndpoint()}/trade/search/${props.filters.trade.league}?q=${JSON.stringify(createTradeRequest(props.filters, props.stats, props.item))}`
|
: `https://${getTradeEndpoint()}/trade2/search/poe2/${props.filters.trade.league}?q=${JSON.stringify(createTradeRequest(props.filters, props.stats, props.item))}`
|
||||||
}
|
}
|
||||||
|
|
||||||
const { t } = useI18nNs('trade_result')
|
const { t } = useI18nNs('trade_result')
|
||||||
@@ -261,7 +267,7 @@ export default defineComponent({
|
|||||||
@apply bg-gray-800;
|
@apply bg-gray-800;
|
||||||
@apply p-0 m-0;
|
@apply p-0 m-0;
|
||||||
|
|
||||||
& > div {
|
&>div {
|
||||||
@apply border-b border-gray-700;
|
@apply border-b border-gray-700;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -271,10 +277,14 @@ export default defineComponent({
|
|||||||
height: 0.375rem;
|
height: 0.375rem;
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
|
|
||||||
&.online { /* */ }
|
&.online {
|
||||||
|
/* */
|
||||||
|
}
|
||||||
|
|
||||||
&.offline {
|
&.offline {
|
||||||
@apply bg-red-600;
|
@apply bg-red-600;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.afk {
|
&.afk {
|
||||||
@apply bg-orange-500;
|
@apply bg-orange-500;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,21 @@
|
|||||||
import { DateTime } from 'luxon'
|
import { DateTime } from 'luxon'
|
||||||
import { Host } from '@/web/background/IPC'
|
import { Host } from '@/web/background/IPC'
|
||||||
import { TradeResponse, Account, getTradeEndpoint, RATE_LIMIT_RULES, adjustRateLimits, tradeTag, preventQueueCreation } from './common'
|
import {
|
||||||
|
TradeResponse,
|
||||||
|
Account,
|
||||||
|
getTradeEndpoint,
|
||||||
|
RATE_LIMIT_RULES,
|
||||||
|
adjustRateLimits,
|
||||||
|
tradeTag,
|
||||||
|
preventQueueCreation
|
||||||
|
} from './common'
|
||||||
import { RateLimiter } from './RateLimiter'
|
import { RateLimiter } from './RateLimiter'
|
||||||
import { ItemFilters } from '../filters/interfaces'
|
import { ItemFilters } from '../filters/interfaces'
|
||||||
import { ParsedItem } from '@/parser'
|
import { ParsedItem } from '@/parser'
|
||||||
import { Cache } from './Cache'
|
import { Cache } from './Cache'
|
||||||
|
|
||||||
interface TradeRequest { /* eslint-disable camelcase */
|
interface TradeRequest {
|
||||||
engine: 'new'
|
/* eslint-disable camelcase */ engine: 'new'
|
||||||
query: {
|
query: {
|
||||||
status: { option: 'online' | 'onlineleague' | 'any' }
|
status: { option: 'online' | 'onlineleague' | 'any' }
|
||||||
have: string[]
|
have: string[]
|
||||||
@@ -56,34 +64,42 @@ export interface PricingResult {
|
|||||||
|
|
||||||
const cache = new Cache()
|
const cache = new Cache()
|
||||||
|
|
||||||
async function requestTradeResultList (body: TradeRequest, leagueId: string): Promise<SearchResult> {
|
async function requestTradeResultList (
|
||||||
|
body: TradeRequest,
|
||||||
|
leagueId: string
|
||||||
|
): Promise<SearchResult> {
|
||||||
let data = cache.get<SearchResult>([body, leagueId])
|
let data = cache.get<SearchResult>([body, leagueId])
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
preventQueueCreation([
|
preventQueueCreation([{ count: 1, limiters: RATE_LIMIT_RULES.EXCHANGE }])
|
||||||
{ count: 1, limiters: RATE_LIMIT_RULES.EXCHANGE }
|
|
||||||
])
|
|
||||||
|
|
||||||
await RateLimiter.waitMulti(RATE_LIMIT_RULES.EXCHANGE)
|
await RateLimiter.waitMulti(RATE_LIMIT_RULES.EXCHANGE)
|
||||||
|
|
||||||
const response = await Host.proxy(`${getTradeEndpoint()}/api/trade/exchange/${leagueId}`, {
|
const response = await Host.proxy(
|
||||||
method: 'POST',
|
`${getTradeEndpoint()}/api/trade2/exchange/${leagueId}`,
|
||||||
headers: {
|
{
|
||||||
'Accept': 'application/json',
|
method: 'POST',
|
||||||
'Content-Type': 'application/json'
|
headers: {
|
||||||
},
|
'Accept': 'application/json',
|
||||||
body: JSON.stringify(body)
|
'Content-Type': 'application/json'
|
||||||
})
|
},
|
||||||
|
body: JSON.stringify(body)
|
||||||
|
}
|
||||||
|
)
|
||||||
adjustRateLimits(RATE_LIMIT_RULES.EXCHANGE, response.headers)
|
adjustRateLimits(RATE_LIMIT_RULES.EXCHANGE, response.headers)
|
||||||
|
|
||||||
const _data = await response.json() as TradeResponse<SearchResult>
|
const _data = (await response.json()) as TradeResponse<SearchResult>
|
||||||
if (_data.error) {
|
if (_data.error) {
|
||||||
throw new Error(_data.error.message)
|
throw new Error(_data.error.message)
|
||||||
} else {
|
} else {
|
||||||
data = _data
|
data = _data
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.set<SearchResult>([body, leagueId], data, Cache.deriveTtl(...RATE_LIMIT_RULES.EXCHANGE))
|
cache.set<SearchResult>(
|
||||||
|
[body, leagueId],
|
||||||
|
data,
|
||||||
|
Cache.deriveTtl(...RATE_LIMIT_RULES.EXCHANGE)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return data
|
return data
|
||||||
@@ -96,15 +112,19 @@ function toPricingResult (
|
|||||||
): PricingResult {
|
): PricingResult {
|
||||||
return {
|
return {
|
||||||
id: result.id,
|
id: result.id,
|
||||||
relativeDate: DateTime.fromISO(result.listing.indexed).toRelative({ style: 'short' }) ?? '',
|
relativeDate:
|
||||||
|
DateTime.fromISO(result.listing.indexed).toRelative({ style: 'short' }) ??
|
||||||
|
'',
|
||||||
exchangeAmount: result.listing.offers[offer].exchange.amount,
|
exchangeAmount: result.listing.offers[offer].exchange.amount,
|
||||||
itemAmount: result.listing.offers[offer].item.amount,
|
itemAmount: result.listing.offers[offer].item.amount,
|
||||||
stock: result.listing.offers[offer].item.stock,
|
stock: result.listing.offers[offer].item.stock,
|
||||||
isMine: (result.listing.account.name === opts.accountName),
|
isMine: result.listing.account.name === opts.accountName,
|
||||||
ign: result.listing.account.lastCharacterName,
|
ign: result.listing.account.lastCharacterName,
|
||||||
accountName: result.listing.account.name,
|
accountName: result.listing.account.name,
|
||||||
accountStatus: result.listing.account.online
|
accountStatus: result.listing.account.online
|
||||||
? (result.listing.account.online.status === 'afk' ? 'afk' : 'online')
|
? result.listing.account.online.status === 'afk'
|
||||||
|
? 'afk'
|
||||||
|
: 'online'
|
||||||
: 'offline'
|
: 'offline'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,18 +136,27 @@ export interface BulkSearch {
|
|||||||
listed: PricingResult[]
|
listed: PricingResult[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createTradeRequest (filters: ItemFilters, item: ParsedItem, have: string[]): TradeRequest {
|
export function createTradeRequest (
|
||||||
|
filters: ItemFilters,
|
||||||
|
item: ParsedItem,
|
||||||
|
have: string[]
|
||||||
|
): TradeRequest {
|
||||||
return {
|
return {
|
||||||
engine: 'new',
|
engine: 'new',
|
||||||
query: {
|
query: {
|
||||||
have: have,
|
have,
|
||||||
want: [tradeTag(item)!],
|
want: [tradeTag(item)!],
|
||||||
status: {
|
status: {
|
||||||
option: filters.trade.offline
|
option: filters.trade.offline
|
||||||
? 'any'
|
? 'any'
|
||||||
: (filters.trade.onlineInLeague ? 'onlineleague' : 'online')
|
: filters.trade.onlineInLeague
|
||||||
|
? 'onlineleague'
|
||||||
|
: 'online'
|
||||||
},
|
},
|
||||||
minimum: (filters.stackSize && !filters.stackSize.disabled) ? filters.stackSize.value : undefined
|
minimum:
|
||||||
|
filters.stackSize && !filters.stackSize.disabled
|
||||||
|
? filters.stackSize.value
|
||||||
|
: undefined
|
||||||
// fulfillable: null
|
// fulfillable: null
|
||||||
},
|
},
|
||||||
sort: { have: 'asc' }
|
sort: { have: 'asc' }
|
||||||
@@ -149,40 +178,46 @@ export async function execBulkSearch (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const offer = 0
|
const offer = 0
|
||||||
const results = Object.values(query.result)
|
const results = Object.values(query.result).filter(
|
||||||
.filter(result => result.listing.offers.length === 1)
|
(result) => result.listing.offers.length === 1
|
||||||
|
)
|
||||||
|
|
||||||
const resultByHave = have.map(tradeTag => {
|
const resultByHave = have.map((tradeTag) => {
|
||||||
const resultsTag = results.filter(result => result.listing.offers[offer].exchange.currency === tradeTag)
|
const resultsTag = results.filter(
|
||||||
|
(result) => result.listing.offers[offer].exchange.currency === tradeTag
|
||||||
|
)
|
||||||
|
|
||||||
const loadedOnDemand = (
|
const loadedOnDemand =
|
||||||
tradeTag === 'chaos' &&
|
tradeTag === 'chaos' &&
|
||||||
resultsTag.length < SHOW_RESULTS &&
|
resultsTag.length < SHOW_RESULTS &&
|
||||||
query.total > API_FETCH_LIMIT
|
query.total > API_FETCH_LIMIT
|
||||||
)
|
|
||||||
if (loadedOnDemand) return null
|
if (loadedOnDemand) return null
|
||||||
|
|
||||||
const listed = resultsTag
|
const listed = resultsTag
|
||||||
.sort((a, b) =>
|
.sort(
|
||||||
(a.listing.offers[offer].exchange.amount / a.listing.offers[offer].item.amount) -
|
(a, b) =>
|
||||||
(b.listing.offers[offer].exchange.amount / b.listing.offers[offer].item.amount))
|
a.listing.offers[offer].exchange.amount /
|
||||||
|
a.listing.offers[offer].item.amount -
|
||||||
|
b.listing.offers[offer].exchange.amount /
|
||||||
|
b.listing.offers[offer].item.amount
|
||||||
|
)
|
||||||
.slice(0, SHOW_RESULTS)
|
.slice(0, SHOW_RESULTS)
|
||||||
.map(result => toPricingResult(result, opts, offer))
|
.map((result) => toPricingResult(result, opts, offer))
|
||||||
|
|
||||||
const chaosIsLoaded = (
|
const chaosIsLoaded =
|
||||||
tradeTag === 'divine' &&
|
tradeTag === 'divine' &&
|
||||||
resultsTag.length < results.length &&
|
resultsTag.length < results.length &&
|
||||||
((results.length - resultsTag.length) >= SHOW_RESULTS || query.total <= API_FETCH_LIMIT)
|
(results.length - resultsTag.length >= SHOW_RESULTS ||
|
||||||
)
|
query.total <= API_FETCH_LIMIT)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
queryId: query.id,
|
queryId: query.id,
|
||||||
haveTag: tradeTag,
|
haveTag: tradeTag,
|
||||||
// this is a best guess when making request with multiple `have` currencies
|
// this is a best guess when making request with multiple `have` currencies
|
||||||
total: (chaosIsLoaded)
|
total: chaosIsLoaded
|
||||||
? resultsTag.length
|
? resultsTag.length
|
||||||
: (query.total - (results.length - resultsTag.length)),
|
: query.total - (results.length - resultsTag.length),
|
||||||
listed: listed
|
listed
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,21 @@
|
|||||||
import { ItemInfluence, ItemCategory, ParsedItem, ItemRarity } from '@/parser'
|
import { ItemInfluence, ItemCategory, ParsedItem, ItemRarity } from '@/parser'
|
||||||
import { ItemFilters, StatFilter, INTERNAL_TRADE_IDS, InternalTradeId } from '../filters/interfaces'
|
import {
|
||||||
|
ItemFilters,
|
||||||
|
StatFilter,
|
||||||
|
INTERNAL_TRADE_IDS,
|
||||||
|
InternalTradeId
|
||||||
|
} from '../filters/interfaces'
|
||||||
import { setProperty as propSet } from 'dot-prop'
|
import { setProperty as propSet } from 'dot-prop'
|
||||||
import { DateTime } from 'luxon'
|
import { DateTime } from 'luxon'
|
||||||
import { Host } from '@/web/background/IPC'
|
import { Host } from '@/web/background/IPC'
|
||||||
import { TradeResponse, Account, getTradeEndpoint, adjustRateLimits, RATE_LIMIT_RULES, preventQueueCreation } from './common'
|
import {
|
||||||
|
TradeResponse,
|
||||||
|
Account,
|
||||||
|
getTradeEndpoint,
|
||||||
|
adjustRateLimits,
|
||||||
|
RATE_LIMIT_RULES,
|
||||||
|
preventQueueCreation
|
||||||
|
} from './common'
|
||||||
import { STAT_BY_REF } from '@/assets/data'
|
import { STAT_BY_REF } from '@/assets/data'
|
||||||
import { RateLimiter } from './RateLimiter'
|
import { RateLimiter } from './RateLimiter'
|
||||||
import { ModifierType } from '@/parser/modifiers'
|
import { ModifierType } from '@/parser/modifiers'
|
||||||
@@ -62,11 +74,7 @@ const TOTAL_MODS_TEXT = {
|
|||||||
'# Empty Prefix Modifiers',
|
'# Empty Prefix Modifiers',
|
||||||
'# Empty Suffix Modifiers'
|
'# Empty Suffix Modifiers'
|
||||||
],
|
],
|
||||||
TOTAL_MODIFIERS: [
|
TOTAL_MODIFIERS: ['# Modifiers', '# Prefix Modifiers', '# Suffix Modifiers']
|
||||||
'# Modifiers',
|
|
||||||
'# Prefix Modifiers',
|
|
||||||
'# Suffix Modifiers'
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const INFLUENCE_PSEUDO_TEXT = {
|
const INFLUENCE_PSEUDO_TEXT = {
|
||||||
@@ -78,10 +86,16 @@ const INFLUENCE_PSEUDO_TEXT = {
|
|||||||
[ItemInfluence.Warlord]: 'Has Warlord Influence'
|
[ItemInfluence.Warlord]: 'Has Warlord Influence'
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FilterBoolean { option?: 'true' | 'false' }
|
interface FilterBoolean {
|
||||||
interface FilterRange { min?: number, max?: number }
|
option?: 'true' | 'false'
|
||||||
|
}
|
||||||
|
interface FilterRange {
|
||||||
|
min?: number
|
||||||
|
max?: number
|
||||||
|
}
|
||||||
|
|
||||||
interface TradeRequest { /* eslint-disable camelcase */
|
interface TradeRequest {
|
||||||
|
/* eslint-disable camelcase */
|
||||||
query: {
|
query: {
|
||||||
status: { option: 'online' | 'onlineleague' | 'any' }
|
status: { option: 'online' | 'onlineleague' | 'any' }
|
||||||
name?: string | { discriminator: string, option: string }
|
name?: string | { discriminator: string, option: string }
|
||||||
@@ -207,10 +221,10 @@ interface FetchResult {
|
|||||||
properties?: Array<{
|
properties?: Array<{
|
||||||
values: [[string, number]]
|
values: [[string, number]]
|
||||||
type:
|
type:
|
||||||
78 | // Corpse Level (Filled Coffin)
|
| 78 // Corpse Level (Filled Coffin)
|
||||||
30 | // Spawns a Level %0 Monster when Harvested
|
| 30 // Spawns a Level %0 Monster when Harvested
|
||||||
6 | // Quality
|
| 6 // Quality
|
||||||
5 // Level
|
| 5 // Level
|
||||||
}>
|
}>
|
||||||
note?: string
|
note?: string
|
||||||
}
|
}
|
||||||
@@ -242,17 +256,21 @@ export interface PricingResult {
|
|||||||
ign: string
|
ign: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createTradeRequest (filters: ItemFilters, stats: StatFilter[], item: ParsedItem) {
|
export function createTradeRequest (
|
||||||
|
filters: ItemFilters,
|
||||||
|
stats: StatFilter[],
|
||||||
|
item: ParsedItem
|
||||||
|
) {
|
||||||
const body: TradeRequest = {
|
const body: TradeRequest = {
|
||||||
query: {
|
query: {
|
||||||
status: {
|
status: {
|
||||||
option: filters.trade.offline
|
option: filters.trade.offline
|
||||||
? 'any'
|
? 'any'
|
||||||
: (filters.trade.onlineInLeague ? 'onlineleague' : 'online')
|
: filters.trade.onlineInLeague
|
||||||
|
? 'onlineleague'
|
||||||
|
: 'online'
|
||||||
},
|
},
|
||||||
stats: [
|
stats: [{ type: 'and', filters: [] }],
|
||||||
{ type: 'and', filters: [] }
|
|
||||||
],
|
|
||||||
filters: {}
|
filters: {}
|
||||||
},
|
},
|
||||||
sort: {
|
sort: {
|
||||||
@@ -262,20 +280,33 @@ export function createTradeRequest (filters: ItemFilters, stats: StatFilter[], i
|
|||||||
const { query } = body
|
const { query } = body
|
||||||
|
|
||||||
if (filters.trade.currency) {
|
if (filters.trade.currency) {
|
||||||
propSet(query.filters, 'trade_filters.filters.price.option', filters.trade.currency)
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'trade_filters.filters.price.option',
|
||||||
|
filters.trade.currency
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.trade.collapseListings === 'api') {
|
if (filters.trade.collapseListings === 'api') {
|
||||||
propSet(query.filters, 'trade_filters.filters.collapse.option', String(true))
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'trade_filters.filters.collapse.option',
|
||||||
|
String(true)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.trade.listed) {
|
if (filters.trade.listed) {
|
||||||
propSet(query.filters, 'trade_filters.filters.indexed.option', filters.trade.listed)
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'trade_filters.filters.indexed.option',
|
||||||
|
filters.trade.listed
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const activeSearch = (filters.searchRelaxed && !filters.searchRelaxed.disabled)
|
const activeSearch =
|
||||||
? filters.searchRelaxed
|
filters.searchRelaxed && !filters.searchRelaxed.disabled
|
||||||
: filters.searchExact
|
? filters.searchRelaxed
|
||||||
|
: filters.searchExact
|
||||||
|
|
||||||
if (activeSearch.nameTrade) {
|
if (activeSearch.nameTrade) {
|
||||||
query.name = nameToQuery(activeSearch.nameTrade, filters)
|
query.name = nameToQuery(activeSearch.nameTrade, filters)
|
||||||
@@ -292,7 +323,11 @@ export function createTradeRequest (filters: ItemFilters, stats: StatFilter[], i
|
|||||||
if (filters.foil && !filters.foil.disabled) {
|
if (filters.foil && !filters.foil.disabled) {
|
||||||
propSet(query.filters, 'type_filters.filters.rarity.option', 'uniquefoil')
|
propSet(query.filters, 'type_filters.filters.rarity.option', 'uniquefoil')
|
||||||
} else if (filters.rarity) {
|
} else if (filters.rarity) {
|
||||||
propSet(query.filters, 'type_filters.filters.rarity.option', filters.rarity.value)
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'type_filters.filters.rarity.option',
|
||||||
|
filters.rarity.value
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activeSearch.category) {
|
if (activeSearch.category) {
|
||||||
@@ -305,85 +340,166 @@ export function createTradeRequest (filters: ItemFilters, stats: StatFilter[], i
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (filters.corrupted?.value === false || filters.corrupted?.exact) {
|
if (filters.corrupted?.value === false || filters.corrupted?.exact) {
|
||||||
propSet(query.filters, 'misc_filters.filters.corrupted.option', String(filters.corrupted.value))
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'misc_filters.filters.corrupted.option',
|
||||||
|
String(filters.corrupted.value)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if (filters.fractured?.value === false) {
|
if (filters.fractured?.value === false) {
|
||||||
propSet(query.filters, 'misc_filters.filters.fractured_item.option', String(false))
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'misc_filters.filters.fractured_item.option',
|
||||||
|
String(false)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if (filters.mirrored) {
|
if (filters.mirrored) {
|
||||||
if (filters.mirrored.disabled) {
|
if (filters.mirrored.disabled) {
|
||||||
propSet(query.filters, 'misc_filters.filters.mirrored.option', String(false))
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'misc_filters.filters.mirrored.option',
|
||||||
|
String(false)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
item.rarity === ItemRarity.Normal ||
|
item.rarity === ItemRarity.Normal ||
|
||||||
item.rarity === ItemRarity.Magic ||
|
item.rarity === ItemRarity.Magic ||
|
||||||
item.rarity === ItemRarity.Rare
|
item.rarity === ItemRarity.Rare
|
||||||
) {
|
) {
|
||||||
propSet(query.filters, 'misc_filters.filters.mirrored.option', String(false))
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'misc_filters.filters.mirrored.option',
|
||||||
|
String(false)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.gemLevel && !filters.gemLevel.disabled) {
|
if (filters.gemLevel && !filters.gemLevel.disabled) {
|
||||||
propSet(query.filters, 'misc_filters.filters.gem_level.min', filters.gemLevel.value)
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'misc_filters.filters.gem_level.min',
|
||||||
|
filters.gemLevel.value
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.quality && !filters.quality.disabled) {
|
if (filters.quality && !filters.quality.disabled) {
|
||||||
propSet(query.filters, 'misc_filters.filters.quality.min', filters.quality.value)
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'misc_filters.filters.quality.min',
|
||||||
|
filters.quality.value
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.itemLevel && !filters.itemLevel.disabled) {
|
if (filters.itemLevel && !filters.itemLevel.disabled) {
|
||||||
propSet(query.filters, 'misc_filters.filters.ilvl.min', filters.itemLevel.value)
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'misc_filters.filters.ilvl.min',
|
||||||
|
filters.itemLevel.value
|
||||||
|
)
|
||||||
if (filters.itemLevel.max) {
|
if (filters.itemLevel.max) {
|
||||||
propSet(query.filters, 'misc_filters.filters.ilvl.max', filters.itemLevel.max)
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'misc_filters.filters.ilvl.max',
|
||||||
|
filters.itemLevel.max
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.stackSize && !filters.stackSize.disabled) {
|
if (filters.stackSize && !filters.stackSize.disabled) {
|
||||||
propSet(query.filters, 'misc_filters.filters.stack_size.min', filters.stackSize.value)
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'misc_filters.filters.stack_size.min',
|
||||||
|
filters.stackSize.value
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.linkedSockets && !filters.linkedSockets.disabled) {
|
if (filters.linkedSockets && !filters.linkedSockets.disabled) {
|
||||||
propSet(query.filters, 'socket_filters.filters.links.min', filters.linkedSockets.value)
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'socket_filters.filters.links.min',
|
||||||
|
filters.linkedSockets.value
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.whiteSockets && !filters.whiteSockets.disabled) {
|
if (filters.whiteSockets && !filters.whiteSockets.disabled) {
|
||||||
propSet(query.filters, 'socket_filters.filters.sockets.w', filters.whiteSockets.value)
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'socket_filters.filters.sockets.w',
|
||||||
|
filters.whiteSockets.value
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.mapTier && !filters.mapTier.disabled) {
|
if (filters.mapTier && !filters.mapTier.disabled) {
|
||||||
propSet(query.filters, 'map_filters.filters.map_tier.min', filters.mapTier.value)
|
propSet(
|
||||||
propSet(query.filters, 'map_filters.filters.map_tier.max', filters.mapTier.value)
|
query.filters,
|
||||||
|
'map_filters.filters.map_tier.min',
|
||||||
|
filters.mapTier.value
|
||||||
|
)
|
||||||
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'map_filters.filters.map_tier.max',
|
||||||
|
filters.mapTier.value
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.mapBlighted) {
|
if (filters.mapBlighted) {
|
||||||
if (filters.mapBlighted.value === 'Blighted') {
|
if (filters.mapBlighted.value === 'Blighted') {
|
||||||
propSet(query.filters, 'map_filters.filters.map_blighted.option', String(true))
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'map_filters.filters.map_blighted.option',
|
||||||
|
String(true)
|
||||||
|
)
|
||||||
} else if (filters.mapBlighted.value === 'Blight-ravaged') {
|
} else if (filters.mapBlighted.value === 'Blight-ravaged') {
|
||||||
propSet(query.filters, 'map_filters.filters.map_uberblighted.option', String(true))
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'map_filters.filters.map_uberblighted.option',
|
||||||
|
String(true)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.unidentified && !filters.unidentified.disabled) {
|
if (filters.unidentified && !filters.unidentified.disabled) {
|
||||||
propSet(query.filters, 'misc_filters.filters.identified.option', String(false))
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'misc_filters.filters.identified.option',
|
||||||
|
String(false)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.areaLevel && !filters.areaLevel.disabled) {
|
if (filters.areaLevel && !filters.areaLevel.disabled) {
|
||||||
propSet(query.filters, 'map_filters.filters.area_level.min', filters.areaLevel.value)
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'map_filters.filters.area_level.min',
|
||||||
|
filters.areaLevel.value
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.heistWingsRevealed && !filters.heistWingsRevealed.disabled) {
|
if (filters.heistWingsRevealed && !filters.heistWingsRevealed.disabled) {
|
||||||
propSet(query.filters, 'heist_filters.filters.heist_wings.min', filters.heistWingsRevealed.value)
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'heist_filters.filters.heist_wings.min',
|
||||||
|
filters.heistWingsRevealed.value
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.sentinelCharge && !filters.sentinelCharge.disabled) {
|
if (filters.sentinelCharge && !filters.sentinelCharge.disabled) {
|
||||||
propSet(query.filters, 'sentinel_filters.filters.sentinel_durability.min', filters.sentinelCharge.value)
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'sentinel_filters.filters.sentinel_durability.min',
|
||||||
|
filters.sentinelCharge.value
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const stat of stats) {
|
for (const stat of stats) {
|
||||||
if (stat.tradeId[0] === 'item.has_empty_modifier') {
|
if (stat.tradeId[0] === 'item.has_empty_modifier') {
|
||||||
const TARGET_ID = {
|
const TARGET_ID = {
|
||||||
CRAFTED_MODIFIERS: STAT_BY_REF(TOTAL_MODS_TEXT.CRAFTED_MODIFIERS[stat.option!.value])!.trade.ids[ModifierType.Pseudo][0],
|
CRAFTED_MODIFIERS: STAT_BY_REF(
|
||||||
EMPTY_MODIFIERS: STAT_BY_REF(TOTAL_MODS_TEXT.EMPTY_MODIFIERS[stat.option!.value])!.trade.ids[ModifierType.Pseudo][0],
|
TOTAL_MODS_TEXT.CRAFTED_MODIFIERS[stat.option!.value]
|
||||||
TOTAL_MODIFIERS: STAT_BY_REF(TOTAL_MODS_TEXT.TOTAL_MODIFIERS[0])!.trade.ids[ModifierType.Pseudo][0]
|
)!.trade.ids[ModifierType.Pseudo][0],
|
||||||
|
EMPTY_MODIFIERS: STAT_BY_REF(
|
||||||
|
TOTAL_MODS_TEXT.EMPTY_MODIFIERS[stat.option!.value]
|
||||||
|
)!.trade.ids[ModifierType.Pseudo][0],
|
||||||
|
TOTAL_MODIFIERS: STAT_BY_REF(TOTAL_MODS_TEXT.TOTAL_MODIFIERS[0])!.trade
|
||||||
|
.ids[ModifierType.Pseudo][0]
|
||||||
}
|
}
|
||||||
|
|
||||||
query.stats.push({
|
query.stats.push({
|
||||||
@@ -391,8 +507,16 @@ export function createTradeRequest (filters: ItemFilters, stats: StatFilter[], i
|
|||||||
value: { min: 1, max: 1 },
|
value: { min: 1, max: 1 },
|
||||||
disabled: stat.disabled,
|
disabled: stat.disabled,
|
||||||
filters: [
|
filters: [
|
||||||
{ id: TARGET_ID.EMPTY_MODIFIERS, value: { min: 1, max: 1 }, disabled: stat.disabled },
|
{
|
||||||
{ id: TARGET_ID.CRAFTED_MODIFIERS, value: { min: 1, max: undefined }, disabled: stat.disabled }
|
id: TARGET_ID.EMPTY_MODIFIERS,
|
||||||
|
value: { min: 1, max: 1 },
|
||||||
|
disabled: stat.disabled
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: TARGET_ID.CRAFTED_MODIFIERS,
|
||||||
|
value: { min: 1, max: undefined },
|
||||||
|
disabled: stat.disabled
|
||||||
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -401,22 +525,31 @@ export function createTradeRequest (filters: ItemFilters, stats: StatFilter[], i
|
|||||||
value: { min: 1, max: 1 },
|
value: { min: 1, max: 1 },
|
||||||
disabled: stat.disabled,
|
disabled: stat.disabled,
|
||||||
filters: [
|
filters: [
|
||||||
{ id: TARGET_ID.EMPTY_MODIFIERS, value: { min: 1, max: 1 }, disabled: stat.disabled },
|
{
|
||||||
{ id: TARGET_ID.TOTAL_MODIFIERS, value: { min: 6, max: undefined }, disabled: stat.disabled }
|
id: TARGET_ID.EMPTY_MODIFIERS,
|
||||||
|
value: { min: 1, max: 1 },
|
||||||
|
disabled: stat.disabled
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: TARGET_ID.TOTAL_MODIFIERS,
|
||||||
|
value: { min: 6, max: undefined },
|
||||||
|
disabled: stat.disabled
|
||||||
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
} else if ( // https://github.com/SnosMe/awakened-poe-trade/issues/758
|
} else if (
|
||||||
|
// https://github.com/SnosMe/awakened-poe-trade/issues/758
|
||||||
item.category === ItemCategory.Flask &&
|
item.category === ItemCategory.Flask &&
|
||||||
stat.statRef === '#% increased Charge Recovery' &&
|
stat.statRef === '#% increased Charge Recovery' &&
|
||||||
!stats.some(s => s.statRef === '#% increased effect')
|
!stats.some((s) => s.statRef === '#% increased effect')
|
||||||
) {
|
) {
|
||||||
const reducedEffectId = STAT_BY_REF('#% increased effect')!.trade.ids[ModifierType.Explicit][0]
|
const reducedEffectId = STAT_BY_REF('#% increased effect')!.trade.ids[
|
||||||
|
ModifierType.Explicit
|
||||||
|
][0]
|
||||||
query.stats.push({
|
query.stats.push({
|
||||||
type: 'not',
|
type: 'not',
|
||||||
disabled: stat.disabled,
|
disabled: stat.disabled,
|
||||||
filters: [
|
filters: [{ id: reducedEffectId, disabled: stat.disabled }]
|
||||||
{ id: reducedEffectId, disabled: stat.disabled }
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,53 +558,143 @@ export function createTradeRequest (filters: ItemFilters, stats: StatFilter[], i
|
|||||||
const input = stat.roll!
|
const input = stat.roll!
|
||||||
switch (stat.tradeId[0] as InternalTradeId) {
|
switch (stat.tradeId[0] as InternalTradeId) {
|
||||||
case 'item.base_percentile':
|
case 'item.base_percentile':
|
||||||
propSet(query.filters, 'armour_filters.filters.base_defence_percentile.min', typeof input.min === 'number' ? input.min : undefined)
|
propSet(
|
||||||
propSet(query.filters, 'armour_filters.filters.base_defence_percentile.max', typeof input.max === 'number' ? input.max : undefined)
|
query.filters,
|
||||||
|
'armour_filters.filters.base_defence_percentile.min',
|
||||||
|
typeof input.min === 'number' ? input.min : undefined
|
||||||
|
)
|
||||||
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'armour_filters.filters.base_defence_percentile.max',
|
||||||
|
typeof input.max === 'number' ? input.max : undefined
|
||||||
|
)
|
||||||
break
|
break
|
||||||
case 'item.armour':
|
case 'item.armour':
|
||||||
propSet(query.filters, 'armour_filters.filters.ar.min', typeof input.min === 'number' ? input.min : undefined)
|
propSet(
|
||||||
propSet(query.filters, 'armour_filters.filters.ar.max', typeof input.max === 'number' ? input.max : undefined)
|
query.filters,
|
||||||
|
'armour_filters.filters.ar.min',
|
||||||
|
typeof input.min === 'number' ? input.min : undefined
|
||||||
|
)
|
||||||
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'armour_filters.filters.ar.max',
|
||||||
|
typeof input.max === 'number' ? input.max : undefined
|
||||||
|
)
|
||||||
break
|
break
|
||||||
case 'item.evasion_rating':
|
case 'item.evasion_rating':
|
||||||
propSet(query.filters, 'armour_filters.filters.ev.min', typeof input.min === 'number' ? input.min : undefined)
|
propSet(
|
||||||
propSet(query.filters, 'armour_filters.filters.ev.max', typeof input.max === 'number' ? input.max : undefined)
|
query.filters,
|
||||||
|
'armour_filters.filters.ev.min',
|
||||||
|
typeof input.min === 'number' ? input.min : undefined
|
||||||
|
)
|
||||||
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'armour_filters.filters.ev.max',
|
||||||
|
typeof input.max === 'number' ? input.max : undefined
|
||||||
|
)
|
||||||
break
|
break
|
||||||
case 'item.energy_shield':
|
case 'item.energy_shield':
|
||||||
propSet(query.filters, 'armour_filters.filters.es.min', typeof input.min === 'number' ? input.min : undefined)
|
propSet(
|
||||||
propSet(query.filters, 'armour_filters.filters.es.max', typeof input.max === 'number' ? input.max : undefined)
|
query.filters,
|
||||||
|
'armour_filters.filters.es.min',
|
||||||
|
typeof input.min === 'number' ? input.min : undefined
|
||||||
|
)
|
||||||
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'armour_filters.filters.es.max',
|
||||||
|
typeof input.max === 'number' ? input.max : undefined
|
||||||
|
)
|
||||||
break
|
break
|
||||||
case 'item.ward':
|
case 'item.ward':
|
||||||
propSet(query.filters, 'armour_filters.filters.ward.min', typeof input.min === 'number' ? input.min : undefined)
|
propSet(
|
||||||
propSet(query.filters, 'armour_filters.filters.ward.max', typeof input.max === 'number' ? input.max : undefined)
|
query.filters,
|
||||||
|
'armour_filters.filters.ward.min',
|
||||||
|
typeof input.min === 'number' ? input.min : undefined
|
||||||
|
)
|
||||||
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'armour_filters.filters.ward.max',
|
||||||
|
typeof input.max === 'number' ? input.max : undefined
|
||||||
|
)
|
||||||
break
|
break
|
||||||
case 'item.block':
|
case 'item.block':
|
||||||
propSet(query.filters, 'armour_filters.filters.block.min', typeof input.min === 'number' ? input.min : undefined)
|
propSet(
|
||||||
propSet(query.filters, 'armour_filters.filters.block.max', typeof input.max === 'number' ? input.max : undefined)
|
query.filters,
|
||||||
|
'armour_filters.filters.block.min',
|
||||||
|
typeof input.min === 'number' ? input.min : undefined
|
||||||
|
)
|
||||||
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'armour_filters.filters.block.max',
|
||||||
|
typeof input.max === 'number' ? input.max : undefined
|
||||||
|
)
|
||||||
break
|
break
|
||||||
case 'item.total_dps':
|
case 'item.total_dps':
|
||||||
propSet(query.filters, 'weapon_filters.filters.dps.min', typeof input.min === 'number' ? input.min : undefined)
|
propSet(
|
||||||
propSet(query.filters, 'weapon_filters.filters.dps.max', typeof input.max === 'number' ? input.max : undefined)
|
query.filters,
|
||||||
|
'weapon_filters.filters.dps.min',
|
||||||
|
typeof input.min === 'number' ? input.min : undefined
|
||||||
|
)
|
||||||
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'weapon_filters.filters.dps.max',
|
||||||
|
typeof input.max === 'number' ? input.max : undefined
|
||||||
|
)
|
||||||
break
|
break
|
||||||
case 'item.physical_dps':
|
case 'item.physical_dps':
|
||||||
propSet(query.filters, 'weapon_filters.filters.pdps.min', typeof input.min === 'number' ? input.min : undefined)
|
propSet(
|
||||||
propSet(query.filters, 'weapon_filters.filters.pdps.max', typeof input.max === 'number' ? input.max : undefined)
|
query.filters,
|
||||||
|
'weapon_filters.filters.pdps.min',
|
||||||
|
typeof input.min === 'number' ? input.min : undefined
|
||||||
|
)
|
||||||
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'weapon_filters.filters.pdps.max',
|
||||||
|
typeof input.max === 'number' ? input.max : undefined
|
||||||
|
)
|
||||||
break
|
break
|
||||||
case 'item.elemental_dps':
|
case 'item.elemental_dps':
|
||||||
propSet(query.filters, 'weapon_filters.filters.edps.min', typeof input.min === 'number' ? input.min : undefined)
|
propSet(
|
||||||
propSet(query.filters, 'weapon_filters.filters.edps.max', typeof input.max === 'number' ? input.max : undefined)
|
query.filters,
|
||||||
|
'weapon_filters.filters.edps.min',
|
||||||
|
typeof input.min === 'number' ? input.min : undefined
|
||||||
|
)
|
||||||
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'weapon_filters.filters.edps.max',
|
||||||
|
typeof input.max === 'number' ? input.max : undefined
|
||||||
|
)
|
||||||
break
|
break
|
||||||
case 'item.crit':
|
case 'item.crit':
|
||||||
propSet(query.filters, 'weapon_filters.filters.crit.min', typeof input.min === 'number' ? input.min : undefined)
|
propSet(
|
||||||
propSet(query.filters, 'weapon_filters.filters.crit.max', typeof input.max === 'number' ? input.max : undefined)
|
query.filters,
|
||||||
|
'weapon_filters.filters.crit.min',
|
||||||
|
typeof input.min === 'number' ? input.min : undefined
|
||||||
|
)
|
||||||
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'weapon_filters.filters.crit.max',
|
||||||
|
typeof input.max === 'number' ? input.max : undefined
|
||||||
|
)
|
||||||
break
|
break
|
||||||
case 'item.aps':
|
case 'item.aps':
|
||||||
propSet(query.filters, 'weapon_filters.filters.aps.min', typeof input.min === 'number' ? input.min : undefined)
|
propSet(
|
||||||
propSet(query.filters, 'weapon_filters.filters.aps.max', typeof input.max === 'number' ? input.max : undefined)
|
query.filters,
|
||||||
|
'weapon_filters.filters.aps.min',
|
||||||
|
typeof input.min === 'number' ? input.min : undefined
|
||||||
|
)
|
||||||
|
propSet(
|
||||||
|
query.filters,
|
||||||
|
'weapon_filters.filters.aps.max',
|
||||||
|
typeof input.max === 'number' ? input.max : undefined
|
||||||
|
)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stats = stats.filter(stat => !INTERNAL_TRADE_IDS.includes(stat.tradeId[0] as any))
|
stats = stats.filter(
|
||||||
|
(stat) => !INTERNAL_TRADE_IDS.includes(stat.tradeId[0] as any)
|
||||||
|
)
|
||||||
if (filters.veiled) {
|
if (filters.veiled) {
|
||||||
for (const statRef of filters.veiled.statRefs) {
|
for (const statRef of filters.veiled.statRefs) {
|
||||||
stats.push({
|
stats.push({
|
||||||
@@ -493,7 +716,9 @@ export function createTradeRequest (filters: ItemFilters, stats: StatFilter[], i
|
|||||||
text: undefined!,
|
text: undefined!,
|
||||||
tag: undefined!,
|
tag: undefined!,
|
||||||
sources: undefined!,
|
sources: undefined!,
|
||||||
tradeId: STAT_BY_REF(INFLUENCE_PSEUDO_TEXT[influence.value])!.trade.ids[ModifierType.Pseudo]
|
tradeId: STAT_BY_REF(INFLUENCE_PSEUDO_TEXT[influence.value])!.trade.ids[
|
||||||
|
ModifierType.Pseudo
|
||||||
|
]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -507,7 +732,7 @@ export function createTradeRequest (filters: ItemFilters, stats: StatFilter[], i
|
|||||||
type: 'count',
|
type: 'count',
|
||||||
value: { min: 1 },
|
value: { min: 1 },
|
||||||
disabled: stat.disabled,
|
disabled: stat.disabled,
|
||||||
filters: stat.tradeId.map(id => tradeIdToQuery(id, stat))
|
filters: stat.tradeId.map((id) => tradeIdToQuery(id, stat))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -517,7 +742,10 @@ export function createTradeRequest (filters: ItemFilters, stats: StatFilter[], i
|
|||||||
|
|
||||||
const cache = new Cache()
|
const cache = new Cache()
|
||||||
|
|
||||||
export async function requestTradeResultList (body: TradeRequest, leagueId: string): Promise<SearchResult> {
|
export async function requestTradeResultList (
|
||||||
|
body: TradeRequest,
|
||||||
|
leagueId: string
|
||||||
|
): Promise<SearchResult> {
|
||||||
let data = cache.get<SearchResult>([body, leagueId])
|
let data = cache.get<SearchResult>([body, leagueId])
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
@@ -528,24 +756,31 @@ export async function requestTradeResultList (body: TradeRequest, leagueId: stri
|
|||||||
|
|
||||||
await RateLimiter.waitMulti(RATE_LIMIT_RULES.SEARCH)
|
await RateLimiter.waitMulti(RATE_LIMIT_RULES.SEARCH)
|
||||||
|
|
||||||
const response = await Host.proxy(`${getTradeEndpoint()}/api/trade/search/${leagueId}`, {
|
const response = await Host.proxy(
|
||||||
method: 'POST',
|
`${getTradeEndpoint()}/api/trade2/search/${leagueId}`,
|
||||||
headers: {
|
{
|
||||||
'Accept': 'application/json',
|
method: 'POST',
|
||||||
'Content-Type': 'application/json'
|
headers: {
|
||||||
},
|
'Accept': 'application/json',
|
||||||
body: JSON.stringify(body)
|
'Content-Type': 'application/json'
|
||||||
})
|
},
|
||||||
|
body: JSON.stringify(body)
|
||||||
|
}
|
||||||
|
)
|
||||||
adjustRateLimits(RATE_LIMIT_RULES.SEARCH, response.headers)
|
adjustRateLimits(RATE_LIMIT_RULES.SEARCH, response.headers)
|
||||||
|
|
||||||
const _data = await response.json() as TradeResponse<SearchResult>
|
const _data = (await response.json()) as TradeResponse<SearchResult>
|
||||||
if (_data.error) {
|
if (_data.error) {
|
||||||
throw new Error(_data.error.message)
|
throw new Error(_data.error.message)
|
||||||
} else {
|
} else {
|
||||||
data = _data
|
data = _data
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.set<SearchResult>([body, leagueId], data, Cache.deriveTtl(...RATE_LIMIT_RULES.SEARCH, ...RATE_LIMIT_RULES.FETCH))
|
cache.set<SearchResult>(
|
||||||
|
[body, leagueId],
|
||||||
|
data,
|
||||||
|
Cache.deriveTtl(...RATE_LIMIT_RULES.SEARCH, ...RATE_LIMIT_RULES.FETCH)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return data
|
return data
|
||||||
@@ -561,36 +796,53 @@ export async function requestResults (
|
|||||||
if (!data) {
|
if (!data) {
|
||||||
await RateLimiter.waitMulti(RATE_LIMIT_RULES.FETCH)
|
await RateLimiter.waitMulti(RATE_LIMIT_RULES.FETCH)
|
||||||
|
|
||||||
const response = await Host.proxy(`${getTradeEndpoint()}/api/trade/fetch/${resultIds.join(',')}?query=${queryId}`)
|
const response = await Host.proxy(
|
||||||
|
`${getTradeEndpoint()}/api/trade2/fetch/${resultIds.join(',')}?query=${queryId}`
|
||||||
|
)
|
||||||
adjustRateLimits(RATE_LIMIT_RULES.FETCH, response.headers)
|
adjustRateLimits(RATE_LIMIT_RULES.FETCH, response.headers)
|
||||||
|
|
||||||
const _data = await response.json() as TradeResponse<{ result: Array<FetchResult | null> }>
|
const _data = (await response.json()) as TradeResponse<{
|
||||||
|
result: Array<FetchResult | null>
|
||||||
|
}>
|
||||||
if (_data.error) {
|
if (_data.error) {
|
||||||
throw new Error(_data.error.message)
|
throw new Error(_data.error.message)
|
||||||
} else {
|
} else {
|
||||||
data = _data.result.filter(res => res != null)
|
data = _data.result.filter((res) => res != null)
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.set<FetchResult[]>(resultIds, data, Cache.deriveTtl(...RATE_LIMIT_RULES.SEARCH, ...RATE_LIMIT_RULES.FETCH))
|
cache.set<FetchResult[]>(
|
||||||
|
resultIds,
|
||||||
|
data,
|
||||||
|
Cache.deriveTtl(...RATE_LIMIT_RULES.SEARCH, ...RATE_LIMIT_RULES.FETCH)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return data.map<PricingResult>(result => {
|
return data.map<PricingResult>((result) => {
|
||||||
return {
|
return {
|
||||||
id: result.id,
|
id: result.id,
|
||||||
itemLevel: result.item.properties?.find(prop => prop.type === 78)?.values[0][0] ?? String(result.item.ilvl),
|
itemLevel:
|
||||||
|
result.item.properties?.find((prop) => prop.type === 78)
|
||||||
|
?.values[0][0] ?? String(result.item.ilvl),
|
||||||
stackSize: result.item.stackSize,
|
stackSize: result.item.stackSize,
|
||||||
corrupted: result.item.corrupted,
|
corrupted: result.item.corrupted,
|
||||||
quality: result.item.properties?.find(prop => prop.type === 6)?.values[0][0],
|
quality: result.item.properties?.find((prop) => prop.type === 6)
|
||||||
level: result.item.properties?.find(prop => prop.type === 5)?.values[0][0],
|
?.values[0][0],
|
||||||
relativeDate: DateTime.fromISO(result.listing.indexed).toRelative({ style: 'short' }) ?? '',
|
level: result.item.properties?.find((prop) => prop.type === 5)
|
||||||
|
?.values[0][0],
|
||||||
|
relativeDate:
|
||||||
|
DateTime.fromISO(result.listing.indexed).toRelative({
|
||||||
|
style: 'short'
|
||||||
|
}) ?? '',
|
||||||
priceAmount: result.listing.price?.amount ?? 0,
|
priceAmount: result.listing.price?.amount ?? 0,
|
||||||
priceCurrency: result.listing.price?.currency ?? 'no price',
|
priceCurrency: result.listing.price?.currency ?? 'no price',
|
||||||
hasNote: result.item.note != null,
|
hasNote: result.item.note != null,
|
||||||
isMine: (result.listing.account.name === opts.accountName),
|
isMine: result.listing.account.name === opts.accountName,
|
||||||
ign: result.listing.account.lastCharacterName,
|
ign: result.listing.account.lastCharacterName,
|
||||||
accountName: result.listing.account.name,
|
accountName: result.listing.account.name,
|
||||||
accountStatus: result.listing.account.online
|
accountStatus: result.listing.account.online
|
||||||
? (result.listing.account.online.status === 'afk' ? 'afk' : 'online')
|
? result.listing.account.online.status === 'afk'
|
||||||
|
? 'afk'
|
||||||
|
: 'online'
|
||||||
: 'offline'
|
: 'offline'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -619,28 +871,26 @@ function tradeIdToQuery (id: string, stat: StatFilter) {
|
|||||||
if (stat.roll?.value === 100) {
|
if (stat.roll?.value === 100) {
|
||||||
roll = undefined // stat semantic type is flag
|
roll = undefined // stat semantic type is flag
|
||||||
}
|
}
|
||||||
// fixes "Cannot be Poisoned" from Essence
|
// fixes "Cannot be Poisoned" from Essence
|
||||||
} else if (id === 'explicit.stat_3835551335') {
|
} else if (id === 'explicit.stat_3835551335') {
|
||||||
if (stat.roll?.value === 100) {
|
if (stat.roll?.value === 100) {
|
||||||
roll = undefined // stat semantic type is flag
|
roll = undefined // stat semantic type is flag
|
||||||
}
|
}
|
||||||
// fixes "Instant Recovery" on Flasks
|
// fixes "Instant Recovery" on Flasks
|
||||||
} else if (id.endsWith('stat_1526933524')) {
|
} else if (id.endsWith('stat_1526933524')) {
|
||||||
if (stat.roll?.value === 100) {
|
if (stat.roll?.value === 100) {
|
||||||
roll = undefined // stat semantic type is flag
|
roll = undefined // stat semantic type is flag
|
||||||
}
|
}
|
||||||
// fixes Delve "Reservation Efficiency of Skills"
|
// fixes Delve "Reservation Efficiency of Skills"
|
||||||
} else if (id.endsWith('stat_1269219558')) {
|
} else if (id.endsWith('stat_1269219558')) {
|
||||||
roll = { ...roll!, tradeInvert: !(roll!.tradeInvert) }
|
roll = { ...roll!, tradeInvert: !roll!.tradeInvert }
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
value: {
|
value: {
|
||||||
...getMinMax(roll),
|
...getMinMax(roll),
|
||||||
option: stat.option != null
|
option: stat.option != null ? stat.option.value : undefined
|
||||||
? stat.option.value
|
|
||||||
: undefined
|
|
||||||
},
|
},
|
||||||
disabled: stat.disabled
|
disabled: stat.disabled
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ export default defineComponent({
|
|||||||
: autoCurrency(trend.chaos)
|
: autoCurrency(trend.chaos)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
price: price,
|
price,
|
||||||
change: deltaFromGraph(trend.graph),
|
change: deltaFromGraph(trend.graph),
|
||||||
url: trend.url
|
url: trend.url
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export default defineComponent({
|
|||||||
function select (info: BaseType) {
|
function select (info: BaseType) {
|
||||||
const newItem: ParsedItem = {
|
const newItem: ParsedItem = {
|
||||||
...props.item!,
|
...props.item!,
|
||||||
info: info
|
info
|
||||||
}
|
}
|
||||||
ctx.emit('identify', newItem)
|
ctx.emit('identify', newItem)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,51 +1,51 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div :class="$style.podium" v-if="podiumVisible">
|
<div :class="$style.podium" v-if="podiumVisible">
|
||||||
<div v-for="i in [2, 4, 5, 3, 1]">
|
<div v-for="i in [2, 4, 5, 3, 1]">
|
||||||
<div v-for="patron in patrons[i - 1]" :key="patron.from"
|
<div v-for="patron in patrons[i - 1]" :key="patron.from"
|
||||||
:class="[$style.rating, $style[`rating-${patron.style}`]]"
|
:class="[$style.rating, $style[`rating-${patron.style}`]]">{{ patron.from }}{{ (patron.months > 1) ? `
|
||||||
>{{ patron.from }}{{ (patron.months > 1) ? ` x${patron.months}` : null }}</div>
|
x${patron.months}` : null }}</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div :class="[$style.patronsHorizontal, { 'invisible': podiumVisible }]" :onMouseenter="showPodium">
|
|
||||||
<div class="bg-gray-800 rounded p-1 justify-center text-center w-44 shrink-0 flex items-center">
|
|
||||||
{{ t('settings.thank_you') }}
|
|
||||||
</div>
|
|
||||||
<div class="overflow-x-hidden whitespace-nowrap p-1 text-base">
|
|
||||||
<span :class="$style.patronsLine">{{ patronsString[0] }}</span><br>
|
|
||||||
<span :class="$style.patronsLine">{{ patronsString[1] }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div :class="$style.window" class="grow layout-column" :onMouseenter="hidePodium">
|
|
||||||
<AppTitleBar @close="cancel" :title="t('settings.title')" />
|
|
||||||
<div class="flex grow min-h-0">
|
|
||||||
<div class="pl-2 pt-2 bg-gray-900 flex flex-col gap-1" style="min-width: 10rem;">
|
|
||||||
<template v-for="item of menuItems">
|
|
||||||
<button v-if="item.type === 'menu-item'"
|
|
||||||
@click="item.select" :class="[$style['menu-item'], { [$style['active']]: item.isSelected }]">{{ item.name }}</button>
|
|
||||||
<div v-else
|
|
||||||
class="border-b mx-2 border-gray-800" />
|
|
||||||
</template>
|
|
||||||
<button v-if="menuItems.length >= 4"
|
|
||||||
:class="$style['quit-btn']" @click="quit">{{ t('app.quit') }}</button>
|
|
||||||
<div class="text-gray-400 text-center mt-auto pr-3 pt-4 pb-12" style="max-width: fit-content; min-width: 100%;">
|
|
||||||
<img class="mx-auto mb-1" src="/images/peepoLove2x.webp">
|
|
||||||
{{ t('Support development on') }}<br> <a href="https://patreon.com/awakened_poe_trade" class="inline-flex mt-1" target="_blank"><img class="inline h-5" src="/images/Patreon.svg"></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="text-gray-100 grow layout-column bg-gray-900">
|
</div>
|
||||||
<div class="grow overflow-y-auto bg-gray-800 rounded-tl">
|
<div :class="[$style.patronsHorizontal, { 'invisible': podiumVisible }]" :onMouseenter="showPodium">
|
||||||
<component v-if="configClone"
|
<div class="bg-gray-800 rounded p-1 justify-center text-center w-44 shrink-0 flex items-center">
|
||||||
:is="selectedComponent" :config="configClone" :configWidget="configWidget" />
|
{{ t('settings.thank_you') }}
|
||||||
|
</div>
|
||||||
|
<div class="overflow-x-hidden whitespace-nowrap p-1 text-base">
|
||||||
|
<span :class="$style.patronsLine">{{ patronsString[0] }}</span><br>
|
||||||
|
<span :class="$style.patronsLine">{{ patronsString[1] }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div :class="$style.window" class="grow layout-column" :onMouseenter="hidePodium">
|
||||||
|
<ConversionWarningBanner />
|
||||||
|
<AppTitleBar @close="cancel" :title="t('settings.title')" />
|
||||||
|
<div class="flex grow min-h-0">
|
||||||
|
<div class="pl-2 pt-2 bg-gray-900 flex flex-col gap-1" style="min-width: 10rem;">
|
||||||
|
<template v-for="item of menuItems">
|
||||||
|
<button v-if="item.type === 'menu-item'" @click="item.select"
|
||||||
|
:class="[$style['menu-item'], { [$style['active']]: item.isSelected }]">{{ item.name }}</button>
|
||||||
|
<div v-else class="border-b mx-2 border-gray-800" />
|
||||||
|
</template>
|
||||||
|
<button v-if="menuItems.length >= 4" :class="$style['quit-btn']" @click="quit">{{ t('app.quit') }}</button>
|
||||||
|
<div class="text-gray-400 text-center mt-auto pr-3 pt-4 pb-12"
|
||||||
|
style="max-width: fit-content; min-width: 100%;">
|
||||||
|
<img class="mx-auto mb-1" src="/images/peepoLove2x.webp">
|
||||||
|
{{ t('Support development on') }}<br> <a href="https://patreon.com/awakened_poe_trade"
|
||||||
|
class="inline-flex mt-1" target="_blank"><img class="inline h-5" src="/images/Patreon.svg"></a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="border-t bg-gray-900 border-gray-600 p-2 flex justify-end gap-x-2">
|
<div class="text-gray-100 grow layout-column bg-gray-900">
|
||||||
<button @click="save" class="px-3 bg-gray-800 rounded">{{ t('Save') }}</button>
|
<div class="grow overflow-y-auto bg-gray-800 rounded-tl">
|
||||||
<button @click="cancel" class="px-3">{{ t('Cancel') }}</button>
|
<component v-if="configClone" :is="selectedComponent" :config="configClone" :configWidget="configWidget" />
|
||||||
|
</div>
|
||||||
|
<div class="border-t bg-gray-900 border-gray-600 p-2 flex justify-end gap-x-2">
|
||||||
|
<button @click="save" class="px-3 bg-gray-800 rounded">{{ t('Save') }}</button>
|
||||||
|
<button @click="cancel" class="px-3">{{ t('Cancel') }}</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -67,6 +67,7 @@ import SettingsMaps from '../map-check/settings-maps.vue'
|
|||||||
import SettingsStashSearch from '../stash-search/stash-search-editor.vue'
|
import SettingsStashSearch from '../stash-search/stash-search-editor.vue'
|
||||||
import SettingsStopwatch from './stopwatch.vue'
|
import SettingsStopwatch from './stopwatch.vue'
|
||||||
import SettingsItemSearch from '../item-search/settings-item-search.vue'
|
import SettingsItemSearch from '../item-search/settings-item-search.vue'
|
||||||
|
import ConversionWarningBanner from '../conversion-warn-banner/ConversionWarningBanner.vue'
|
||||||
|
|
||||||
function shuffle<T> (array: T[]): T[] {
|
function shuffle<T> (array: T[]): T[] {
|
||||||
let currentIndex = array.length
|
let currentIndex = array.length
|
||||||
@@ -87,7 +88,7 @@ function quit () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { AppTitleBar },
|
components: { AppTitleBar, ConversionWarningBanner },
|
||||||
props: {
|
props: {
|
||||||
config: {
|
config: {
|
||||||
type: Object as PropType<Widget>,
|
type: Object as PropType<Widget>,
|
||||||
@@ -218,13 +219,17 @@ function flatJoin<T, J> (arr: T[][], joinEl: () => J) {
|
|||||||
<style lang="postcss" module>
|
<style lang="postcss" module>
|
||||||
.window {
|
.window {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0; bottom: 0; left: 0; right: 0;
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
max-width: 50rem;
|
max-width: 50rem;
|
||||||
max-height: 38rem;
|
max-height: 38rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@apply bg-gray-800;
|
@apply bg-gray-800;
|
||||||
@apply rounded-b;
|
@apply rounded-b;
|
||||||
|
|
||||||
&:global {
|
&:global {
|
||||||
animation-name: slideInDown;
|
animation-name: slideInDown;
|
||||||
animation-duration: 1s;
|
animation-duration: 1s;
|
||||||
@@ -262,10 +267,13 @@ function flatJoin<T, J> (arr: T[][], joinEl: () => J) {
|
|||||||
.patronsHorizontal {
|
.patronsHorizontal {
|
||||||
@apply bg-gray-900 p-1 rounded gap-1;
|
@apply bg-gray-900 p-1 rounded gap-1;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 40rem; left: 0; right: 0;
|
top: 40rem;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
max-width: 50rem;
|
max-width: 50rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
&:global {
|
&:global {
|
||||||
animation-name: slideInDown;
|
animation-name: slideInDown;
|
||||||
animation-duration: 1s;
|
animation-duration: 1s;
|
||||||
@@ -273,10 +281,19 @@ function flatJoin<T, J> (arr: T[][], joinEl: () => J) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes slide {
|
@keyframes slide {
|
||||||
0% { transform: translate(0%, 0); }
|
0% {
|
||||||
4% { transform: translate(0%, 0); }
|
transform: translate(0%, 0);
|
||||||
100% { transform: translate(-99%, 0); }
|
}
|
||||||
|
|
||||||
|
4% {
|
||||||
|
transform: translate(0%, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: translate(-99%, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.patronsLine {
|
.patronsLine {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
animation: slide 64s linear infinite;
|
animation: slide 64s linear infinite;
|
||||||
@@ -291,22 +308,40 @@ function flatJoin<T, J> (arr: T[][], joinEl: () => J) {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@apply gap-4 p-4;
|
@apply gap-4 p-4;
|
||||||
|
|
||||||
&:global {
|
&:global {
|
||||||
animation-name: fadeIn;
|
animation-name: fadeIn;
|
||||||
animation-duration: 1.5s;
|
animation-duration: 1.5s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.podium > div {
|
|
||||||
|
.podium>div {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
min-width: min-content;
|
min-width: min-content;
|
||||||
}
|
}
|
||||||
.podium > div:nth-child(1) { max-width: 18rem; }
|
|
||||||
.podium > div:nth-child(2) { max-width: 16rem; }
|
.podium>div:nth-child(1) {
|
||||||
.podium > div:nth-child(3) { flex-direction: column; align-items: center; }
|
max-width: 18rem;
|
||||||
.podium > div:nth-child(4) { max-width: 24rem; }
|
}
|
||||||
.podium > div:nth-child(5) { max-width: 18rem; }
|
|
||||||
|
.podium>div:nth-child(2) {
|
||||||
|
max-width: 16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.podium>div:nth-child(3) {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.podium>div:nth-child(4) {
|
||||||
|
max-width: 24rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.podium>div:nth-child(5) {
|
||||||
|
max-width: 18rem;
|
||||||
|
}
|
||||||
|
|
||||||
.rating {
|
.rating {
|
||||||
min-width: 3rem;
|
min-width: 3rem;
|
||||||
@@ -314,30 +349,35 @@ function flatJoin<T, J> (arr: T[][], joinEl: () => J) {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@apply px-1 border;
|
@apply px-1 border;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rating-1 {
|
.rating-1 {
|
||||||
background-color: rgb(0, 0, 0);
|
background-color: rgb(0, 0, 0);
|
||||||
color: rgb(190, 178, 135);
|
color: rgb(190, 178, 135);
|
||||||
border-color: currentColor;
|
border-color: currentColor;
|
||||||
@apply text-base;
|
@apply text-base;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rating-2 {
|
.rating-2 {
|
||||||
background-color: rgb(210, 178, 135);
|
background-color: rgb(210, 178, 135);
|
||||||
color: rgb(0, 0, 0);
|
color: rgb(0, 0, 0);
|
||||||
border-color: currentColor;
|
border-color: currentColor;
|
||||||
@apply text-lg;
|
@apply text-lg;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rating-3 {
|
.rating-3 {
|
||||||
background-color: rgb(213, 159, 0);
|
background-color: rgb(213, 159, 0);
|
||||||
color: rgb(0, 0, 0);
|
color: rgb(0, 0, 0);
|
||||||
border-color: currentColor;
|
border-color: currentColor;
|
||||||
@apply text-lg;
|
@apply text-lg;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rating-4 {
|
.rating-4 {
|
||||||
background-color: rgb(240, 90, 35);
|
background-color: rgb(240, 90, 35);
|
||||||
color: rgb(255, 255, 255);
|
color: rgb(255, 255, 255);
|
||||||
border-color: currentColor;
|
border-color: currentColor;
|
||||||
@apply text-xl;
|
@apply text-xl;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rating-5 {
|
.rating-5 {
|
||||||
background-color: rgb(255, 255, 255);
|
background-color: rgb(255, 255, 255);
|
||||||
color: rgb(255, 0, 0);
|
color: rgb(255, 0, 0);
|
||||||
|
|||||||
@@ -2,24 +2,28 @@
|
|||||||
<div class="p-2 flex flex-col h-full items-center">
|
<div class="p-2 flex flex-col h-full items-center">
|
||||||
<div class="flex flex-col items-center p-2 mb-4">
|
<div class="flex flex-col items-center p-2 mb-4">
|
||||||
<img class="w-12 h-12" src="/images/TransferOrb.png">
|
<img class="w-12 h-12" src="/images/TransferOrb.png">
|
||||||
<p class="text-base">Awakened PoE Trade</p>
|
<p class="text-base">Exiled Exchange 2</p>
|
||||||
<p class="">{{ t('app.version', [version]) }}</p>
|
<p class="">{{ t('app.version', [version]) }}</p>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<a class="border-b" href="https://github.com/SnosMe/awakened-poe-trade/releases" target="_blank">{{ t('app.release_notes') }}</a>
|
<a class="border-b" href="https://github.com/Kvan7/exiled-exchange-2/releases" target="_blank">{{
|
||||||
<a class="border-b" href="https://github.com/SnosMe/awakened-poe-trade/issues" target="_blank">{{ t('app.report_bug') }}</a>
|
t('app.release_notes') }}</a>
|
||||||
|
<a class="border-b" href="https://github.com/Kvan7/exiled-exchange-2/issues" target="_blank">{{
|
||||||
|
t('app.report_bug') }}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="border border-gray-600 rounded p-2 whitespace-nowrap min-w-min w-72">
|
<div class="border border-gray-600 rounded p-2 whitespace-nowrap min-w-min w-72">
|
||||||
<p>{{ info.str1 }}</p>
|
<p>{{ info.str1 }}</p>
|
||||||
<p>{{ info.str2 }}</p>
|
<p>{{ info.str2 }}</p>
|
||||||
<button v-if="info.action" @click="info.action"
|
<button v-if="info.action" @click="info.action" class="btn w-full mt-1">{{ info.actionText }}</button>
|
||||||
class="btn w-full mt-1">{{ info.actionText }}</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center mt-auto py-8">
|
<div class="text-center mt-auto py-8">
|
||||||
<p>{{ t('app.contact_me') }} <br><span class="font-sans text-gray-500 select-all"><@295216259795124225></span></p>
|
<p>{{ t('app.contact_me') }} <br><span
|
||||||
|
class="font-sans text-gray-500 select-all"><@295216259795124225></span></p>
|
||||||
<ul class="flex gap-4">
|
<ul class="flex gap-4">
|
||||||
<li><img class="rounded inline" src="/images/dc_tft.gif"> <a class="border-b" href="https://discord.gg/tftrove" target="_blank">The Forbidden Trove</a></li>
|
<li><img class="rounded inline" src="/images/dc_tft.gif"> <a class="border-b" href="https://discord.gg/tftrove"
|
||||||
<li><img class="rounded inline" src="/images/dc_reddit.png"> <a class="border-b" href="https://discord.gg/pathofexile" target="_blank">r/pathofexile</a></li>
|
target="_blank">The Forbidden Trove</a></li>
|
||||||
|
<li><img class="rounded inline" src="/images/dc_reddit.png"> <a class="border-b"
|
||||||
|
href="https://discord.gg/pathofexile" target="_blank">r/pathofexile</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -39,7 +43,7 @@ function checkForUpdates () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function openDownloadPage () {
|
function openDownloadPage () {
|
||||||
window.open('https://snosme.github.io/awakened-poe-trade/download')
|
window.open('https://github.com/Kvan7/exiled-exchange-2/releases')
|
||||||
}
|
}
|
||||||
|
|
||||||
function quitAndInstall () {
|
function quitAndInstall () {
|
||||||
@@ -63,19 +67,50 @@ export default defineComponent({
|
|||||||
const rawInfo = Host.updateInfo.value
|
const rawInfo = Host.updateInfo.value
|
||||||
switch (rawInfo.state) {
|
switch (rawInfo.state) {
|
||||||
case 'initial':
|
case 'initial':
|
||||||
return { str1: t('updates.maybe_outdated'), str2: t('updates.never_checked'), action: checkForUpdates, actionText: t('updates.check_now') }
|
return {
|
||||||
|
str1: t('updates.maybe_outdated'),
|
||||||
|
str2: t('updates.never_checked'),
|
||||||
|
action: checkForUpdates,
|
||||||
|
actionText: t('updates.check_now')
|
||||||
|
}
|
||||||
case 'checking-for-update':
|
case 'checking-for-update':
|
||||||
return { str1: t('updates.checking'), str2: t('please_wait') }
|
return { str1: t('updates.checking'), str2: t('please_wait') }
|
||||||
case 'update-not-available':
|
case 'update-not-available':
|
||||||
return { str1: t('updates.latest'), str2: t('updates.last_checked', [fmtTime(rawInfo.checkedAt)]), action: checkForUpdates, actionText: t('updates.check_now') }
|
return {
|
||||||
|
str1: t('updates.latest'),
|
||||||
|
str2: t('updates.last_checked', [fmtTime(rawInfo.checkedAt)]),
|
||||||
|
action: checkForUpdates,
|
||||||
|
actionText: t('updates.check_now')
|
||||||
|
}
|
||||||
case 'error':
|
case 'error':
|
||||||
return { str1: t('updates.maybe_outdated'), str2: t('updates.error'), action: openDownloadPage, actionText: t('updates.downloads_page') }
|
return {
|
||||||
|
str1: t('updates.maybe_outdated'),
|
||||||
|
str2: t('updates.error'),
|
||||||
|
action: openDownloadPage,
|
||||||
|
actionText: t('updates.downloads_page')
|
||||||
|
}
|
||||||
case 'update-downloaded':
|
case 'update-downloaded':
|
||||||
return { str1: t('updates.available', [rawInfo.version]), str2: t('updates.installed_on_exit'), action: quitAndInstall, actionText: t('updates.install_now') }
|
return {
|
||||||
|
str1: t('updates.available', [rawInfo.version]),
|
||||||
|
str2: t('updates.installed_on_exit'),
|
||||||
|
action: quitAndInstall,
|
||||||
|
actionText: t('updates.install_now')
|
||||||
|
}
|
||||||
case 'update-available':
|
case 'update-available':
|
||||||
return (rawInfo.noDownloadReason)
|
return rawInfo.noDownloadReason
|
||||||
? { str1: t('updates.available', [rawInfo.version]), str2: (rawInfo.noDownloadReason === 'not-supported') ? t('updates.download_manually') : t('updates.download_disabled'), action: openDownloadPage, actionText: t('updates.downloads_page') }
|
? {
|
||||||
: { str1: t('updates.available', [rawInfo.version]), str2: t('updates.downloading') }
|
str1: t('updates.available', [rawInfo.version]),
|
||||||
|
str2:
|
||||||
|
rawInfo.noDownloadReason === 'not-supported'
|
||||||
|
? t('updates.download_manually')
|
||||||
|
: t('updates.download_disabled'),
|
||||||
|
action: openDownloadPage,
|
||||||
|
actionText: t('updates.downloads_page')
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
str1: t('updates.available', [rawInfo.version]),
|
||||||
|
str2: t('updates.downloading')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -28,12 +28,12 @@
|
|||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<div class="flex-1 mb-1">{{ t(':poe_log_file') }}</div>
|
<div class="flex-1 mb-1">{{ t(':poe_log_file') }}</div>
|
||||||
<input v-model.trim="clientLog"
|
<input v-model.trim="clientLog"
|
||||||
class="rounded bg-gray-900 px-1 block w-full font-sans" placeholder="...?/Grinding Gear Games/Path of Exile/logs/Client.txt">
|
class="rounded bg-gray-900 px-1 block w-full font-sans" placeholder="...?/Grinding Gear Games/Path of Exile 2/logs/Client.txt">
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<div class="flex-1 mb-1">{{ t(':poe_cfg_file') }}</div>
|
<div class="flex-1 mb-1">{{ t(':poe_cfg_file') }}</div>
|
||||||
<input v-model.trim="gameConfig"
|
<input v-model.trim="gameConfig"
|
||||||
class="rounded bg-gray-900 px-1 block w-full font-sans" placeholder="...?/My Games/Path of Exile/production_Config.ini">
|
class="rounded bg-gray-900 px-1 block w-full font-sans" placeholder="...?/My Games/Path of Exile 2/poe2_production_Config.ini">
|
||||||
</div>
|
</div>
|
||||||
<hr class="mb-4 mx-8 border-gray-700">
|
<hr class="mb-4 mx-8 border-gray-700">
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
|
|||||||
22
testUpdate.sh
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Remove ./renderer/dist if it exists
|
||||||
|
rm -rf ./renderer/dist
|
||||||
|
|
||||||
|
# Remove ./main/dist if it exists
|
||||||
|
rm -rf ./main/dist
|
||||||
|
|
||||||
|
cd ./renderer
|
||||||
|
|
||||||
|
npm install
|
||||||
|
npm run make-index-files
|
||||||
|
npm run build
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
cd ./main
|
||||||
|
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
npm run package
|
||||||
|
|
||||||
|
|
||||||