1
1
from typing import Callable , Optional
2
2
3
- import re
4
- from pathlib import Path
5
-
6
3
from flet import (
7
4
AlertDialog ,
8
5
FilePicker ,
9
6
FilePickerUploadFile ,
10
7
Page ,
11
8
SnackBar ,
12
9
TemplateRoute ,
13
- Text ,
14
10
View ,
15
11
app ,
16
12
)
17
13
18
- import demo
19
- import sqlmodel
20
14
from auth .view import ProfileScreen , SplashScreen
21
15
from contracts .view import ContractEditorScreen , ViewContractScreen
22
16
from core .abstractions import TuttleView , TuttleViewParams
23
17
from core .client_storage_impl import ClientStorageImpl
18
+ from core .database_storage_impl import DatabaseStorageImpl
24
19
from core .models import RouteView
25
20
from core .utils import AlertDialogControls
26
21
from core .views import get_heading
@@ -64,9 +59,11 @@ def __init__(
64
59
self .page .fonts = APP_FONTS
65
60
self .page .theme = APP_THEME
66
61
self .client_storage = ClientStorageImpl (page = self .page )
67
- preferences = PreferencesIntent (
68
- client_storage = self .client_storage ,
62
+ self .db = DatabaseStorageImpl (
63
+ store_demo_timetracking_dataframe = self .store_demo_timetracking_dataframe ,
64
+ debug_mode = self .debug_mode ,
69
65
)
66
+ preferences = PreferencesIntent (self .client_storage )
70
67
preferences_result = preferences .get_preference_by_key (
71
68
PreferencesStorageKeys .theme_mode_key
72
69
)
@@ -92,10 +89,6 @@ def __init__(
92
89
self .current_route_view : Optional [RouteView ] = None
93
90
self .page .on_resize = self .page_resize
94
91
95
- # database config
96
- self .app_dir = self .ensure_app_dir ()
97
- self .db_path = self .app_dir / "tuttle.db"
98
-
99
92
def page_resize (self , e ):
100
93
if self .current_route_view :
101
94
self .current_route_view .on_window_resized (
@@ -193,7 +186,6 @@ def control_alert_dialog(
193
186
def change_route (self , to_route : str , data : Optional [any ] = None ):
194
187
"""navigates to a new route"""
195
188
newRoute = to_route if data is None else f"{ to_route } /{ data } "
196
-
197
189
self .page .go (newRoute )
198
190
199
191
def on_view_pop (self , view : Optional [View ] = None ):
@@ -247,89 +239,35 @@ def on_route_change(self, route):
247
239
self .page .window_width , self .page .window_height
248
240
)
249
241
250
- def create_model (self ):
251
- logger .info ("Creating database model" )
252
- sqlmodel .SQLModel .metadata .create_all (
253
- self .db_engine ,
254
- checkfirst = True ,
255
- )
256
-
257
- def ensure_database (self ):
258
- """
259
- Ensure that the database exists and is up to date.
260
- """
261
- if not self .db_path .exists ():
262
- self .reset_database ()
263
- else :
264
- logger .info ("Database exists, skipping creation" )
265
-
266
- def reset_database (self ):
267
- """
268
- Delete the database and rebuild database model.
269
- """
270
- logger .info ("Clearing database" )
271
- try :
272
- self .db_path .unlink ()
273
- except FileNotFoundError :
274
- logger .info ("Database file not found, skipping delete" )
275
- self .db_engine = sqlmodel .create_engine (
276
- f"sqlite:///{ self .db_path } " ,
277
- echo = self .debug_mode ,
278
- )
279
- self .create_model ()
280
-
281
242
def store_demo_timetracking_dataframe (self , time_tracking_data : DataFrame ):
282
243
"""Caches the time tracking dataframe created from a demo installation"""
283
244
self .timetracking_intent = TimeTrackingIntent (
284
245
client_storage = self .client_storage
285
246
)
286
247
self .timetracking_intent .set_timetracking_data (data = time_tracking_data )
287
248
288
- def install_demo_data (self ):
289
- """Install demo data into the database."""
290
- self .reset_database ()
291
- try :
292
- demo .install_demo_data (
293
- n_projects = 4 ,
294
- db_path = self .db_path ,
295
- on_cache_timetracking_dataframe = self .store_demo_timetracking_dataframe ,
296
- )
297
- except Exception as ex :
298
- logger .exception (ex )
299
- logger .error ("Failed to install demo data" )
300
-
301
- def ensure_app_dir (self ) -> Path :
302
- """Ensures that the user directory exists"""
303
- app_dir = Path .home () / ".tuttle"
304
- if not app_dir .exists ():
305
- app_dir .mkdir (parents = True )
306
- return app_dir
307
-
308
- def ensure_uploads_dir (self ) -> Path :
309
- uploads_dir = self .app_dir / "uploads"
310
- if not uploads_dir .exists ():
311
- uploads_dir .mkdir (parents = True )
312
- return uploads_dir
249
+ def build (self ):
250
+ self .page .go (self .page .route )
313
251
314
252
def close (self ):
315
253
"""Closes the application."""
316
254
self .page .window_close ()
317
255
318
- def build (self ):
319
- self .page .go (self .page .route )
320
-
321
256
def reset_and_quit (self ):
322
257
"""Resets the application and quits."""
323
- self .reset_database ()
258
+ self .db . reset_database ()
324
259
self .close ()
325
260
326
261
327
262
class TuttleRoutes :
328
263
"""Utility class for parsing of routes to destination views"""
329
264
330
265
def __init__ (self , app : TuttleApp ):
331
- self . app = app
266
+ # init callbacks for some views
332
267
self .on_theme_changed = app .on_theme_mode_changed
268
+ self .on_reset_and_quit = app .reset_and_quit
269
+ self .on_install_demo_data = app .db .install_demo_data
270
+ # init common params for views
333
271
self .tuttle_view_params = TuttleViewParams (
334
272
navigate_to_route = app .change_route ,
335
273
show_snack = app .show_snack ,
@@ -370,14 +308,16 @@ def parse_route(self, pageRoute: str):
370
308
if routePath .match (SPLASH_SCREEN_ROUTE ):
371
309
screen = SplashScreen (
372
310
params = self .tuttle_view_params ,
373
- install_demo_data_callback = self .app . install_demo_data ,
311
+ on_install_demo_data = self .on_install_demo_data ,
374
312
)
375
313
elif routePath .match (HOME_SCREEN_ROUTE ):
376
314
screen = HomeScreen (
377
315
params = self .tuttle_view_params ,
378
316
)
379
317
elif routePath .match (PROFILE_SCREEN_ROUTE ):
380
- screen = ProfileScreen (params = self .tuttle_view_params )
318
+ screen = ProfileScreen (
319
+ params = self .tuttle_view_params ,
320
+ )
381
321
elif routePath .match (CONTRACT_EDITOR_SCREEN_ROUTE ):
382
322
screen = ContractEditorScreen (params = self .tuttle_view_params )
383
323
elif routePath .match (f"{ CONTRACT_DETAILS_SCREEN_ROUTE } /:contractId" ):
@@ -395,7 +335,7 @@ def parse_route(self, pageRoute: str):
395
335
screen = PreferencesScreen (
396
336
params = self .tuttle_view_params ,
397
337
on_theme_changed_callback = self .on_theme_changed ,
398
- on_reset_app_callback = self .app . reset_and_quit ,
338
+ on_reset_app_callback = self .on_reset_and_quit ,
399
339
)
400
340
elif routePath .match (PROJECT_EDITOR_SCREEN_ROUTE ):
401
341
screen = ProjectEditorScreen (params = self .tuttle_view_params )
@@ -431,7 +371,7 @@ def main(page: Page):
431
371
app = TuttleApp (page )
432
372
433
373
# if database does not exist, create it
434
- app .ensure_database ()
374
+ app .db . ensure_database ()
435
375
436
376
app .build ()
437
377
0 commit comments