draftomen 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. draftomen/__init__.py +17 -0
  2. draftomen/assets/draftomen.icns +0 -0
  3. draftomen/assets/draftomen.ico +0 -0
  4. draftomen/assets/draftomen_logo.png +0 -0
  5. draftomen/audit.py +606 -0
  6. draftomen/backtest.py +449 -0
  7. draftomen/benchmark.py +834 -0
  8. draftomen/carddb.py +1869 -0
  9. draftomen/cardimages.py +313 -0
  10. draftomen/cli.py +891 -0
  11. draftomen/config.py +133 -0
  12. draftomen/deckbuilder.py +2723 -0
  13. draftomen/events.py +772 -0
  14. draftomen/logfollow.py +451 -0
  15. draftomen/mock_session.py +745 -0
  16. draftomen/paths.py +120 -0
  17. draftomen/pickengine.py +1117 -0
  18. draftomen/pool.py +1259 -0
  19. draftomen/preferences.py +289 -0
  20. draftomen/qml/AboutDialog.qml +156 -0
  21. draftomen/qml/AppBar.qml +120 -0
  22. draftomen/qml/BacktestView.qml +316 -0
  23. draftomen/qml/BuildView.qml +1151 -0
  24. draftomen/qml/CardPreview.qml +434 -0
  25. draftomen/qml/DimensionalButton.qml +42 -0
  26. draftomen/qml/DimensionalComboBox.qml +182 -0
  27. draftomen/qml/DimensionalSurface.qml +118 -0
  28. draftomen/qml/DimensionalTabButton.qml +41 -0
  29. draftomen/qml/LiveDraftView.qml +468 -0
  30. draftomen/qml/Main.qml +175 -0
  31. draftomen/qml/NavigationRail.qml +226 -0
  32. draftomen/qml/PoolSummaryPanel.qml +322 -0
  33. draftomen/qml/PrivacyDialog.qml +96 -0
  34. draftomen/qml/RecentPickThumbnail.qml +83 -0
  35. draftomen/qml/RecentPicksGallery.qml +333 -0
  36. draftomen/qml/RecommendationRow.qml +404 -0
  37. draftomen/qml/SettingsSwitch.qml +141 -0
  38. draftomen/qml/SettingsView.qml +531 -0
  39. draftomen/qml/StateBanner.qml +189 -0
  40. draftomen/qml/StatusStrip.qml +84 -0
  41. draftomen/qml/Theme.qml +71 -0
  42. draftomen/qml/qmldir +23 -0
  43. draftomen/qt_adapter.py +884 -0
  44. draftomen/qt_gui.py +338 -0
  45. draftomen/qt_mock.py +63 -0
  46. draftomen/ranking.py +126 -0
  47. draftomen/replay.py +480 -0
  48. draftomen/session.py +3668 -0
  49. draftomen/setinfo.py +26 -0
  50. draftomen/seventeen.py +2766 -0
  51. draftomen/splash.py +617 -0
  52. draftomen/tui.py +4007 -0
  53. draftomen/watch.py +336 -0
  54. draftomen-0.3.0.dist-info/METADATA +156 -0
  55. draftomen-0.3.0.dist-info/RECORD +59 -0
  56. draftomen-0.3.0.dist-info/WHEEL +5 -0
  57. draftomen-0.3.0.dist-info/entry_points.txt +6 -0
  58. draftomen-0.3.0.dist-info/licenses/LICENSE +21 -0
  59. draftomen-0.3.0.dist-info/top_level.txt +1 -0
draftomen/qml/Main.qml ADDED
@@ -0,0 +1,175 @@
1
+ import QtQuick 2.15
2
+ import QtQuick.Controls 2.15
3
+ import QtQuick.Layouts 1.15
4
+
5
+ ApplicationWindow {
6
+ id: window
7
+ required property var provider
8
+
9
+ width: initialWindowWidth
10
+ height: initialWindowHeight
11
+ minimumWidth: 680
12
+ minimumHeight: 640
13
+ visible: true
14
+ title: applicationTitle
15
+ color: Theme.background
16
+ font.pixelSize: guiPreferences.systemTextScaling
17
+ ? guiPreferences.applicationFontPixelSize
18
+ : Theme.baseFontPixelSize
19
+
20
+ property string currentSurface: initialSurface
21
+ readonly property bool narrow: width < Theme.narrowBreakpoint
22
+ readonly property var sessionState: provider.state
23
+ readonly property var displayPreferences: guiPreferences
24
+ property string automaticBuildContext: ""
25
+ property string pendingCompletedDraftBuildContext: ""
26
+ property string previousPublishedDraftContext: ""
27
+ property bool previousDraftCompleted: false
28
+ readonly property string desktopApplicationVersion: applicationVersion
29
+
30
+ function observePublishedDraftState() {
31
+ const state = window.sessionState
32
+ const draft = state ? state.draft : null
33
+ const draftContext = (
34
+ draft && draft.account_id && draft.draft_id
35
+ ? draft.account_id + ":" + draft.draft_id
36
+ : ""
37
+ )
38
+ const draftCompleted = Boolean(draft && draft.completed)
39
+ const completedTransition = Boolean(
40
+ draftContext
41
+ && draftContext === window.previousPublishedDraftContext
42
+ && !window.previousDraftCompleted
43
+ && draftCompleted
44
+ )
45
+
46
+ window.previousPublishedDraftContext = draftContext
47
+ window.previousDraftCompleted = draftCompleted
48
+ if (completedTransition) {
49
+ window.pendingCompletedDraftBuildContext = draftContext
50
+ window.currentSurface = "build"
51
+ }
52
+ Qt.callLater(window.requestCompletedDraftBuild)
53
+ }
54
+
55
+ function requestCompletedDraftBuild() {
56
+ const state = window.sessionState
57
+ const errors = state ? state.errors : null
58
+ if (errors && errors.some(error => error && error.operation === "build")) {
59
+ window.automaticBuildContext = ""
60
+ return
61
+ }
62
+
63
+ const progress = state ? state.progress : null
64
+ if (progress && progress.operation === "build")
65
+ return
66
+
67
+ if (window.currentSurface !== "build")
68
+ return
69
+
70
+ const draft = state ? state.draft : null
71
+ const pool = state ? state.pool : null
72
+ const cardData = state ? state.card_data : null
73
+ if (!draft || !draft.completed || !pool || pool.total_cards <= 0
74
+ || !cardData || cardData.phase !== "ready")
75
+ return
76
+
77
+ const context = draft.account_id + ":" + draft.draft_id
78
+ const completedTransitionPending = (
79
+ window.pendingCompletedDraftBuildContext === context
80
+ )
81
+ if (!completedTransitionPending
82
+ && (state.build || window.automaticBuildContext === context))
83
+ return
84
+
85
+ window.automaticBuildContext = context
86
+ window.pendingCompletedDraftBuildContext = ""
87
+ window.provider.requestBuild("")
88
+ }
89
+
90
+ onCurrentSurfaceChanged: Qt.callLater(window.requestCompletedDraftBuild)
91
+ onSessionStateChanged: window.observePublishedDraftState()
92
+ Component.onCompleted: window.observePublishedDraftState()
93
+
94
+ header: AppBar {
95
+ narrow: window.narrow
96
+ sessionState: window.sessionState
97
+ provider: window.provider
98
+ onSettingsRequested: window.currentSurface = "settings"
99
+ }
100
+
101
+ footer: StatusStrip {
102
+ sessionState: window.sessionState
103
+ displayPreferences: window.displayPreferences
104
+ applicationVersion: window.desktopApplicationVersion
105
+ narrow: window.narrow
106
+ }
107
+
108
+ AboutDialog {
109
+ id: aboutDialog
110
+ applicationVersion: window.desktopApplicationVersion
111
+ }
112
+
113
+ PrivacyDialog {
114
+ id: privacyDialog
115
+ }
116
+
117
+ RowLayout {
118
+ anchors.fill: parent
119
+ spacing: 0
120
+
121
+ NavigationRail {
122
+ Layout.fillHeight: true
123
+ currentSurface: window.currentSurface
124
+ compact: window.narrow
125
+ displayPreferences: window.displayPreferences
126
+ onSurfaceRequested: surface => window.currentSurface = surface
127
+ onAboutRequested: opener => {
128
+ aboutDialog.returnFocusItem = opener
129
+ aboutDialog.open()
130
+ }
131
+ onPrivacyRequested: opener => {
132
+ privacyDialog.returnFocusItem = opener
133
+ privacyDialog.open()
134
+ }
135
+ }
136
+
137
+ StackLayout {
138
+ Layout.fillWidth: true
139
+ Layout.fillHeight: true
140
+ Layout.margins: window.narrow ? 12 : 20
141
+ currentIndex: {
142
+ if (window.currentSurface === "build") return 1
143
+ if (window.currentSurface === "backtest") return 2
144
+ if (window.currentSurface === "settings") return 3
145
+ return 0
146
+ }
147
+
148
+ LiveDraftView {
149
+ sessionState: window.sessionState
150
+ recommendationModel: window.provider.recommendationsModel
151
+ narrow: window.narrow
152
+ displayPreferences: window.displayPreferences
153
+ }
154
+
155
+ BuildView {
156
+ sessionState: window.sessionState
157
+ narrow: window.narrow
158
+ displayPreferences: window.displayPreferences
159
+ }
160
+
161
+ BacktestView {
162
+ sessionState: window.sessionState
163
+ narrow: window.narrow
164
+ displayPreferences: window.displayPreferences
165
+ }
166
+
167
+ SettingsView {
168
+ sessionState: window.sessionState
169
+ narrow: window.narrow
170
+ displayPreferences: window.displayPreferences
171
+ }
172
+ }
173
+ }
174
+ }
175
+
@@ -0,0 +1,226 @@
1
+ pragma ComponentBehavior: Bound
2
+
3
+ import QtQuick 2.15
4
+ import QtQuick.Controls 2.15
5
+ import QtQuick.Layouts 1.15
6
+
7
+ Rectangle {
8
+ id: root
9
+ objectName: "navigationRail"
10
+
11
+ required property string currentSurface
12
+ required property bool compact
13
+ required property var displayPreferences
14
+ readonly property bool backtestNavigationVisible: root.displayPreferences.showBacktest
15
+ signal surfaceRequested(string surface)
16
+ signal aboutRequested(var opener)
17
+ signal privacyRequested(var opener)
18
+
19
+ color: Theme.surfaceLow
20
+ implicitWidth: compact ? 116 : 176
21
+
22
+ ButtonGroup {
23
+ id: navigationGroup
24
+ }
25
+
26
+ ColumnLayout {
27
+ anchors.fill: parent
28
+ anchors.margins: 12
29
+ spacing: 8
30
+
31
+ ColumnLayout {
32
+ Layout.fillWidth: true
33
+ visible: !root.compact
34
+ spacing: 6
35
+
36
+ Label {
37
+ Layout.fillWidth: true
38
+ text: "DRAFTOMEN"
39
+ color: Theme.primary
40
+ font.pixelSize: Theme.textPixelSize(14)
41
+ font.bold: true
42
+ font.letterSpacing: 1.2
43
+ horizontalAlignment: Text.AlignHCenter
44
+ }
45
+
46
+ Rectangle {
47
+ Layout.alignment: Qt.AlignHCenter
48
+ Layout.preferredWidth: 144
49
+ Layout.preferredHeight: 144
50
+ color: Theme.background
51
+ border.color: Theme.outline
52
+ border.width: 1
53
+ radius: Theme.radius
54
+ clip: true
55
+
56
+ Image {
57
+ objectName: "draftomenLogo"
58
+ anchors.fill: parent
59
+ source: "../assets/draftomen_logo.png"
60
+ sourceSize.width: 288
61
+ sourceSize.height: 288
62
+ fillMode: Image.PreserveAspectFit
63
+ smooth: true
64
+ mipmap: true
65
+ Accessible.name: "Draft Omen logo"
66
+ }
67
+ }
68
+ }
69
+
70
+ Repeater {
71
+ model: [
72
+ { key: "live", label: "Live Draft", shortLabel: "Draft", icon: "gavel" },
73
+ { key: "build", label: "Deck Build", shortLabel: "Build", icon: "style" },
74
+ { key: "backtest", label: "Backtest", shortLabel: "Backtest", icon: "history" }
75
+ ]
76
+
77
+ delegate: DimensionalButton {
78
+ id: navigationButton
79
+ required property var modelData
80
+
81
+ Layout.fillWidth: true
82
+ Layout.preferredHeight: Theme.targetHeight
83
+ visible: navigationButton.modelData.key !== "backtest"
84
+ || root.backtestNavigationVisible
85
+ text: root.compact
86
+ ? navigationButton.modelData.shortLabel
87
+ : navigationButton.modelData.label
88
+ checkable: true
89
+ checked: root.currentSurface === navigationButton.modelData.key
90
+ accented: navigationButton.checked
91
+ ButtonGroup.group: navigationGroup
92
+ Accessible.name: navigationButton.modelData.label
93
+ Accessible.description: "Open the " + navigationButton.modelData.label + " surface."
94
+ onClicked: root.surfaceRequested(navigationButton.modelData.key)
95
+
96
+ contentItem: RowLayout {
97
+ anchors.fill: parent
98
+ anchors.topMargin: navigationButton.down ? Theme.controlPressOffset : 0
99
+ anchors.leftMargin: root.compact ? 6 : 10
100
+ anchors.rightMargin: root.compact ? 6 : 10
101
+ spacing: root.compact ? 6 : 10
102
+
103
+ Canvas {
104
+ id: navigationIcon
105
+ objectName: navigationButton.modelData.key + "NavigationIcon"
106
+ Layout.preferredWidth: 24
107
+ Layout.preferredHeight: 24
108
+ Layout.alignment: Qt.AlignVCenter
109
+ implicitWidth: 24
110
+ implicitHeight: 24
111
+ property string iconName: navigationButton.modelData.icon
112
+ property color iconColor: navigationButton.contentColor
113
+
114
+ onIconNameChanged: requestPaint()
115
+ onIconColorChanged: requestPaint()
116
+ Component.onCompleted: requestPaint()
117
+
118
+ onPaint: {
119
+ var context = getContext("2d")
120
+ context.clearRect(0, 0, width, height)
121
+ context.strokeStyle = iconColor
122
+ context.fillStyle = iconColor
123
+ context.lineWidth = 2
124
+ context.lineCap = "round"
125
+ context.lineJoin = "round"
126
+
127
+ if (iconName === "gavel") {
128
+ context.save()
129
+ context.translate(12, 11)
130
+ context.rotate(-Math.PI / 4)
131
+ context.fillRect(-4, -9, 8, 9)
132
+ context.fillRect(-1.5, 0, 3, 10)
133
+ context.restore()
134
+ context.fillRect(2, 20, 20, 2)
135
+ } else if (iconName === "style") {
136
+ context.strokeRect(4, 3, 16, 13)
137
+ context.strokeRect(2, 7, 16, 13)
138
+ context.beginPath()
139
+ context.moveTo(7, 11)
140
+ context.lineTo(15, 11)
141
+ context.stroke()
142
+ } else if (iconName === "history") {
143
+ context.beginPath()
144
+ context.arc(12, 12, 8, -Math.PI * 0.78, Math.PI * 1.64)
145
+ context.stroke()
146
+ context.beginPath()
147
+ context.moveTo(4, 4)
148
+ context.lineTo(4, 9)
149
+ context.lineTo(9, 7)
150
+ context.fill()
151
+ context.beginPath()
152
+ context.moveTo(12, 7)
153
+ context.lineTo(12, 12)
154
+ context.lineTo(16, 14)
155
+ context.stroke()
156
+ }
157
+ }
158
+ }
159
+
160
+ Text {
161
+ Layout.fillWidth: true
162
+ text: navigationButton.text
163
+ color: navigationButton.contentColor
164
+ font.bold: navigationButton.checked
165
+ verticalAlignment: Text.AlignVCenter
166
+ horizontalAlignment: Text.AlignLeft
167
+ }
168
+ }
169
+ }
170
+ }
171
+
172
+ Item {
173
+ Layout.fillHeight: true
174
+ }
175
+
176
+ ColumnLayout {
177
+ Layout.fillWidth: true
178
+ spacing: 6
179
+
180
+ DimensionalButton {
181
+ id: aboutButton
182
+ objectName: "aboutLink"
183
+ Layout.fillWidth: true
184
+ text: "About"
185
+ accented: true
186
+ accentColor: Theme.primary
187
+ accentContentColor: Theme.primaryContent
188
+ Accessible.name: "Open About dialog"
189
+ Accessible.description: "Show Draft Omen information and project website."
190
+ onClicked: root.aboutRequested(aboutButton)
191
+ }
192
+
193
+ DimensionalButton {
194
+ id: privacyButton
195
+ objectName: "privacyLink"
196
+ Layout.fillWidth: true
197
+ text: "Privacy"
198
+ accented: true
199
+ accentColor: Theme.secondary
200
+ accentContentColor: Theme.secondaryContent
201
+ activeFocusOnTab: true
202
+ focusPolicy: Qt.StrongFocus
203
+ Accessible.role: Accessible.Button
204
+ Accessible.name: "Open Privacy dialog"
205
+ Accessible.description: "Show how Draft Omen handles your data."
206
+ onClicked: root.privacyRequested(privacyButton)
207
+ }
208
+
209
+ Label {
210
+ Layout.fillWidth: true
211
+ text: root.compact ? "Read only" : "Arena integration · Read only"
212
+ color: Theme.textMuted
213
+ font.pixelSize: Theme.textPixelSize(10)
214
+ wrapMode: Text.WordWrap
215
+ }
216
+ }
217
+ }
218
+
219
+ Rectangle {
220
+ anchors.right: parent.right
221
+ width: 1
222
+ height: parent.height
223
+ color: Theme.outline
224
+ }
225
+ }
226
+