Skip to content

Commit 016cc20

Browse files
authored
Dev flet gui (#53)
* minimal test * experimentation with flet * minor * MVC example * MVC example * WIP: UI components * removed requirement fints to make pyinstaller work * rename app main file * demo content * displaying demo objects * WIP: desktop app layout * WIP: app layout * WIP: app layout * WIP: app layout * WIP: invoicing page * prepare for merge
1 parent f9883da commit 016cc20

30 files changed

+2671
-30
lines changed

.vscode/settings.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
22
"python.testing.unittestEnabled": false,
3-
"python.testing.pytestEnabled": true
3+
"python.testing.pytestEnabled": true,
4+
"python.formatting.provider": "black"
45
}

app/Tuttle.py

+302
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
from loguru import logger
2+
3+
import flet
4+
from flet import (
5+
Page,
6+
Row,
7+
Column,
8+
Container,
9+
Text,
10+
Card,
11+
NavigationRailDestination,
12+
UserControl,
13+
ElevatedButton,
14+
TextButton,
15+
Icon,
16+
Dropdown,
17+
dropdown,
18+
)
19+
from flet import icons, colors
20+
21+
from layout import DesktopAppLayout
22+
23+
import views
24+
from views import (
25+
ContactView,
26+
ContactView2,
27+
)
28+
29+
from tuttle.controller import Controller
30+
from tuttle.model import (
31+
Contact,
32+
Contract,
33+
Project,
34+
Client,
35+
)
36+
37+
from tuttle_tests import demo
38+
39+
40+
class App:
41+
def __init__(
42+
self,
43+
controller: Controller,
44+
page: Page,
45+
):
46+
self.con = controller
47+
self.page = page
48+
49+
50+
class AppPage(UserControl):
51+
def __init__(
52+
self,
53+
app: App,
54+
):
55+
super().__init__()
56+
self.app = app
57+
58+
def build(self):
59+
self.main_column = Column(
60+
scroll="auto",
61+
)
62+
# self.view = Row([self.main_column])
63+
64+
return self.main_column
65+
66+
def update_content(self):
67+
pass
68+
69+
70+
class DemoPage(AppPage):
71+
def __init__(
72+
self,
73+
app: App,
74+
):
75+
super().__init__(app)
76+
77+
def update(self):
78+
super().update()
79+
80+
def add_demo_data(self, event):
81+
"""Install the demo data on button click."""
82+
demo.add_demo_data(self.app.con)
83+
self.main_column.controls.clear()
84+
self.main_column.controls.append(
85+
Text("Demo data installed ☑️"),
86+
)
87+
self.update()
88+
89+
def build(self):
90+
self.main_column = Column(
91+
[
92+
ElevatedButton(
93+
"Install demo data",
94+
icon=icons.TOYS,
95+
on_click=self.add_demo_data,
96+
),
97+
],
98+
)
99+
return self.main_column
100+
101+
102+
class ContactsPage(AppPage):
103+
def __init__(
104+
self,
105+
app: App,
106+
):
107+
super().__init__(app)
108+
109+
def update(self):
110+
super().update()
111+
112+
def update_content(self):
113+
super().update_content()
114+
self.main_column.controls.clear()
115+
116+
contacts = self.app.con.query(Contact)
117+
118+
for contact in contacts:
119+
self.main_column.controls.append(
120+
views.make_contact_view(contact),
121+
)
122+
self.update()
123+
124+
125+
class ContractsPage(AppPage):
126+
def __init__(
127+
self,
128+
app: App,
129+
):
130+
super().__init__(app)
131+
132+
def update(self):
133+
super().update()
134+
135+
def update_content(self):
136+
super().update_content()
137+
self.main_column.controls.clear()
138+
139+
contracts = self.app.con.query(Contract)
140+
141+
for contract in contracts:
142+
self.main_column.controls.append(
143+
# TODO: replace with view class
144+
views.make_contract_view(contract)
145+
)
146+
self.update()
147+
148+
149+
class ProjectsPage(AppPage):
150+
def __init__(
151+
self,
152+
app: App,
153+
):
154+
super().__init__(app)
155+
156+
def update(self):
157+
super().update()
158+
159+
def update_content(self):
160+
super().update_content()
161+
self.main_column.controls.clear()
162+
163+
projects = self.app.con.query(Project)
164+
165+
for project in projects:
166+
self.main_column.controls.append(
167+
# TODO: replace with view class
168+
views.make_project_view(project)
169+
)
170+
self.update()
171+
172+
173+
class InvoicingPage(AppPage):
174+
def __init__(
175+
self,
176+
app: App,
177+
):
178+
super().__init__(app)
179+
180+
def update(self):
181+
super().update()
182+
183+
def update_content(self):
184+
super().update_content()
185+
186+
self.main_column.controls.clear()
187+
188+
projects = self.app.con.query(Project)
189+
190+
project_select = Dropdown(
191+
label="Project",
192+
hint_text="Select the project",
193+
options=[dropdown.Option(project.title) for project in projects],
194+
autofocus=True,
195+
)
196+
197+
self.main_column.controls.append(
198+
Row(
199+
[
200+
project_select,
201+
]
202+
)
203+
)
204+
self.update()
205+
206+
207+
def main(page: Page):
208+
209+
con = Controller(
210+
in_memory=True,
211+
verbose=False,
212+
)
213+
214+
app = App(
215+
controller=con,
216+
page=page,
217+
)
218+
219+
pages = [
220+
(
221+
NavigationRailDestination(
222+
icon=icons.TOYS_OUTLINED,
223+
selected_icon=icons.TOYS,
224+
label="Demo",
225+
),
226+
DemoPage(app),
227+
),
228+
(
229+
NavigationRailDestination(
230+
icon=icons.SPEED_OUTLINED,
231+
selected_icon=icons.SPEED,
232+
label="Dashboard",
233+
),
234+
AppPage(app),
235+
),
236+
(
237+
NavigationRailDestination(
238+
icon=icons.WORK,
239+
label="Projects",
240+
),
241+
ProjectsPage(app),
242+
),
243+
(
244+
NavigationRailDestination(
245+
icon=icons.DATE_RANGE,
246+
label="Time",
247+
),
248+
AppPage(app),
249+
),
250+
(
251+
NavigationRailDestination(
252+
icon=icons.CONTACT_MAIL,
253+
label="Contacts",
254+
),
255+
ContactsPage(app),
256+
),
257+
(
258+
NavigationRailDestination(
259+
icon=icons.HANDSHAKE,
260+
label="Clients",
261+
),
262+
AppPage(app),
263+
),
264+
(
265+
NavigationRailDestination(
266+
icon=icons.HISTORY_EDU,
267+
label="Contracts",
268+
),
269+
ContractsPage(app),
270+
),
271+
(
272+
NavigationRailDestination(
273+
icon=icons.OUTGOING_MAIL,
274+
label="Invocing",
275+
),
276+
InvoicingPage(app),
277+
),
278+
(
279+
NavigationRailDestination(
280+
icon=icons.SETTINGS,
281+
label_content=Text("Settings"),
282+
),
283+
AppPage(app),
284+
),
285+
]
286+
287+
layout = DesktopAppLayout(
288+
page=page,
289+
pages=pages,
290+
title="Tuttle",
291+
window_size=(1280, 720),
292+
)
293+
294+
page.add(
295+
layout,
296+
)
297+
298+
299+
if __name__ == "__main__":
300+
flet.app(
301+
target=main,
302+
)

0 commit comments

Comments
 (0)