Compare commits

..

85 Commits

Author SHA1 Message Date
DarkPhoenix
7b5c95213f Bump version 2024-09-18 13:54:33 +02:00
DarkPhoenix
1312177e0e Add new renames 2024-09-18 13:42:53 +02:00
DarkPhoenix
5b0df0a9c3 Update static data to 2682489 2024-09-18 13:33:03 +02:00
DarkPhoenix
1ea6136cb2 Update static data 2024-09-11 16:32:13 +02:00
DarkPhoenix
da2b6bbb6d Bump version 2024-09-10 00:01:40 +02:00
DarkPhoenix
87007af5f8 Pass package path to importlib call, not module path 2024-09-09 23:35:07 +02:00
DarkPhoenix
dd5ab872b1 Reapply "Make it 3.9+, but get rid of deprecation warnings"
This reverts commit 65fb46885a.
2024-09-09 23:31:19 +02:00
DarkPhoenix
65fb46885a Revert "Make it 3.9+, but get rid of deprecation warnings"
This reverts commit 01354a0a83.
2024-09-09 23:00:24 +02:00
DarkPhoenix
fad1e401b2 Bump version 2024-09-09 20:25:02 +02:00
DarkPhoenix
d59f8afd8a Update icons 2024-09-09 20:24:33 +02:00
DarkPhoenix
7c42d00219 Update static data 2024-09-09 20:20:44 +02:00
DarkPhoenix
777ba69ac4 Ensure context menus can be called on items w/o market group 2024-07-20 19:09:00 +02:00
DarkPhoenix
9a3bde872b Fix regex pattern to remove syntax warning 2024-07-09 23:23:49 +02:00
DarkPhoenix
01354a0a83 Make it 3.9+, but get rid of deprecation warnings 2024-07-09 21:49:05 +02:00
DarkPhoenix
8c3b8589d5 Adjust jargon loader to be py3.12-compatible 2024-07-09 21:46:39 +02:00
Anton Vorobyov
451b5d4312 Merge pull request #2624 from lunedis/feature/charges-for-fit
Add "Charges For Active Fit" market tree shortcut
2024-07-09 23:31:53 +04:00
Anton Vorobyov
d204e70afc Merge pull request #2614 from kgasiorowski/issue/2613
Rename Industrial to Hauler
2024-07-09 23:29:02 +04:00
Karl Werner
ce9ce17ad2 use mode to limit refresh 2024-07-07 14:41:16 +02:00
Karl Werner
6a7cdda91a add comments 2024-07-06 16:01:58 +02:00
Karl Werner
f38c61da51 update on fit change, new icon 2024-07-06 15:52:18 +02:00
Karl Werner
735827a25b proof of concept 2024-07-06 12:12:48 +02:00
DarkPhoenix
d3fcdcbe47 Marshal bonus is not stacking penalized 2024-06-29 23:50:03 +02:00
DarkPhoenix
a3dce73663 Update static data 2024-06-27 21:21:35 +02:00
Kuba Gasiorowski
594b58388f Merge branch 'master' into issue/2613 2024-06-14 18:40:49 -04:00
DarkPhoenix
fa6be2edfb Bump version 2024-06-13 16:20:49 +02:00
DarkPhoenix
1177968b02 Update renders 2024-06-13 16:20:29 +02:00
DarkPhoenix
c04b370410 Update static data 2024-06-13 16:15:45 +02:00
DarkPhoenix
038b95531d Bump version 2024-06-12 16:04:00 +02:00
DarkPhoenix
56bc5c3376 Fix icons script and add missing renders 2024-06-12 16:03:09 +02:00
DarkPhoenix
f5d8be7861 Update static data and add new effect 2024-06-12 15:11:15 +02:00
Kuba Gasiorowski
5366c23db2 Merge branch 'master' into issue/2613 2024-06-11 14:03:24 -04:00
DarkPhoenix
d147db22f1 Bump version 2024-06-11 16:33:10 +02:00
DarkPhoenix
28ebcd2739 Fix upwell ship race detection 2024-06-08 03:12:34 +02:00
DarkPhoenix
2f57eb6ea6 Bump version 2024-06-08 03:01:13 +02:00
DarkPhoenix
3a7ee4699e Update effects and related things 2024-06-08 03:00:45 +02:00
DarkPhoenix
fa7f991fae Update icons 2024-06-08 01:37:13 +02:00
DarkPhoenix
0be8b429aa Add renames 2024-06-08 01:19:22 +02:00
DarkPhoenix
7d94e2de7d Update static data to 2604967 2024-06-08 00:57:34 +02:00
Kuba Gasiorowski
6d32db5827 Rename Industrial to Hauler 2024-05-26 23:45:27 -04:00
DarkPhoenix
0fbb318d8a Bump version 2024-04-30 04:10:53 +06:00
DarkPhoenix
cd013e8287 Add new effects 2024-04-30 04:10:33 +06:00
DarkPhoenix
e667453c1e Add new icons 2024-04-30 03:59:25 +06:00
DarkPhoenix
24e2db0f88 Update static data to 2563119 2024-04-30 03:55:34 +06:00
DarkPhoenix
3c47f8c6bb Add OS version comments to windows manifest 2024-04-17 02:42:42 +06:00
DarkPhoenix
42c2b3f253 Bundle extra library with appimage 2024-04-16 22:16:35 +06:00
DarkPhoenix
71d6830ac0 Bundle extra library with appimage 2024-04-16 22:03:25 +06:00
DarkPhoenix
ac2fb01a7c Update icons 2024-04-16 21:32:17 +06:00
DarkPhoenix
fc66c212fc Bump version 2024-04-16 21:31:29 +06:00
DarkPhoenix
9625fafda7 Merge remote-tracking branch 'origin/master' 2024-04-16 21:21:46 +06:00
DarkPhoenix
6b1aca4306 Update static data to 2550121 2024-04-16 21:21:33 +06:00
Anton Vorobyov
fd5a094304 Merge pull request #2597 from josephdouce/patch-2
Searchable exportHtml.py
2024-02-28 20:10:02 +04:00
Joseph Douce
a3142ff62f Update exportHtml.py 2024-02-28 15:36:02 +00:00
Joseph Douce
58ebfd3643 Searchable exportHtml.py
added searchable fits
2024-02-28 15:33:18 +00:00
Anton Vorobyov
e272267842 Merge pull request #2596 from josephdouce/patch-1
Fix exportHtml.py
2024-02-28 19:25:20 +04:00
Joseph Douce
b0256542bc Fix exportHtml.py 2024-02-28 13:17:23 +00:00
DarkPhoenix
9b8fd24987 Update pot 2024-02-27 16:30:06 +06:00
DarkPhoenix
9c68889a6d Call SelectAll() after Fit() since that's what seems to be causing issues under windows 2024-02-27 08:15:39 +06:00
DarkPhoenix
a4ed6e8066 Move select all call earlier, to see which call breaks it on windows 2024-02-27 07:38:01 +06:00
DarkPhoenix
9fe8163a69 Select all text even later 2024-02-27 05:54:55 +06:00
DarkPhoenix
9f9b496726 Select all text even later 2024-02-27 05:30:03 +06:00
DarkPhoenix
3b8fa68a4c Bump version 2024-02-27 04:11:02 +06:00
DarkPhoenix
9f5a649b04 Change migration to include newly added constraints 2024-02-27 04:05:19 +06:00
DarkPhoenix
fb45736c14 Extend UNIQUE constraint by new server column, to avoid possible collisions 2024-02-27 03:36:43 +06:00
Anton Vorobyov
b8a58fc7a6 Merge pull request #2590 from huangzheng2016/master
Update the SSO Login for Serenity and Singularity server's player
2024-02-26 23:35:31 +04:00
DarkPhoenix
b04c521805 Make sure not to crash character editor during SSO init when char editor is opened 2024-02-27 01:18:01 +06:00
DarkPhoenix
526695fa9a Try setting size for graph input boxes as a workaround for wx bug 2024-02-27 00:30:19 +06:00
Anton Vorobyov
d6be77d107 Merge pull request #2589 from pyfa-org/dependabot/pip/cryptography-42.0.4
Bump cryptography from 42.0.2 to 42.0.4
2024-02-26 22:22:33 +04:00
DarkPhoenix
907da343b1 Rework how progress dialog is used 2024-02-27 00:04:44 +06:00
DarkPhoenix
3fadccc715 Select all after setting focus as an attempt to fix input box not selecting everything under windows 2024-02-26 06:25:07 +06:00
DarkPhoenix
82a912858f Fix items in market's item view 2024-02-26 04:45:18 +06:00
正汰
cc1fdddc0a Merge branch 'pyfa-org:master' into master 2024-02-23 02:50:41 +08:00
正汰
e314ecf887 Fix the esi problem for Serenity when setting 2024-02-23 02:48:54 +08:00
正汰
94b1c8b029 Fix the esi problem for Serenity when setting 2024-02-23 02:47:59 +08:00
正汰
6e3b7ff132 Fix the esi problem for Serenity when setting 2024-02-23 02:47:47 +08:00
正汰
ff14855808 Fix the esi problem for Serenity when setting 2024-02-23 02:47:27 +08:00
dependabot[bot]
4761857b84 Bump cryptography from 42.0.2 to 42.0.4
Bumps [cryptography](https://github.com/pyca/cryptography) from 42.0.2 to 42.0.4.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/42.0.2...42.0.4)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-21 20:48:49 +00:00
DarkPhoenix
bb53e75bfe Force light rack colors on windows regardless of OS theme 2024-02-21 03:04:36 +06:00
正汰
be85080d8d Merge branch 'pyfa-org:master' into master 2024-01-12 11:00:13 +08:00
blitzmann
27101732ca Add a couple of bug fixes, and make the server option a checkbox 2022-05-08 13:48:38 -04:00
blitzmann
ed48a8b5d0 Re-work the exceptions related to logging a character in 2022-05-08 13:21:23 -04:00
blitzmann
5a6fe373f1 Merge branch 'master' into huangzheng2016-master
# Conflicts:
#	gui/builtinPreferenceViews/pyfaEsiPreferences.py
2022-05-08 12:35:46 -04:00
blitzmann
3c6eb6d054 Some updates to allow code / token paste regardless of server setting 2022-05-08 12:24:12 -04:00
blitzmann
dc997f0dc4 Various updates to support server-aware calls per character 2022-05-07 12:35:16 -04:00
blitzmann
14afc83e86 Fix client ID that is used 2022-04-30 10:17:51 -04:00
hz2016
216dd2a787 Update the SSO Login for Serenity and Singularity server's player 2022-04-28 15:58:33 +08:00
430 changed files with 99268 additions and 4209 deletions

View File

@@ -2,7 +2,7 @@
## Requirements
- Python 3.7
- Python 3.11
- Git CLI installed
- Python, pip and git are all available as command-line commands (add to the path if needed)

View File

@@ -9,6 +9,7 @@ import hashlib
from eos.const import FittingSlot
from cryptography.fernet import Fernet
from collections import namedtuple
pyfalog = Logger(__name__)
@@ -44,9 +45,16 @@ experimentalFeatures = None
version = None
language = None
API_CLIENT_ID = '095d8cd841ac40b581330919b49fe746'
ApiServer = namedtuple('ApiBase', ['name', 'sso', 'esi', 'client_id', 'callback', 'supports_auto_login'])
supported_servers = {
"Tranquility": ApiServer("Tranquility", "login.eveonline.com", "esi.evetech.net", '095d8cd841ac40b581330919b49fe746', 'https://pyfa-org.github.io/Pyfa/callback', True),
# No point having SISI: https://developers.eveonline.com/blog/article/removing-datasource-singularity
# "Singularity": ApiServer("Singularity", "sisilogin.testeveonline.com", "esi.evetech.net", 'b9c3cc79448f449ab17f3aebd018842e', 'https://pyfa-org.github.io/Pyfa/callback'),
"Serenity": ApiServer("Serenity", "login.evepc.163.com", "ali-esi.evepc.163.com", 'bc90aa496a404724a93f41b4f4e97761', 'https://ali-esi.evepc.163.com/ui/oauth2-redirect.html', False)
}
SSO_LOGOFF_SERENITY='https://login.evepc.163.com/account/logoff'
ESI_CACHE = 'esi_cache'
SSO_CALLBACK = 'https://pyfa-org.github.io/Pyfa/callback'
LOGLEVEL_MAP = {
"critical": CRITICAL,

View File

@@ -33,6 +33,8 @@ AppDir:
- libwebkit2gtk-4.0-37 # Needed for wx's HTML lib
# Unknown
- libpcre2-32-0 # https://github.com/pyfa-org/Pyfa/issues/2572
- libnotify4 # https://github.com/pyfa-org/Pyfa/issues/2598
- libwayland-client0 # https://github.com/pyfa-org/Pyfa/issues/2600
exclude:
- hicolor-icon-theme
- humanity-icon-theme

View File

@@ -10,10 +10,15 @@
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 10 and Windows 11 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>

View File

@@ -0,0 +1,36 @@
"""
Migration 46
- add support for server selection for SSO characters
"""
import sqlalchemy
tmpTable = """
CREATE TABLE ssoCharacterTemp (
ID INTEGER NOT NULL,
client VARCHAR NOT NULL,
characterID INTEGER NOT NULL,
characterName VARCHAR NOT NULL,
refreshToken VARCHAR NOT NULL,
accessToken VARCHAR NOT NULL,
accessTokenExpires DATETIME NOT NULL,
created DATETIME,
modified DATETIME,
server VARCHAR,
PRIMARY KEY (ID),
CONSTRAINT "uix_client_server_characterID" UNIQUE (client, server, characterID),
CONSTRAINT "uix_client_server_characterName" UNIQUE (client, server, characterName)
)
"""
def upgrade(saveddata_engine):
try:
saveddata_engine.execute("SELECT server FROM ssoCharacter LIMIT 1")
except sqlalchemy.exc.DatabaseError:
saveddata_engine.execute(tmpTable)
saveddata_engine.execute(
"INSERT INTO ssoCharacterTemp (ID, client, characterID, characterName, refreshToken, accessToken, accessTokenExpires, created, modified, server) "
"SELECT ID, client, characterID, characterName, refreshToken, accessToken, accessTokenExpires, created, modified, 'Tranquility' "
"FROM ssoCharacter")
saveddata_engine.execute("DROP TABLE ssoCharacter")
saveddata_engine.execute("ALTER TABLE ssoCharacterTemp RENAME TO ssoCharacter")

View File

@@ -40,18 +40,18 @@ characters_table = Table("characters", saveddata_meta,
Column("modified", DateTime, nullable=True, onupdate=datetime.datetime.now))
sso_table = Table("ssoCharacter", saveddata_meta,
Column("ID", Integer, primary_key=True),
Column("client", String, nullable=False),
Column("characterID", Integer, nullable=False),
Column("characterName", String, nullable=False),
Column("refreshToken", String, nullable=False),
Column("accessToken", String, nullable=False),
Column("accessTokenExpires", DateTime, nullable=False),
Column("created", DateTime, nullable=True, default=datetime.datetime.now),
Column("modified", DateTime, nullable=True, onupdate=datetime.datetime.now),
UniqueConstraint('client', 'characterID', name='uix_client_characterID'),
UniqueConstraint('client', 'characterName', name='uix_client_characterName')
)
Column("ID", Integer, primary_key=True),
Column("client", String, nullable=False),
Column("characterID", Integer, nullable=False),
Column("characterName", String, nullable=False),
Column("server", String, nullable=False),
Column("refreshToken", String, nullable=False),
Column("accessToken", String, nullable=False),
Column("accessTokenExpires", DateTime, nullable=False),
Column("created", DateTime, nullable=True, default=datetime.datetime.now),
Column("modified", DateTime, nullable=True, onupdate=datetime.datetime.now),
UniqueConstraint('client', 'server', 'characterID', name='uix_client_server_characterID'),
UniqueConstraint('client', 'server', 'characterName', name='uix_client_server_characterName'))
sso_character_map_table = Table("ssoCharacterMap", saveddata_meta,
Column("characterID", ForeignKey("characters.ID"), primary_key=True),

View File

@@ -493,9 +493,12 @@ def getSsoCharacters(clientHash, eager=None):
@cachedQuery(SsoCharacter, 1, "lookfor", "clientHash")
def getSsoCharacter(lookfor, clientHash, eager=None):
def getSsoCharacter(lookfor, clientHash, server=None, eager=None):
filter = SsoCharacter.client == clientHash
if server is not None:
filter = and_(filter, SsoCharacter.server == server)
if isinstance(lookfor, int):
filter = and_(filter, SsoCharacter.ID == lookfor)
elif isinstance(lookfor, str):

View File

@@ -396,7 +396,7 @@ class Effect59(BaseEffect):
cargoCapacityMultiply
Used by:
Modules from group: Expanded Cargohold (7 of 7)
Modules from group: Expanded Cargohold (8 of 8)
Modules from group: Overdrive Injector System (7 of 7)
Modules from group: Reinforced Bulkhead (8 of 8)
"""
@@ -966,8 +966,8 @@ class Effect272(BaseEffect):
Used by:
Implants named like: Inherent Implants 'Noble' Repair Systems RS (6 of 6)
Implants named like: Repairer Booster (4 of 4)
Modules named like: Nanobot Accelerator (8 of 8)
Implant: AIR Repairer Booster III
Implant: Numon Family Heirloom
Skill: Repair Systems
"""
@@ -1060,6 +1060,7 @@ class Effect290(BaseEffect):
Used by:
Implants named like: Frentix Booster (4 of 4)
Implants named like: Halcyon B Booster (5 of 5)
Implants named like: SoCT Turret Booster (3 of 3)
Implants named like: Zainou 'Deadeye' Sharpshooter ST (6 of 6)
Skill: Sharpshooter
"""
@@ -1169,6 +1170,7 @@ class Effect394(BaseEffect):
Implant: AIR Overclocker Booster II
Implant: Quafe Zero Classic
Implant: Serenity YC122.9 Season Booster - Max Velocity
Implant: Starsi Blast! Classic
Implant: Wisdom of Gheinok
Skill: Navigation
"""
@@ -1190,17 +1192,18 @@ class Effect395(BaseEffect):
Used by:
Modules from group: Rig Anchor (4 of 4)
Implants named like: Agility Booster (4 of 4)
Implants named like: Eifyr and Co. 'Rogue' Evasive Maneuvering EM (6 of 6)
Implants named like: Grand Prix Booster (4 of 6)
Implants named like: Halcyon G Booster (5 of 5)
Implants named like: Halcyon Y Booster (5 of 5)
Implants named like: grade Nomad (10 of 12)
Modules named like: Low Friction Nozzle Joints (8 of 8)
Implant: AIR Agility Booster II
Implant: AIR Overclocker Booster III
Implant: Genolution Core Augmentation CA-4
Implant: Quafe Zero Green Apple
Implant: Serenity YC122.9 Season Booster - Agility
Implant: Starsi Blast! Classic
Skill: Evasive Maneuvering
Skill: Spaceship Command
"""
@@ -1335,6 +1338,7 @@ class Effect485(BaseEffect):
Implant: Basic Capsuleer Engineering Augmentation Chip
Implant: Genolution Core Augmentation CA-2
Implant: Quafe Zero Green Apple
Implant: Starsi Blast! Orange
Skill: Capacitor Systems Operation
"""
@@ -1771,6 +1775,7 @@ class Effect584(BaseEffect):
Implants named like: 'Pyrolancea' Dose (7 of 7)
Implants named like: Eifyr and Co. 'Gunslinger' Surgical Strike SS (6 of 6)
Implants named like: Halcyon Y Booster (5 of 5)
Implants named like: SoCT Turret Booster (3 of 3)
Implant: AIR Pyrolancea Booster II
Implant: Standard Cerebral Accelerator
"""
@@ -2153,9 +2158,11 @@ class Effect699(BaseEffect):
Used by:
Implants named like: Halcyon B Booster (5 of 5)
Implants named like: Halcyon R Booster (5 of 5)
Implants named like: SoCT Scan Booster (3 of 3)
Implants named like: Zainou 'Gypsy' Signature Analysis SA (6 of 6)
Modules named like: Targeting System Subcontroller (8 of 8)
Implant: Quafe Zero Classic
Implant: Starsi Blast! Orange
Skill: Signature Analysis
"""
@@ -2502,6 +2509,7 @@ class Effect856(BaseEffect):
Implants named like: Grand Prix Booster (5 of 6)
Implants named like: Halcyon B Booster (5 of 5)
Implants named like: Serenity Limited 'Overclocker' Dose (3 of 3)
Implants named like: SoCT Agility Booster (3 of 3)
Implants named like: grade Ascendancy (10 of 12)
Modules named like: Hyperspatial Velocity Optimizer (8 of 8)
Implant: Serenity YC122.9 Season Booster - Warp Speed
@@ -4817,7 +4825,7 @@ class Effect1615(BaseEffect):
shipAdvancedSpaceshipCommandAgilityBonus
Used by:
Items from market group: Ships > Capital Ships (50 of 50)
Items from market group: Ships > Capital Ships (51 of 51)
"""
type = 'passive'
@@ -4890,8 +4898,8 @@ class Effect1635(BaseEffect):
capitalRepairSystemsSkillDurationBonus
Used by:
Implants named like: Repairer Booster (4 of 4)
Modules named like: Nanobot Accelerator (8 of 8)
Implant: AIR Repairer Booster III
Skill: Capital Repair Systems
"""
@@ -4955,9 +4963,7 @@ class Effect1644(BaseEffect):
skirmishCommandMindlink
Used by:
Implant: Federation Navy Command Mindlink
Implant: Republic Fleet Command Mindlink
Implant: Skirmish Command Mindlink
Implants from group: Cyber Leadership (4 of 11)
"""
type = 'passive'
@@ -4981,7 +4987,7 @@ class Effect1645(BaseEffect):
shieldCommandMindlink
Used by:
Implants from group: Cyber Leadership (4 of 10)
Implants from group: Cyber Leadership (4 of 11)
"""
type = 'passive'
@@ -5005,9 +5011,7 @@ class Effect1646(BaseEffect):
informationCommandMindlink
Used by:
Implant: Caldari Navy Command Mindlink
Implant: Imperial Navy Command Mindlink
Implant: Information Command Mindlink
Implants from group: Cyber Leadership (4 of 11)
"""
type = 'passive'
@@ -6737,7 +6741,7 @@ class Effect2252(BaseEffect):
Used by:
Ships from group: Black Ops (5 of 5)
Ships from group: Blockade Runner (4 of 4)
Ships from group: Blockade Runner (5 of 5)
Ships from group: Covert Ops (8 of 8)
Ships from group: Expedition Frigate (2 of 2)
Ships from group: Force Recon Ship (9 of 9)
@@ -6786,8 +6790,8 @@ class Effect2255(BaseEffect):
tractorBeamCan
Used by:
Deployables from group: Mobile Tractor Unit (4 of 4)
Modules from group: Tractor Beam (4 of 4)
Deployables from group: Mobile Tractor Unit (5 of 5)
Modules from group: Tractor Beam (6 of 6)
"""
type = 'active'
@@ -6996,6 +7000,7 @@ class Effect2432(BaseEffect):
Implants named like: Halcyon Y Booster (5 of 5)
Implants named like: Inherent Implants 'Squire' Capacitor Management EM (6 of 6)
Implants named like: Mindflood Booster (4 of 4)
Implants named like: SoCT Capacitor Booster (3 of 3)
Modules named like: Semiconductor Memory Cell (8 of 8)
Implant: Antipharmakon Aeolis
Implant: Basic Capsuleer Engineering Augmentation Chip
@@ -9490,7 +9495,7 @@ class Effect3046(BaseEffect):
modifyMaxVelocityOfShipPassive
Used by:
Modules from group: Expanded Cargohold (7 of 7)
Modules from group: Expanded Cargohold (8 of 8)
"""
type = 'offline'
@@ -9505,7 +9510,7 @@ class Effect3047(BaseEffect):
structureHPMultiplyPassive
Used by:
Modules from group: Expanded Cargohold (7 of 7)
Modules from group: Expanded Cargohold (8 of 8)
"""
type = 'passive'
@@ -13484,6 +13489,7 @@ class Effect4162(BaseEffect):
Implants named like: Poteque 'Prospector' Astrometric Rangefinding AR (3 of 3)
Implants named like: Poteque 'Prospector' Sharpeye (2 of 2)
Implants named like: Serenity Limited 'Sharpeye' Dose (3 of 3)
Implants named like: SoCT Scan Booster (3 of 3)
Implants named like: grade Virtue (10 of 12)
Modules named like: Gravity Capacitor Upgrade (8 of 8)
Implant: AIR Astro-Rangefinding II Booster
@@ -16344,7 +16350,7 @@ class Effect4921(BaseEffect):
microJumpDrive
Used by:
Modules from group: Micro Jump Drive (2 of 2)
Modules named like: Micro Jump Drive (3 of 3)
"""
type = 'active'
@@ -16627,8 +16633,8 @@ class Effect4967(BaseEffect):
shieldBoosterDurationBonusShieldSkills
Used by:
Implants named like: Repairer Booster (4 of 4)
Modules named like: Core Defense Operational Solidifier (8 of 8)
Implant: AIR Repairer Booster III
"""
type = 'passive'
@@ -18657,7 +18663,7 @@ class Effect5266(BaseEffect):
blockadeRunnerCloakCpuPercentBonus
Used by:
Ships from group: Blockade Runner (4 of 4)
Ships from group: Blockade Runner (5 of 5)
"""
runTime = 'early'
@@ -20175,6 +20181,7 @@ class Effect5437(BaseEffect):
Used by:
Implants named like: Halcyon Y Booster (5 of 5)
Implants named like: SoCT Relic Coherence Booster (3 of 3)
Modules named like: Emission Scope Sharpener (8 of 8)
Implant: Poteque 'Prospector' Archaeology AC-905
Implant: Poteque 'Prospector' Environmental Analysis EY-1005
@@ -22423,7 +22430,7 @@ class Effect5869(BaseEffect):
eliteIndustrialWarpSpeedBonus1
Used by:
Ships from group: Blockade Runner (4 of 4)
Ships from group: Blockade Runner (5 of 5)
"""
type = 'passive'
@@ -22505,7 +22512,7 @@ class Effect5874(BaseEffect):
eliteIndustrialFleetCapacity1
Used by:
Ships from group: Deep Space Transport (4 of 4)
Ships from group: Deep Space Transport (5 of 5)
"""
type = 'passive'
@@ -22521,8 +22528,7 @@ class Effect5881(BaseEffect):
eliteIndustrialShieldResists2
Used by:
Ship: Bustard
Ship: Mastodon
Ships from group: Deep Space Transport (3 of 5)
"""
type = 'passive'
@@ -22557,7 +22563,7 @@ class Effect5889(BaseEffect):
eliteIndustrialABHeatBonus
Used by:
Ships from group: Deep Space Transport (4 of 4)
Ships from group: Deep Space Transport (5 of 5)
Ships from group: Interceptor (4 of 10)
"""
@@ -22574,7 +22580,7 @@ class Effect5890(BaseEffect):
eliteIndustrialMWDHeatBonus
Used by:
Ships from group: Deep Space Transport (4 of 4)
Ships from group: Deep Space Transport (5 of 5)
Ships from group: Interceptor (4 of 10)
"""
@@ -22591,7 +22597,7 @@ class Effect5891(BaseEffect):
eliteIndustrialArmorHardenerHeatBonus
Used by:
Ships from group: Deep Space Transport (4 of 4)
Ships from group: Deep Space Transport (5 of 5)
"""
type = 'passive'
@@ -22607,7 +22613,7 @@ class Effect5892(BaseEffect):
eliteIndustrialReactiveArmorHardenerHeatBonus
Used by:
Ships from group: Deep Space Transport (4 of 4)
Ships from group: Deep Space Transport (5 of 5)
"""
type = 'passive'
@@ -22623,7 +22629,7 @@ class Effect5893(BaseEffect):
eliteIndustrialShieldHardenerHeatBonus
Used by:
Ships from group: Deep Space Transport (4 of 4)
Ships from group: Deep Space Transport (5 of 5)
"""
type = 'passive'
@@ -22639,7 +22645,7 @@ class Effect5896(BaseEffect):
eliteIndustrialShieldBoosterHeatBonus
Used by:
Ships from group: Deep Space Transport (4 of 4)
Ships from group: Deep Space Transport (5 of 5)
"""
type = 'passive'
@@ -22657,7 +22663,7 @@ class Effect5899(BaseEffect):
eliteIndustrialArmorRepairHeatBonus
Used by:
Ships from group: Deep Space Transport (4 of 4)
Ships from group: Deep Space Transport (5 of 5)
"""
type = 'passive'
@@ -22690,7 +22696,7 @@ class Effect5901(BaseEffect):
roleBonusBulkheadCPU
Used by:
Ships from group: Freighter (4 of 5)
Ships from group: Freighter (4 of 6)
Ships from group: Jump Freighter (4 of 4)
"""
@@ -26912,8 +26918,7 @@ class Effect6431(BaseEffect):
fighterAbilityMissiles
Used by:
Items from category: Fighter (48 of 82)
Fighters from group: Light Fighter (32 of 32)
Items from category: Fighter (56 of 94)
"""
dealsDamage = True
@@ -26928,7 +26933,7 @@ class Effect6434(BaseEffect):
fighterAbilityEnergyNeutralizer
Used by:
Fighters named like: Cenobite (4 of 4)
Fighters named like: Cenobite (5 of 5)
"""
displayName = 'Energy Neutralizer'
@@ -26957,7 +26962,7 @@ class Effect6435(BaseEffect):
fighterAbilityStasisWebifier
Used by:
Fighters named like: Dromi (4 of 4)
Fighters named like: Dromi (5 of 5)
"""
displayName = 'Stasis Webifier'
@@ -26984,7 +26989,7 @@ class Effect6436(BaseEffect):
fighterAbilityWarpDisruption
Used by:
Fighters named like: Siren (4 of 4)
Fighters named like: Siren (5 of 5)
"""
displayName = 'Warp Disruption'
@@ -27011,7 +27016,7 @@ class Effect6437(BaseEffect):
fighterAbilityECM
Used by:
Fighters named like: Scarab (4 of 4)
Fighters named like: Scarab (5 of 5)
"""
displayName = 'ECM'
@@ -27041,7 +27046,8 @@ class Effect6439(BaseEffect):
fighterAbilityEvasiveManeuvers
Used by:
Fighters from group: Light Fighter (16 of 32)
Fighters from group: Light Fighter (12 of 24)
Fighters from group: Structure Light Fighter (8 of 16)
"""
displayName = 'Evasive Maneuvers'
@@ -27079,7 +27085,7 @@ class Effect6440(BaseEffect):
Used by:
Fighters named like: Shadow (2 of 2)
Fighters named like: Siren (4 of 4)
Fighters named like: Siren (5 of 5)
"""
displayName = 'Afterburner'
@@ -27098,7 +27104,7 @@ class Effect6441(BaseEffect):
fighterAbilityMicroWarpDrive
Used by:
Items from category: Fighter (44 of 82)
Items from category: Fighter (51 of 94)
"""
displayName = 'Microwarpdrive'
@@ -27192,8 +27198,7 @@ class Effect6465(BaseEffect):
fighterAbilityAttackM
Used by:
Items from category: Fighter (50 of 82)
Fighters from group: Heavy Fighter (34 of 34)
Items from category: Fighter (54 of 94)
"""
dealsDamage = True
@@ -27466,7 +27471,8 @@ class Effect6485(BaseEffect):
fighterAbilityLaunchBomb
Used by:
Fighters from group: Heavy Fighter (16 of 34)
Fighters from group: Heavy Fighter (8 of 17)
Fighters from group: Structure Heavy Fighter (8 of 17)
"""
dealsDamage = True
@@ -28352,6 +28358,9 @@ class Effect6567(BaseEffect):
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name in groups or
mod.item.requiresSkill('Propulsion Jamming'),
'capacitorNeed', src.getModifiedItemAttr('ewCapacitorNeedBonus'), **kwargs)
fit.modules.filteredItemIncrease(
lambda mod: mod.item.requiresSkill('Capital Micro Jump Drive Operation'), 'activationBlocked',
src.getModifiedItemAttr('networkedSensorArrayDisallowCapitalMicroJump'), **kwargs)
class Effect6570(BaseEffect):
@@ -31617,9 +31626,9 @@ class Effect6789(BaseEffect):
industrialBonusDroneDamage
Used by:
Ships from group: Blockade Runner (4 of 4)
Ships from group: Deep Space Transport (4 of 4)
Ships from group: Hauler (17 of 17)
Ships from group: Blockade Runner (5 of 5)
Ships from group: Deep Space Transport (5 of 5)
Ships from group: Hauler (18 of 18)
Ships from group: Industrial Command Ship (2 of 2)
Ship: Hulk
Ship: Mackinaw
@@ -32204,7 +32213,7 @@ class Effect6879(BaseEffect):
@staticmethod
def handler(fit, src, context, projectionRange, **kwargs):
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == 'Stasis Web', 'maxRange',
src.getModifiedItemAttr('eliteBonusBlackOps3'), stackingPenalties=True, skill='Black Ops', **kwargs)
src.getModifiedItemAttr('eliteBonusBlackOps3'), skill='Black Ops', **kwargs)
class Effect6880(BaseEffect):
@@ -33538,7 +33547,7 @@ class Effect7008(BaseEffect):
structureFullPowerStateHitpointModifier
Used by:
Items from category: Structure (17 of 17)
Items from category: Structure (18 of 18)
"""
type = 'passive'
@@ -33556,7 +33565,7 @@ class Effect7009(BaseEffect):
Used by:
Structure Modules from group: Structure Citadel Service Module (2 of 2)
Structure Modules from group: Structure Engineering Service Module (6 of 6)
Structure Modules from group: Structure Navigation Service Module (3 of 3)
Structure Modules from group: Structure FLEX Service Module (3 of 3)
Structure Modules from group: Structure Resource Processing Service Module (4 of 4)
Structure Module: Standup Moon Drill I
"""
@@ -33789,7 +33798,7 @@ class Effect7030(BaseEffect):
structureAoERoFRoleBonus
Used by:
Items from category: Structure (11 of 17)
Items from category: Structure (11 of 18)
Structures from group: Citadel (8 of 9)
"""
@@ -33938,7 +33947,7 @@ class Effect7039(BaseEffect):
structureHiddenMissileDamageMultiplier
Used by:
Items from category: Structure (14 of 17)
Items from category: Structure (14 of 18)
"""
type = 'passive'
@@ -33957,7 +33966,7 @@ class Effect7040(BaseEffect):
structureHiddenArmorHPMultiplier
Used by:
Items from category: Structure (17 of 17)
Items from category: Structure (18 of 18)
"""
type = 'passive'
@@ -36668,7 +36677,7 @@ class Effect8108(BaseEffect):
signatureRadiusBonusOnline
Used by:
Module: Signature Radius Suppressor I
Modules from group: Signature Suppressor (5 of 5)
"""
type = 'passive'
@@ -36684,7 +36693,7 @@ class Effect8109(BaseEffect):
targetSpectrumBreakerBonus
Used by:
Module: Signature Radius Suppressor I
Modules from group: Signature Suppressor (5 of 5)
"""
type = 'active'
@@ -38004,6 +38013,40 @@ class Effect8323(BaseEffect):
skill='Gallente Hauler', **kwargs)
class Effect8327(BaseEffect):
"""
relicAnalyzerRangeBonusPassive
Used by:
Implants named like: SoCT Relic Range Booster (3 of 3)
"""
type = 'passive'
@staticmethod
def handler(fit, container, context, projectionRange, **kwargs):
fit.modules.filteredItemBoost(
lambda mod: mod.item.requiresSkill('Archaeology'), 'maxRange',
container.getModifiedItemAttr('rangeSkillBonus'), **kwargs)
class Effect8328(BaseEffect):
"""
relicVirusStrengthBonusPassive
Used by:
Implants named like: SoCT Relic Strength Booster (3 of 3)
"""
type = 'passive'
@staticmethod
def handler(fit, container, context, projectionRange, **kwargs):
fit.modules.filteredItemIncrease(
lambda mod: mod.item.requiresSkill('Archaeology'), 'virusStrength',
container.getModifiedItemAttr('virusStrengthBonus'), **kwargs)
class Effect8360(BaseEffect):
"""
shipBonusMissileReloadTimeGC2
@@ -38222,6 +38265,23 @@ class Effect8479(BaseEffect):
container.getModifiedItemAttr('falloffBonus'), **kwargs)
class Effect8594(BaseEffect):
"""
modifyArmorDamageResistanceBonusPostPercentPassive
Used by:
Implants named like: SoCT Armor Booster (3 of 3)
"""
type = 'passive'
@staticmethod
def handler(fit, booster, context, projectionRange, **kwargs):
for type in ('Em', 'Explosive', 'Kinetic', 'Thermal'):
fit.ship.boostItemAttr(f'armor{type}DamageResonance',
booster.getModifiedItemAttr('armorDamageResistanceBonus'), **kwargs)
class Effect11055(BaseEffect):
"""
shipBonusBattlecruiserHeavyMissileAoeVelocityMBC1
@@ -40443,3 +40503,326 @@ class Effect12038(BaseEffect):
fit.modules.filteredItemBoost(
lambda mod: mod.item.requiresSkill('Small Projectile Turret'), 'falloff',
ship.getModifiedItemAttr('shipBonus3MF'), skill='Minmatar Frigate', **kwargs)
class Effect12050(BaseEffect):
"""
shipBonusColonyResourcesHoldCapacityUH1
Used by:
Variations of ship: Squall (3 of 3)
"""
type = 'passive'
@staticmethod
def handler(fit, src, context, projectionRange, **kwargs):
fit.ship.boostItemAttr(
'specialColonyResourcesHoldCapacity', src.getModifiedItemAttr('shipBonusUH1'),
skill='Upwell Hauler', **kwargs)
class Effect12051(BaseEffect):
"""
shipMissileEMDamageUH2
Used by:
Variations of ship: Squall (3 of 3)
"""
type = 'passive'
@staticmethod
def handler(fit, container, context, projectionRange, **kwargs):
fit.modules.filteredChargeBoost(
lambda mod: mod.charge.requiresSkill('Missile Launcher Operation'),
'emDamage', container.getModifiedItemAttr('shipBonusUH2'),
skill='Upwell Hauler', **kwargs)
class Effect12052(BaseEffect):
"""
shipMissileThermalDamageUH2
Used by:
Variations of ship: Squall (3 of 3)
"""
type = 'passive'
@staticmethod
def handler(fit, container, context, projectionRange, **kwargs):
fit.modules.filteredChargeBoost(
lambda mod: mod.charge.requiresSkill('Missile Launcher Operation'),
'thermalDamage', container.getModifiedItemAttr('shipBonusUH2'),
skill='Upwell Hauler', **kwargs)
class Effect12053(BaseEffect):
"""
shipMissileExplosiveDamageUH2
Used by:
Variations of ship: Squall (3 of 3)
"""
type = 'passive'
@staticmethod
def handler(fit, container, context, projectionRange, **kwargs):
fit.modules.filteredChargeBoost(
lambda mod: mod.charge.requiresSkill('Missile Launcher Operation'),
'explosiveDamage', container.getModifiedItemAttr('shipBonusUH2'),
skill='Upwell Hauler', **kwargs)
class Effect12054(BaseEffect):
"""
shipMissileKineticDamageUH2
Used by:
Variations of ship: Squall (3 of 3)
"""
type = 'passive'
@staticmethod
def handler(fit, container, context, projectionRange, **kwargs):
fit.modules.filteredChargeBoost(
lambda mod: mod.charge.requiresSkill('Missile Launcher Operation'),
'kineticDamage', container.getModifiedItemAttr('shipBonusUH2'),
skill='Upwell Hauler', **kwargs)
class Effect12057(BaseEffect):
"""
shipBonusColonyResourcesHoldCapacityUFreighter1
Used by:
Ship: Avalanche
"""
type = 'passive'
@staticmethod
def handler(fit, src, context, projectionRange, **kwargs):
fit.ship.boostItemAttr(
'specialColonyResourcesHoldCapacity', src.getModifiedItemAttr('shipBonusUFreighter1'),
skill='Upwell Freighter', **kwargs)
class Effect12058(BaseEffect):
"""
shipMissileEMDamageUFreighter2
Used by:
Ship: Avalanche
"""
type = 'passive'
@staticmethod
def handler(fit, container, context, projectionRange, **kwargs):
fit.modules.filteredChargeBoost(
lambda mod: mod.charge.requiresSkill('Missile Launcher Operation'),
'emDamage', container.getModifiedItemAttr('shipBonusUFreighter2'),
skill='Upwell Freighter', **kwargs)
class Effect12060(BaseEffect):
"""
shipMissileThermalDamageUFreighter2
Used by:
Ship: Avalanche
"""
type = 'passive'
@staticmethod
def handler(fit, container, context, projectionRange, **kwargs):
fit.modules.filteredChargeBoost(
lambda mod: mod.charge.requiresSkill('Missile Launcher Operation'),
'thermalDamage', container.getModifiedItemAttr('shipBonusUFreighter2'),
skill='Upwell Freighter', **kwargs)
class Effect12061(BaseEffect):
"""
shipMissileExplosiveDamageUFreighter2
Used by:
Ship: Avalanche
"""
type = 'passive'
@staticmethod
def handler(fit, container, context, projectionRange, **kwargs):
fit.modules.filteredChargeBoost(
lambda mod: mod.charge.requiresSkill('Missile Launcher Operation'),
'explosiveDamage', container.getModifiedItemAttr('shipBonusUFreighter2'),
skill='Upwell Freighter', **kwargs)
class Effect12062(BaseEffect):
"""
shipMissileKineticDamageUFreighter2
Used by:
Ship: Avalanche
"""
type = 'passive'
@staticmethod
def handler(fit, container, context, projectionRange, **kwargs):
fit.modules.filteredChargeBoost(
lambda mod: mod.charge.requiresSkill('Missile Launcher Operation'),
'kineticDamage', container.getModifiedItemAttr('shipBonusUFreighter2'),
skill='Upwell Freighter', **kwargs)
class Effect12063(BaseEffect):
"""
shipRoleBonusUpwellFreighterCloakCPUPenalty
Used by:
Ship: Avalanche
"""
type = 'passive'
@staticmethod
def handler(fit, ship, context, projectionRange, **kwargs):
fit.modules.filteredItemIncrease(
lambda mod: mod.item.group.name == 'Cloaking Device',
'cpu', ship.getModifiedItemAttr('upwellFreightercloakCPUPenalty'), **kwargs)
class Effect12069(BaseEffect):
"""
shipBonusAutoTargetingMissilesUFreighter3
Used by:
Ship: Avalanche
"""
type = 'passive'
@staticmethod
def handler(fit, container, context, projectionRange, **kwargs):
damageTypes = ('em', 'explosive', 'kinetic', 'thermal')
for dmgType in damageTypes:
fit.modules.filteredChargeBoost(
lambda mod: mod.charge.requiresSkill('Auto-Targeting Missiles'),
f'{dmgType}Damage', container.getModifiedItemAttr('shipBonusUFreighter3'),
skill='Upwell Freighter', **kwargs)
class Effect12071(BaseEffect):
"""
shipRoleBonusUpwellFreighterCapitalFlexHardenerFittingCapBonus
Used by:
Ship: Avalanche
"""
type = 'passive'
@staticmethod
def handler(fit, ship, context, projectionRange, **kwargs):
fit.modules.filteredItemMultiply(
lambda mod: mod.item.group.name == 'Flex Shield Hardener',
'power', ship.getModifiedItemAttr('upwellFreighterCapitalFlexHardenerFittingCapBonus'), **kwargs)
fit.modules.filteredItemMultiply(
lambda mod: mod.item.group.name == 'Flex Shield Hardener',
'capacitorNeed', ship.getModifiedItemAttr('upwellFreighterCapitalFlexHardenerFittingCapBonus'), **kwargs)
class Effect12072(BaseEffect):
"""
eliteIndustrialUpwellNeutNosHeatBonus
Used by:
Ship: Torrent
"""
type = 'passive'
@staticmethod
def handler(fit, ship, context, projectionRange, **kwargs):
fit.modules.filteredItemBoost(
lambda mod: mod.item.group.name in ('Energy Neutralizer', 'Energy Nosferatu'),
'overloadSelfDurationBonus', ship.getModifiedItemAttr('roleBonusOverheatDST'), **kwargs)
class Effect12098(BaseEffect):
"""
jumpPortalPassengerBonusPercentSkill
Used by:
Skill: Capital Jump Portal Generation
"""
type = 'passive'
@staticmethod
def handler(fit, skill, context, projectionRange, **kwargs):
fit.ship.boostItemAttr(
'conduitJumpPassengerCount',
skill.getModifiedItemAttr('conduitPassengerBonusPercent') * skill.level, **kwargs)
class Effect12102(BaseEffect):
"""
capitalMJDSkillCapReductionBonus
Used by:
Skill: Capital Micro Jump Drive Operation
"""
type = 'passive'
@staticmethod
def handler(fit, skill, context, projectionRange, **kwargs):
fit.modules.filteredItemBoost(
lambda mod: mod.item.requiresSkill('Capital Micro Jump Drive Operation'), 'capacitorNeed',
skill.getModifiedItemAttr('capitalMJDCapReductionBonus') * skill.level, **kwargs)
class Effect12126(BaseEffect):
"""
microJumpPortalDriveCapital
Used by:
Module: Capital Micro Jump Field Generator
"""
type = 'active'
@staticmethod
def handler(fit, module, context, projectionRange, **kwargs):
fit.ship.boostItemAttr('signatureRadius', module.getModifiedItemAttr('signatureRadiusBonusPercent'),
stackingPenalties=True, **kwargs)
class Effect12127(BaseEffect):
"""
shipRoleBonusUpwellHaulersMediumMissileFittingBonus
Used by:
Variations of ship: Squall (3 of 3)
"""
type = 'passive'
@staticmethod
def handler(fit, ship, context, projectionRange, **kwargs):
for attr in ('cpu', 'power'):
fit.modules.filteredItemMultiply(
lambda mod: mod.item.group.name in (
'Missile Launcher Heavy Assault',
'Missile Launcher Heavy',
'Missile Launcher Rapid Light'),
attr, ship.getModifiedItemAttr('upwellHaulersMediumMissileFittingBonus'), **kwargs)

View File

@@ -343,7 +343,8 @@ class Item(EqBase):
500018: "mordu",
500019: "sansha",
500020: "serpentis",
500026: "triglavian"
500026: "triglavian",
500027: "upwell",
}
@property
@@ -351,11 +352,7 @@ class Item(EqBase):
if self.__race is None:
try:
if (
self.category.name == 'Structure' or
# Here until CCP puts their shit together
self.name in ("Thunderchild", "Stormbringer", "Skybreaker")
):
if self.category.name == 'Structure':
self.__race = "upwell"
else:
self.__race = self.factionMap[self.factionID]
@@ -377,7 +374,8 @@ class Item(EqBase):
16 : "jove",
32 : "sansha", # Incrusion Sansha
128: "ore",
135: "triglavian"
135: "triglavian",
168: "upwell",
}
# Race is None by default
race = None

View File

@@ -25,10 +25,11 @@ import time
class SsoCharacter:
def __init__(self, charID, name, client, accessToken=None, refreshToken=None):
def __init__(self, charID, name, client, server, accessToken=None, refreshToken=None):
self.characterID = charID
self.characterName = name
self.client = client
self.server = server
self.accessToken = accessToken
self.refreshToken = refreshToken
self.accessTokenExpires = None
@@ -37,6 +38,9 @@ class SsoCharacter:
def init(self):
pass
@property
def characterDisplay(self):
return "{} [{}]".format(self.characterName, self.server)
def is_token_expired(self):
if self.accessTokenExpires is None:
return True

View File

@@ -25,7 +25,7 @@ class AddToCargoAmmo(ContextMenuSingle):
return True
def getText(self, callingWindow, itmContext, mainItem):
if mainItem.marketGroup.name == "Scan Probes":
if mainItem.marketGroup and mainItem.marketGroup.name == "Scan Probes":
return _t("Add {0} to Cargo (x8)").format(itmContext)
return _t("Add {0} to Cargo (x1000)").format(itmContext)
@@ -34,7 +34,7 @@ class AddToCargoAmmo(ContextMenuSingle):
fitID = self.mainFrame.getActiveFit()
typeID = int(mainItem.ID)
if mainItem.marketGroup.name == "Scan Probes":
if mainItem.marketGroup and mainItem.marketGroup.name == "Scan Probes":
command = cmd.GuiAddCargoCommand(fitID=fitID, itemID=typeID, amount=8)
else:
command = cmd.GuiAddCargoCommand(fitID=fitID, itemID=typeID, amount=1000)

View File

@@ -65,7 +65,6 @@ class DroneStackSplit(wx.Dialog):
self.input = wx.TextCtrl(self, wx.ID_ANY, style=wx.TE_PROCESS_ENTER)
self.input.SetValue(str(value))
self.input.SelectAll()
bSizer1.Add(self.input, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, 15)
@@ -75,12 +74,13 @@ class DroneStackSplit(wx.Dialog):
bSizer3.Add(self.CreateStdDialogButtonSizer(wx.OK | wx.CANCEL), 0, wx.EXPAND)
bSizer1.Add(bSizer3, 0, wx.ALL | wx.EXPAND, 10)
self.input.SetFocus()
self.input.Bind(wx.EVT_CHAR, self.onChar)
self.input.Bind(wx.EVT_TEXT_ENTER, self.processEnter)
self.SetSizer(bSizer1)
self.CenterOnParent()
self.Fit()
self.CenterOnParent()
self.input.SetFocus()
self.input.SelectAll()
def processEnter(self, evt):
self.EndModal(wx.ID_OK)

View File

@@ -59,7 +59,6 @@ class NameDialog(wx.Dialog):
else:
value = str(value)
self.input.SetValue(value)
self.input.SelectAll()
bSizer1.Add(self.input, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, 15)
@@ -69,11 +68,12 @@ class NameDialog(wx.Dialog):
bSizer3.Add(self.CreateStdDialogButtonSizer(wx.OK | wx.CANCEL), 0, wx.EXPAND)
bSizer1.Add(bSizer3, 0, wx.ALL | wx.EXPAND, 10)
self.input.SetFocus()
self.input.Bind(wx.EVT_TEXT_ENTER, self.processEnter)
self.SetSizer(bSizer1)
self.CenterOnParent()
self.Fit()
self.CenterOnParent()
self.input.SetFocus()
self.input.SelectAll()
def processEnter(self, evt):
self.EndModal(wx.ID_OK)

View File

@@ -108,7 +108,6 @@ class AmountChanger(wx.Dialog):
self.input = wx.TextCtrl(self, wx.ID_ANY, style=wx.TE_PROCESS_ENTER)
self.input.SetValue(str(value))
self.input.SelectAll()
bSizer1.Add(self.input, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, 15)
@@ -118,12 +117,13 @@ class AmountChanger(wx.Dialog):
bSizer3.Add(self.CreateStdDialogButtonSizer(wx.OK | wx.CANCEL), 0, wx.EXPAND)
bSizer1.Add(bSizer3, 0, wx.ALL | wx.EXPAND, 10)
self.input.SetFocus()
self.input.Bind(wx.EVT_CHAR, self.onChar)
self.input.Bind(wx.EVT_TEXT_ENTER, self.processEnter)
self.SetSizer(bSizer1)
self.CenterOnParent()
self.Fit()
self.CenterOnParent()
self.input.SetFocus()
self.input.SelectAll()
def processEnter(self, evt):
self.EndModal(wx.ID_OK)

View File

@@ -94,7 +94,6 @@ class RangeChanger(wx.Dialog):
value = int(value)
value = str(value)
self.input.SetValue(value)
self.input.SelectAll()
bSizer1.Add(self.input, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, 15)
@@ -104,12 +103,13 @@ class RangeChanger(wx.Dialog):
bSizer3.Add(self.CreateStdDialogButtonSizer(wx.OK | wx.CANCEL), 0, wx.EXPAND)
bSizer1.Add(bSizer3, 0, wx.ALL | wx.EXPAND, 10)
self.input.SetFocus()
self.input.Bind(wx.EVT_CHAR, self.onChar)
self.input.Bind(wx.EVT_TEXT_ENTER, self.processEnter)
self.SetSizer(bSizer1)
self.CenterOnParent()
self.Fit()
self.CenterOnParent()
self.input.SetFocus()
self.input.SelectAll()
def processEnter(self, evt):
self.EndModal(wx.ID_OK)

View File

@@ -72,6 +72,7 @@ AttrGroupDict = {
"specialAmmoHoldCapacity",
"specialCommandCenterHoldCapacity",
"specialPlanetaryCommoditiesHoldCapacity",
"specialColonyResourcesHoldCapacity",
"structureDamageLimit",
"specialSubsystemHoldCapacity",
"emDamageResonance",

View File

@@ -5,3 +5,5 @@ import wx.lib.newevent
ItemSelected, ITEM_SELECTED = wx.lib.newevent.NewEvent()
RECENTLY_USED_MODULES = -2
CHARGES_FOR_FIT = -3

View File

@@ -2,14 +2,17 @@ import wx
from logbook import Logger
import gui.builtinMarketBrowser.pfSearchBox as SBox
from config import slotColourMap
import gui.globalEvents as GE
from config import slotColourMap, slotColourMapDark
from eos.saveddata.module import Module
from gui.builtinMarketBrowser.events import ItemSelected, RECENTLY_USED_MODULES
from gui.builtinMarketBrowser.events import ItemSelected, RECENTLY_USED_MODULES, CHARGES_FOR_FIT
from gui.contextMenu import ContextMenu
from gui.display import Display
from gui.utils.staticHelpers import DragDropHelper
from gui.utils.dark import isDark
from service.fit import Fit
from service.market import Market
from service.ammo import Ammo
pyfalog = Logger(__name__)
@@ -31,6 +34,7 @@ class ItemView(Display):
self.filteredStore = set()
self.sMkt = marketBrowser.sMkt
self.sFit = Fit.getInstance()
self.sAmmo = Ammo.getInstance()
self.marketBrowser = marketBrowser
self.marketView = marketBrowser.marketView
@@ -50,6 +54,9 @@ class ItemView(Display):
self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.itemActivated)
self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.startDrag)
# the "charges for active fitting" needs to listen to fitting changes
self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged)
self.active = []
def delaySearch(self, evt):
@@ -90,7 +97,11 @@ class ItemView(Display):
if sel.IsOk():
# Get data field of the selected item (which is a marketGroup ID if anything was selected)
seldata = self.marketView.GetItemData(sel)
if seldata is not None and seldata != RECENTLY_USED_MODULES:
if seldata == RECENTLY_USED_MODULES:
items = self.sMkt.getRecentlyUsed()
elif seldata == CHARGES_FOR_FIT:
items = self.getChargesForActiveFit()
elif seldata is not None:
# If market group treeview item doesn't have children (other market groups or dummies),
# then it should have items in it and we want to request them
if self.marketView.ItemHasChildren(sel) is False:
@@ -102,11 +113,7 @@ class ItemView(Display):
else:
items = set()
else:
# If method was called but selection wasn't actually made or we have a hit on recently used modules
if seldata == RECENTLY_USED_MODULES:
items = self.sMkt.getRecentlyUsed()
else:
items = set()
items = set()
# Fill store
self.updateItemStore(items)
@@ -114,6 +121,9 @@ class ItemView(Display):
# Set toggle buttons / use search mode flag if recently used modules category is selected (in order to have all modules listed and not filtered)
if seldata == RECENTLY_USED_MODULES:
self.marketBrowser.mode = 'recent'
if seldata == CHARGES_FOR_FIT:
self.marketBrowser.mode = 'charges'
self.setToggles()
if context == 'tree' and self.marketBrowser.settings.get('marketMGMarketSelectMode') == 1:
@@ -122,6 +132,41 @@ class ItemView(Display):
btn.setUserSelection(True)
self.filterItemStore()
def getChargesForActiveFit(self):
fitId = self.mainFrame.getActiveFit()
# no active fit => no charges
if fitId is None:
return set()
fit = self.sFit.getFit(fitId)
# use a set so we only add one entry for each charge
items = set()
for mod in fit.modules:
charges = self.sAmmo.getModuleFlatAmmo(mod)
for charge in charges:
items.add(charge)
return items
def fitChanged(self, event):
# skip the event so the other handlers also get called
event.Skip()
if self.marketBrowser.mode != 'charges':
return
activeFitID = self.mainFrame.getActiveFit()
# if it was not the active fitting that was changed, do not do anything
if activeFitID is not None and activeFitID not in event.fitIDs:
return
items = self.getChargesForActiveFit()
# update the UI
self.updateItemStore(items)
self.filterItemStore()
def updateItemStore(self, items):
self.unfilteredStore = items
@@ -243,6 +288,7 @@ class ItemView(Display):
def columnBackground(self, colItem, item):
if self.sFit.serviceFittingOptions["colorFitBySlot"]:
return slotColourMap.get(Module.calculateSlot(item)) or self.GetBackgroundColour()
colorMap = slotColourMapDark if isDark() else slotColourMap
return colorMap.get(Module.calculateSlot(item)) or self.GetBackgroundColour()
else:
return self.GetBackgroundColour()

View File

@@ -1,7 +1,7 @@
import wx
from gui.cachingImageList import CachingImageList
from gui.builtinMarketBrowser.events import RECENTLY_USED_MODULES
from gui.builtinMarketBrowser.events import RECENTLY_USED_MODULES, CHARGES_FOR_FIT
from logbook import Logger
@@ -35,6 +35,9 @@ class MarketTree(wx.TreeCtrl):
# Add recently used modules node
rumIconId = self.addImage("market_small", "gui")
self.AppendItem(self.root, _t("Recently Used Items"), rumIconId, data=RECENTLY_USED_MODULES)
# Add charges for active fitting node
cffIconId = self.addImage("damagePattern_small", "gui")
self.AppendItem(self.root, _t("Charges For Active Fit"), cffIconId, data=CHARGES_FOR_FIT)
# Bind our lookup method to when the tree gets expanded
self.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.expandLookup)

View File

@@ -1,9 +1,11 @@
# noinspection PyPackageRequirements
import wx
import config
import gui.mainFrame
from gui.bitmap_loader import BitmapLoader
from gui.preferenceView import PreferenceView
from service.esi import Esi
from service.settings import EsiSettings
# noinspection PyPackageRequirements
@@ -41,38 +43,68 @@ class PFEsiPref(PreferenceView):
"due to 'Signature has expired' error")))
mainSizer.Add(self.enforceJwtExpiration, 0, wx.ALL | wx.EXPAND, 5)
self.ssoServer = wx.CheckBox(panel, wx.ID_ANY, _t("Auto-login (starts local server)"), wx.DefaultPosition,
wx.DefaultSize,
0)
self.ssoServer.SetToolTip(wx.ToolTip(_t("This allows the EVE SSO to callback to your local pyfa instance and complete the authentication process without manual intervention.")))
mainSizer.Add(self.ssoServer, 0, wx.ALL | wx.EXPAND, 5)
rbSizer = wx.BoxSizer(wx.HORIZONTAL)
self.rbMode = wx.RadioBox(panel, -1, _t("Login Authentication Method"), wx.DefaultPosition, wx.DefaultSize,
[_t('Local Server'), _t('Manual')], 1, wx.RA_SPECIFY_COLS)
self.rbMode.SetItemToolTip(0, _t("This option starts a local webserver that EVE SSO Server will call back to"
" with information about the character login."))
self.rbMode.SetItemToolTip(1, _t("This option prompts users to copy and paste information to allow for"
" character login. Use this if having issues with the local server."))
self.rbMode.SetSelection(self.settings.get('loginMode'))
self.enforceJwtExpiration.SetValue(self.settings.get("enforceJwtExpiration" or True))
self.enforceJwtExpiration.SetValue(self.settings.get("enforceJwtExpiration") or True)
self.ssoServer.SetValue(True if self.settings.get("loginMode") == 0 else False)
rbSizer.Add(self.rbMode, 1, wx.TOP | wx.RIGHT, 5)
mainSizer.Add(rbSizer, 0, wx.ALL | wx.EXPAND, 0)
self.rbMode.Bind(wx.EVT_RADIOBOX, self.OnModeChange)
esiSizer = wx.BoxSizer(wx.HORIZONTAL)
self.esiServer = wx.StaticText(panel, wx.ID_ANY, _t("Default SSO Server:"), wx.DefaultPosition, wx.DefaultSize, 0)
self.esiServer.Wrap(-1)
esiSizer.Add(self.esiServer, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
self.esiServer.SetToolTip(wx.ToolTip(_t('The source you choose will be used on connection.')))
self.chESIserver = wx.Choice(panel, choices=list(self.settings.keys()))
self.chESIserver.SetStringSelection(self.settings.get("server"))
esiSizer.Add(self.chESIserver, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 10)
mainSizer.Add(esiSizer, 0, wx.TOP | wx.RIGHT, 10)
self.chESIserver.Bind(wx.EVT_CHOICE, self.OnServerChange)
self.enforceJwtExpiration.Bind(wx.EVT_CHECKBOX, self.OnEnforceChange)
mainSizer.Add(rbSizer, 1, wx.ALL | wx.EXPAND, 0)
self.ssoServer.Bind(wx.EVT_CHECKBOX, self.OnModeChange)
panel.SetSizer(mainSizer)
panel.Layout()
def OnTimeoutChange(self, event):
self.settings.set('timeout', event.GetEventObject().GetValue())
event.Skip()
def OnModeChange(self, event):
self.settings.set('loginMode', event.GetInt())
self.settings.set('loginMode', 0 if self.ssoServer.GetValue() else 1)
event.Skip()
def OnEnforceChange(self, event):
self.settings.set('enforceJwtExpiration', self.enforceJwtExpiration.GetValue())
event.Skip()
def OnServerChange(self, event):
# pass
source = self.chESIserver.GetString(self.chESIserver.GetSelection())
esiService = Esi.getInstance()
# init servers
esiService.init(config.supported_servers[source])
self.settings.set("server", source)
event.Skip()
def getImage(self):
return BitmapLoader.getBitmap("eve", "gui")
PFEsiPref.register()
PFEsiPref.register()

View File

@@ -112,6 +112,7 @@ class TargetingMiscViewMinimal(StatsView):
cargoNamesOrder = OrderedDict((
("fleetHangarCapacity", _t("Fleet hangar")),
("shipMaintenanceBayCapacity", _t("Maintenance bay")),
("specialColonyResourcesHoldCapacity", _t("Infrastructure hold")),
("specialAmmoHoldCapacity", _t("Ammo hold")),
("specialFuelBayCapacity", _t("Fuel bay")),
("specialShipHoldCapacity", _t("Ship hold")),
@@ -134,6 +135,7 @@ class TargetingMiscViewMinimal(StatsView):
cargoValues = {
"main": lambda: fit.ship.getModifiedItemAttr("capacity"),
"fleetHangarCapacity": lambda: fit.ship.getModifiedItemAttr("fleetHangarCapacity"),
"specialColonyResourcesHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialColonyResourcesHoldCapacity"),
"shipMaintenanceBayCapacity": lambda: fit.ship.getModifiedItemAttr("shipMaintenanceBayCapacity"),
"specialAmmoHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialAmmoHoldCapacity"),
"specialFuelBayCapacity": lambda: fit.ship.getModifiedItemAttr("specialFuelBayCapacity"),

View File

@@ -590,7 +590,7 @@ class Miscellanea(ViewColumn):
text = "{0}/s".format(formatAmount(capPerSec, 3, 0, 3))
tooltip = "Energy neutralization per second"
return text, tooltip
elif itemGroup in ("Micro Jump Drive", "Micro Jump Field Generators"):
elif itemGroup in ("Micro Jump Drive", "Micro Jump Field Generators", "Capital Mobility Modules"):
cycleTime = stuff.getModifiedItemAttr("duration") / 1000
text = "{0}s".format(formatAmount(cycleTime, 3, 0, 3))
tooltip = "Spoolup time"

View File

@@ -807,7 +807,12 @@ class APIView(wx.Panel):
self.SetSizer(pmainSizer)
self.Layout()
self.ssoListChanged(None)
try:
self.ssoListChanged(None)
except (KeyboardInterrupt, SystemExit):
raise
except:
pass
def ssoCharChanged(self, event):
sChar = Character.getInstance()
@@ -859,7 +864,7 @@ class APIView(wx.Panel):
noneID = self.charChoice.Append(_t("None"), None)
for char in ssoChars:
currId = self.charChoice.Append(char.characterName, char.ID)
currId = self.charChoice.Append(char.characterDisplay, char.ID)
if sso is not None and char.ID == sso.ID:
self.charChoice.SetSelection(currId)

View File

@@ -96,7 +96,7 @@ class EveFittings(AuxiliaryFrame):
self.charChoice.Clear()
for char in chars:
self.charChoice.Append(char.characterName, char.ID)
self.charChoice.Append(char.characterDisplay, char.ID)
if len(chars) > 0:
self.charChoice.SetSelection(0)
@@ -227,21 +227,6 @@ class EveFittings(AuxiliaryFrame):
self.fitView.update([])
class ESIServerExceptionHandler:
def __init__(self, parentWindow, ex):
pyfalog.error(ex)
with wx.MessageDialog(
parentWindow,
_t("There was an issue starting up the localized server, try setting "
"Login Authentication Method to Manual by going to Preferences -> EVE SS0 -> "
"Login Authentication Method. If this doesn't fix the problem please file an "
"issue on Github."),
_t("Add Character Error"),
wx.OK | wx.ICON_ERROR
) as dlg:
dlg.ShowModal()
class ESIExceptionHandler:
# todo: make this a generate excetpion handler for all calls
def __init__(self, ex):
@@ -348,7 +333,7 @@ class ExportToEve(AuxiliaryFrame):
self.charChoice.Clear()
for char in chars:
self.charChoice.Append(char.characterName, char.ID)
self.charChoice.Append(char.characterDisplay, char.ID)
if len(chars) > 0:
self.charChoice.SetSelection(0)
@@ -434,6 +419,7 @@ class SsoCharacterMgmt(AuxiliaryFrame):
self.lcCharacters.InsertColumn(0, heading=_t('Character'))
self.lcCharacters.InsertColumn(1, heading=_t('Character ID'))
self.lcCharacters.InsertColumn(2, heading=_t('Server'))
self.popCharList()
@@ -496,9 +482,11 @@ class SsoCharacterMgmt(AuxiliaryFrame):
self.lcCharacters.InsertItem(index, char.characterName)
self.lcCharacters.SetItem(index, 1, str(char.characterID))
self.lcCharacters.SetItemData(index, char.ID)
self.lcCharacters.SetItem(index, 2, char.server or "<unknown>")
self.lcCharacters.SetColumnWidth(0, wx.LIST_AUTOSIZE)
self.lcCharacters.SetColumnWidth(1, wx.LIST_AUTOSIZE)
self.lcCharacters.SetColumnWidth(2, wx.LIST_AUTOSIZE)
def addChar(self, event):
try:
@@ -506,8 +494,6 @@ class SsoCharacterMgmt(AuxiliaryFrame):
sEsi.login()
except (KeyboardInterrupt, SystemExit):
raise
except Exception as ex:
ESIServerExceptionHandler(self, ex)
def delChar(self, event):
item = self.lcCharacters.GetFirstSelected()

View File

@@ -112,7 +112,7 @@ class FitBrowserLiteDialog(wx.Dialog):
return True
matches = []
searchTokens = [t.lower() for t in re.split('\s+', searchPattern)]
searchTokens = [t.lower() for t in re.split(r'\s+', searchPattern)]
for fit in self.allFits:
if isMatch(fit, searchTokens):
matches.append(fit)

View File

@@ -61,10 +61,11 @@ from gui.statsPane import StatsPane
from gui.targetProfileEditor import TargetProfileEditor
from gui.updateDialog import UpdateDialog
from gui.utils.clipboard import fromClipboard
from gui.utils.progressHelper import ProgressHelper
from service.character import Character
from service.esi import Esi
from service.fit import Fit
from service.port import IPortUser, Port
from service.port import Port
from service.price import Price
from service.settings import HTMLExportSettings, SettingsProvider
from service.update import Update
@@ -130,7 +131,6 @@ class OpenFitsThread(threading.Thread):
self.running = False
# todo: include IPortUser again
class MainFrame(wx.Frame):
__instance = None
@@ -845,14 +845,15 @@ class MainFrame(wx.Frame):
style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_MULTIPLE
) as dlg:
if dlg.ShowModal() == wx.ID_OK:
self.progressDialog = wx.ProgressDialog(
_t("Importing fits"),
" " * 100, # set some arbitrary spacing to create width in window
parent=self,
style=wx.PD_CAN_ABORT | wx.PD_SMOOTH | wx.PD_ELAPSED_TIME | wx.PD_APP_MODAL
)
Port.importFitsThreaded(dlg.GetPaths(), self)
self.progressDialog.ShowModal()
# set some arbitrary spacing to create width in window
progress = ProgressHelper(message=" " * 100, callback=self._openAfterImport)
call = (Port.importFitsThreaded, [dlg.GetPaths(), progress], {})
self.handleProgress(
title=_t("Importing fits"),
style=wx.PD_CAN_ABORT | wx.PD_SMOOTH | wx.PD_APP_MODAL | wx.PD_AUTO_HIDE,
call=call,
progress=progress,
errMsgLbl=_t("Import Error"))
def backupToXml(self, event):
""" Back up all fits to EVE XML file """
@@ -863,32 +864,30 @@ class MainFrame(wx.Frame):
_t("Save Backup As..."),
wildcard=_t("EVE XML fitting file") + " (*.xml)|*.xml",
style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT,
defaultFile=defaultFile,
) as dlg:
if dlg.ShowModal() == wx.ID_OK:
filePath = dlg.GetPath()
defaultFile=defaultFile) as fileDlg:
if fileDlg.ShowModal() == wx.ID_OK:
filePath = fileDlg.GetPath()
if '.' not in os.path.basename(filePath):
filePath += ".xml"
sFit = Fit.getInstance()
max_ = sFit.countAllFits()
self.progressDialog = wx.ProgressDialog(
_t("Backup fits"),
_t("Backing up {} fits to: {}").format(max_, filePath),
maximum=max_,
parent=self,
style=wx.PD_CAN_ABORT | wx.PD_SMOOTH | wx.PD_ELAPSED_TIME | wx.PD_APP_MODAL
)
Port.backupFits(filePath, self)
self.progressDialog.ShowModal()
fitAmount = Fit.getInstance().countAllFits()
progress = ProgressHelper(
message=_t("Backing up {} fits to: {}").format(fitAmount, filePath),
maximum=fitAmount + 1)
call = (Port.backupFits, [filePath, progress], {})
self.handleProgress(
title=_t("Backup fits"),
style=wx.PD_CAN_ABORT | wx.PD_SMOOTH | wx.PD_ELAPSED_TIME | wx.PD_APP_MODAL | wx.PD_AUTO_HIDE,
call=call,
progress=progress,
errMsgLbl=_t("Export Error"))
def exportHtml(self, event):
from gui.utils.exportHtml import exportHtml
sFit = Fit.getInstance()
settings = HTMLExportSettings.getInstance()
max_ = sFit.countAllFits()
path = settings.getPath()
if not os.path.isdir(os.path.dirname(path)):
@@ -903,82 +902,44 @@ class MainFrame(wx.Frame):
) as dlg:
if dlg.ShowModal() == wx.ID_OK:
return
progress = ProgressHelper(
message=_t("Generating HTML file at: {}").format(path),
maximum=sFit.countAllFits() + 1)
call = (exportHtml.getInstance().refreshFittingHtml, [True, progress], {})
self.handleProgress(
title=_t("Backup fits"),
style=wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME,
call=call,
progress=progress)
self.progressDialog = wx.ProgressDialog(
_t("Backup fits"),
_t("Generating HTML file at: {}").format(path),
maximum=max_, parent=self,
style=wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME)
exportHtml.getInstance().refreshFittingHtml(True, self.backupCallback)
self.progressDialog.ShowModal()
def backupCallback(self, info):
if info == -1:
self.closeProgressDialog()
else:
self.progressDialog.Update(info)
def on_port_process_start(self):
# flag for progress dialog.
self.__progress_flag = True
def on_port_processing(self, action, data=None):
# 2017/03/29 NOTE: implementation like interface
wx.CallAfter(
self._on_port_processing, action, data
)
return self.__progress_flag
def _on_port_processing(self, action, data):
"""
While importing fits from file, the logic calls back to this function to
update progress bar to show activity. XML files can contain multiple
ships with multiple fits, whereas EFT cfg files contain many fits of
a single ship. When iterating through the files, we update the message
when we start a new file, and then Pulse the progress bar with every fit
that is processed.
action : a flag that lets us know how to deal with :data
None: Pulse the progress bar
1: Replace message with data
other: Close dialog and handle based on :action (-1 open fits, -2 display error)
"""
_message = None
if action & IPortUser.ID_ERROR:
self.closeProgressDialog()
_message = _t("Import Error") if action & IPortUser.PROCESS_IMPORT else _t("Export Error")
def handleProgress(self, title, style, call, progress, errMsgLbl=None):
extraArgs = {}
if progress.maximum is not None:
extraArgs['maximum'] = progress.maximum
with wx.ProgressDialog(
parent=self,
title=title,
message=progress.message,
style=style,
**extraArgs
) as dlg:
func, args, kwargs = call
func(*args, **kwargs)
while progress.working:
wx.MilliSleep(250)
wx.Yield()
(progress.dlgWorking, skip) = dlg.Update(progress.current, progress.message)
if progress.error and errMsgLbl:
with wx.MessageDialog(
self,
_t("The following error was generated") +
f"\n\n{data}\n\n" +
f"\n\n{progress.error}\n\n" +
_t("Be aware that already processed fits were not saved"),
_message, wx.OK | wx.ICON_ERROR
errMsgLbl, wx.OK | wx.ICON_ERROR
) as dlg:
dlg.ShowModal()
return
# data is str
if action & IPortUser.PROCESS_IMPORT:
if action & IPortUser.ID_PULSE:
_message = ()
# update message
elif action & IPortUser.ID_UPDATE: # and data != self.progressDialog.message:
_message = data
if _message is not None:
self.__progress_flag, _unuse = self.progressDialog.Pulse(_message)
else:
self.closeProgressDialog()
if action & IPortUser.ID_DONE:
self._openAfterImport(data)
# data is tuple(int, str)
elif action & IPortUser.PROCESS_EXPORT:
if action & IPortUser.ID_DONE:
self.closeProgressDialog()
else:
self.__progress_flag, _unuse = self.progressDialog.Update(data[0], data[1])
elif progress.callback:
progress.callback(*progress.cbArgs)
def _openAfterImport(self, fits):
if len(fits) > 0:
@@ -988,6 +949,8 @@ class MainFrame(wx.Frame):
wx.PostEvent(self.shipBrowser, Stage3Selected(shipID=fit.shipID, back=True))
else:
fits.sort(key=lambda _fit: (_fit.ship.item.name, _fit.name))
# Show 100 fits max
fits = fits[:100]
results = []
for fit in fits:
results.append((
@@ -999,15 +962,6 @@ class MainFrame(wx.Frame):
))
wx.PostEvent(self.shipBrowser, ImportSelected(fits=results, back=True))
def closeProgressDialog(self):
# Windows apparently handles ProgressDialogs differently. We can
# simply Destroy it here, but for other platforms we must Close it
if 'wxMSW' in wx.PlatformInfo:
self.progressDialog.Destroy()
else:
self.progressDialog.EndModal(wx.ID_OK)
self.progressDialog.Close()
def importCharacter(self, event):
""" Imports character XML file from EVE API """
with wx.FileDialog(

View File

@@ -146,7 +146,7 @@ class MarketBrowser(wx.Panel):
setting = self.settings.get('marketMGSearchMode')
# We turn on all meta buttons for the duration of search/recents
if setting == 1:
if newMode in ('search', 'recent'):
if newMode in ('search', 'recent', 'charges'):
for btn in self.metaButtons:
btn.setUserSelection(True)
if newMode == 'normal':

View File

@@ -2,30 +2,48 @@ import wx
import gui.mainFrame
import webbrowser
import gui.globalEvents as GE
import config
import time
from service.settings import EsiSettings
_t = wx.GetTranslation
class SsoLogin(wx.Dialog):
def __init__(self):
mainFrame = gui.mainFrame.MainFrame.getInstance()
def __init__(self, server: config.ApiServer, start_local_server=True):
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
from service.esi import Esi
super().__init__(
mainFrame, id=wx.ID_ANY, title=_t("SSO Login"), style=wx.DEFAULT_DIALOG_STYLE,
self.mainFrame, id=wx.ID_ANY, title=_t("SSO Login"), style=wx.DEFAULT_DIALOG_STYLE,
size=wx.Size(450, 240) if "wxGTK" in wx.PlatformInfo else wx.Size(400, 240))
bSizer1 = wx.BoxSizer(wx.VERTICAL)
text = wx.StaticText(self, wx.ID_ANY, _t("Copy and paste the block of text provided by pyfa.io"))
bSizer1.Add(text, 0, wx.ALL | wx.EXPAND, 10)
if start_local_server:
text = wx.StaticText(self, wx.ID_ANY, _t("Waiting for character login through EVE Single Sign-On."))
bSizer1.Add(text, 0, wx.ALL | wx.EXPAND, 10)
bSizer1.Add(wx.StaticLine(self, wx.ID_ANY), 0, wx.EXPAND, 15)
text = wx.StaticText(self, wx.ID_ANY, _t("If auto-login fails, copy and paste the token provided by pyfa.io"))
bSizer1.Add(text, 0, wx.ALL | wx.EXPAND, 10)
elif server.name == "Serenity":
text = wx.StaticText(self, wx.ID_ANY, _t("Please copy and paste the url when your authorization is completed"))
bSizer1.Add(text, 0, wx.ALL | wx.EXPAND, 10)
else:
text = wx.StaticText(self, wx.ID_ANY, _t("Please copy and paste the token provided by pyfa.io"))
bSizer1.Add(text, 0, wx.ALL | wx.EXPAND, 10)
self.ssoInfoCtrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, (-1, -1), style=wx.TE_MULTILINE)
self.ssoInfoCtrl.SetFont(wx.Font(8, wx.FONTFAMILY_TELETYPE, wx.NORMAL, wx.NORMAL))
self.ssoInfoCtrl.Layout()
self.ssoInfoCtrl.Bind(wx.EVT_TEXT, self.OnTextEnter)
bSizer1.Add(self.ssoInfoCtrl, 1, wx.LEFT | wx.RIGHT | wx.EXPAND, 10)
self.Esisettings = EsiSettings.getInstance()
bSizer3 = wx.BoxSizer(wx.VERTICAL)
bSizer3.Add(wx.StaticLine(self, wx.ID_ANY), 0, wx.BOTTOM | wx.EXPAND, 10)
@@ -34,51 +52,43 @@ class SsoLogin(wx.Dialog):
self.SetSizer(bSizer1)
self.Center()
from service.esi import Esi
self.sEsi = Esi.getInstance()
uri = self.sEsi.get_login_uri(None)
webbrowser.open(uri)
class SsoLoginServer(wx.Dialog):
def __init__(self, port):
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
super().__init__(self.mainFrame, id=wx.ID_ANY, title=_t("SSO Login"), size=(-1, -1), style=wx.DEFAULT_DIALOG_STYLE)
from service.esi import Esi
self.sEsi = Esi.getInstance()
serverAddr = self.sEsi.startServer(port)
serverAddr = self.sEsi.startServer(0) if start_local_server else None
uri = self.sEsi.get_login_uri(serverAddr)
bSizer1 = wx.BoxSizer(wx.VERTICAL)
self.mainFrame.Bind(GE.EVT_SSO_LOGIN, self.OnLogin)
self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
if server.name == "Serenity":
webbrowser.open(config.SSO_LOGOFF_SERENITY)
time.sleep(1)
text = wx.StaticText(self, wx.ID_ANY, _t("Waiting for character login through EVE Single Sign-On."))
bSizer1.Add(text, 0, wx.ALL | wx.EXPAND, 10)
bSizer3 = wx.BoxSizer(wx.VERTICAL)
bSizer3.Add(wx.StaticLine(self, wx.ID_ANY), 0, wx.BOTTOM | wx.EXPAND, 10)
bSizer3.Add(self.CreateStdDialogButtonSizer(wx.CANCEL), 0, wx.EXPAND)
bSizer1.Add(bSizer3, 0, wx.BOTTOM | wx.RIGHT | wx.LEFT | wx.EXPAND, 10)
self.SetSizer(bSizer1)
self.Fit()
self.Center()
self.okBtn = self.FindWindow(wx.ID_OK)
self.okBtn.Enable(False)
# Ensure we clean up once they hit the "OK" button
self.okBtn.Bind(wx.EVT_BUTTON, self.OnDestroy)
webbrowser.open(uri)
self.mainFrame.Bind(GE.EVT_SSO_LOGIN, self.OnLogin)
# Ensure we clean up if ESC is pressed
self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
def OnTextEnter(self, event):
t = event.String.strip()
if t == "":
self.okBtn.Enable(False)
else:
self.okBtn.Enable(True)
event.Skip()
def OnLogin(self, event):
self.EndModal(wx.ID_OK)
# This would normally happen if it was logged in via server auto-login. In this case, the modal is done, we effectively want to cancel out
self.EndModal(wx.ID_CANCEL)
event.Skip()
def OnDestroy(self, event):
# Clean up by unbinding some events and stopping the server
self.mainFrame.Unbind(GE.EVT_SSO_LOGIN, handler=self.OnLogin)
if self:
self.Unbind(wx.EVT_WINDOW_DESTROY, handler=self.OnDestroy)
self.sEsi.stopServer()
event.Skip()

View File

@@ -2,6 +2,8 @@ import wx
def isDark():
if 'wxMSW' in wx.PlatformInfo:
return False
try:
return wx.SystemSettings.GetAppearance().IsDark()
except (KeyboardInterrupt, SystemExit):

View File

@@ -26,20 +26,20 @@ class exportHtml:
def __init__(self):
self.thread = exportHtmlThread()
def refreshFittingHtml(self, force=False, callback=False):
def refreshFittingHtml(self, force=False, progress=None):
settings = HTMLExportSettings.getInstance()
if force or settings.getEnabled():
self.thread.stop()
self.thread = exportHtmlThread(callback)
self.thread = exportHtmlThread(progress)
self.thread.start()
class exportHtmlThread(threading.Thread):
def __init__(self, callback=False):
def __init__(self, progress=False):
threading.Thread.__init__(self)
self.name = "HTMLExport"
self.callback = callback
self.progress = progress
self.stopRunning = False
def stop(self):
@@ -72,11 +72,13 @@ class exportHtmlThread(threading.Thread):
pass
except (KeyboardInterrupt, SystemExit):
raise
except Exception as ex:
pass
if self.callback:
wx.CallAfter(self.callback, -1)
except Exception as e:
if self.progress:
self.progress.error = f'{e}'
finally:
if self.progress:
self.progress.current += 1
self.progress.workerWorking = False
def generateFullHTML(self, sMkt, sFit, dnaUrl):
""" Generate the complete HTML with styling and javascript """
@@ -171,13 +173,13 @@ class exportHtmlThread(threading.Thread):
</head>
<body>
<div id="canvas" data-role="page">
<div style="text-align: center;"><strong>Last updated:</strong> %s <small>(<span class="timer"></span>)</small></div>
<div data-role="header">
<h1>Pyfa fits</h1>
<h1>Pyfa fits by Group</h1>
</div>
<div data-role="content">
<div style="text-align: center;"><strong>Last updated:</strong> %s <small>(<span class="timer"></span>)</small></div>
""" % (time.time(), dnaUrl, localDate)
HTML += ' <ul data-role="listview" class="ui-listview-outer" data-inset="true" data-filter="true">\n'
categoryList = list(sMkt.getShipRoot())
categoryList.sort(key=lambda _ship: _ship.name)
@@ -214,7 +216,9 @@ class exportHtmlThread(threading.Thread):
eftFit = Port.exportEft(getFit(fit[0]), options={
PortEftOptions.IMPLANTS: True,
PortEftOptions.MUTATIONS: True,
PortEftOptions.LOADED_CHARGES: True})
PortEftOptions.LOADED_CHARGES: True,
PortEftOptions.BOOSTERS: True,
PortEftOptions.CARGO: True})
HTMLfit = (
' <li data-role="collapsible" data-iconpos="right" data-shadow="false" '
@@ -234,8 +238,8 @@ class exportHtmlThread(threading.Thread):
pyfalog.warning("Failed to export line")
continue
finally:
if self.callback:
wx.CallAfter(self.callback, count)
if self.progress:
self.progress.current = count
count += 1
HTMLgroup += HTMLship + (' </ul>\n'
' </li>\n')
@@ -254,6 +258,68 @@ class exportHtmlThread(threading.Thread):
HTML += """
</ul>
</div>
<div data-role="header">
<h1>Pyfa fits by Name</h1>
</div>
<div data-role="content">
"""
HTML += ' <ul data-role="listview" class="ui-listview-outer" data-inset="true" data-filter="true">\n'
categoryList = list(sMkt.getShipRoot())
categoryList.sort(key=lambda _ship: _ship.name)
count = 0
for group in categoryList:
# init market group string to give ships something to attach to
HTMLgroup = ''
ships = list(sMkt.getShipList(group.ID))
ships.sort(key=lambda _ship: _ship.name)
# Keep track of how many ships per group
groupFits = 0
for ship in ships:
fits = sFit.getFitsWithShip(ship.ID)
if len(fits) > 0:
groupFits += len(fits)
for fit in fits:
if self.stopRunning:
return
try:
eftFit = Port.exportEft(getFit(fit[0]), options={
PortEftOptions.IMPLANTS: True,
PortEftOptions.MUTATIONS: True,
PortEftOptions.LOADED_CHARGES: True,
PortEftOptions.BOOSTERS: True,
PortEftOptions.CARGO: True})
HTMLfit = (
' <li data-role="collapsible" data-iconpos="right" data-shadow="false" '
'data-corners="false">\n'
' <h2>' + ship.name + " - " + fit[1] + '</h2>\n'
' <ul data-role="listview" data-shadow="false" data-inset="true" '
'data-corners="false">\n'
)
HTMLfit += ' <li><pre>' + eftFit + '\n </pre></li>\n'
HTMLfit += ' </ul>\n </li>\n'
HTML += HTMLfit
except (KeyboardInterrupt, SystemExit):
raise
except:
pyfalog.warning("Failed to export line")
continue
finally:
if self.progress:
self.progress.current = count
count += 1
HTML += """
</ul>
</div>
</div>
</body>
</html>"""
@@ -291,7 +357,7 @@ class exportHtmlThread(threading.Thread):
pyfalog.error("Failed to export line")
continue
finally:
if self.callback:
wx.CallAfter(self.callback, count)
if self.progress:
self.progress.current = count
count += 1
return HTML

View File

@@ -58,6 +58,9 @@ class InputValidator(metaclass=ABCMeta):
class FloatBox(wx.TextCtrl):
def __init__(self, parent, value, id=wx.ID_ANY, style=0, validator=None, **kwargs):
# Workaround for #2591
if 'wxMac' in wx.PlatformInfo and 'size' not in kwargs:
kwargs['size'] = wx.Size(97, 26)
super().__init__(parent=parent, id=id, style=style, **kwargs)
self.Bind(wx.EVT_TEXT, self.OnText)
self._storedValue = ''
@@ -107,6 +110,9 @@ class FloatBox(wx.TextCtrl):
class FloatRangeBox(wx.TextCtrl):
def __init__(self, parent, value, id=wx.ID_ANY, style=0, **kwargs):
# Workaround for #2591
if 'wxMac' in wx.PlatformInfo and 'size' not in kwargs:
kwargs['size'] = wx.Size(97, 26)
super().__init__(parent=parent, id=id, style=style, **kwargs)
self.Bind(wx.EVT_TEXT, self.OnText)
self._storedValue = ''

View File

@@ -0,0 +1,19 @@
class ProgressHelper:
def __init__(self, message, maximum=None, callback=None):
self.message = message
self.current = 0
self.maximum = maximum
self.workerWorking = True
self.dlgWorking = True
self.error = None
self.callback = callback
self.cbArgs = []
@property
def working(self):
return self.workerWorking and self.dlgWorking and not self.error
@property
def userCancelled(self):
return not self.dlgWorking

BIN
imgs/icons/10155@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 828 B

BIN
imgs/icons/10155@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
imgs/icons/10848@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

BIN
imgs/icons/10848@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
imgs/icons/24603@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 915 B

BIN
imgs/icons/24603@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
imgs/icons/25994@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 918 B

BIN
imgs/icons/25994@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
imgs/icons/26002@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 910 B

BIN
imgs/icons/26002@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
imgs/icons/26004@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 761 B

BIN
imgs/icons/26004@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
imgs/icons/26005@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 B

BIN
imgs/icons/26005@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
imgs/icons/26016@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

BIN
imgs/icons/26016@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
imgs/icons/26017@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

BIN
imgs/icons/26017@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
imgs/icons/26018@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 822 B

BIN
imgs/icons/26018@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
imgs/icons/26019@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

BIN
imgs/icons/26019@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
imgs/icons/26038@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 980 B

BIN
imgs/icons/26038@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
imgs/icons/26039@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 945 B

BIN
imgs/icons/26039@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
imgs/icons/26040@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 947 B

BIN
imgs/icons/26040@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
imgs/icons/26041@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 951 B

BIN
imgs/icons/26041@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
imgs/icons/26042@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 983 B

BIN
imgs/icons/26042@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
imgs/icons/26043@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 961 B

BIN
imgs/icons/26043@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
imgs/icons/26044@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

BIN
imgs/icons/26044@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
imgs/icons/26048@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 680 B

BIN
imgs/icons/26048@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
imgs/icons/26049@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 689 B

BIN
imgs/icons/26049@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
imgs/icons/26050@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 697 B

BIN
imgs/icons/26050@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
imgs/icons/26051@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 725 B

BIN
imgs/icons/26051@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
imgs/icons/26052@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 805 B

BIN
imgs/icons/26052@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
imgs/icons/26053@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

BIN
imgs/icons/26053@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
imgs/icons/26054@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 772 B

BIN
imgs/icons/26054@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
imgs/icons/26055@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 725 B

BIN
imgs/icons/26055@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
imgs/icons/26056@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 692 B

BIN
imgs/icons/26056@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
imgs/icons/26062@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 B

BIN
imgs/icons/26062@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 B

BIN
imgs/icons/26065@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

BIN
imgs/icons/26065@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 498 B

BIN
imgs/icons/26069@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 868 B

BIN
imgs/icons/26069@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
imgs/icons/26070@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

BIN
imgs/icons/26070@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
imgs/icons/26071@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 759 B

BIN
imgs/icons/26071@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
imgs/icons/26072@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 783 B

BIN
imgs/icons/26072@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
imgs/icons/26073@1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 807 B

BIN
imgs/icons/26073@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Some files were not shown because too many files have changed in this diff Show More