pyflutter-app 0.1.4__tar.gz → 0.1.6__tar.gz
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.
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/PKG-INFO +1 -1
- pyflutter_app-0.1.6/converter/config_app.py +114 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/excel/controller.py +1 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/excel/view.py +9 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/page_forms/config.py +71 -1
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/page_forms/controller_forms.py +18 -10
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/run.py +7 -2
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/local_build/linux.sh +1 -1
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/local_build/send.sh +2 -2
- pyflutter_app-0.1.6/main.py +18 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/pyflutter_ui/app.py +1 -1
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/pyflutter_ui/file_picker.py +6 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/pyflutter_ui/theme.py +3 -3
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/pyflutter_ui/widgets.py +1 -1
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/pyproject.toml +1 -1
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/uv.lock +1 -1
- pyflutter_app-0.1.4/claude.py +0 -202
- pyflutter_app-0.1.4/main.py +0 -32
- pyflutter_app-0.1.4/theme_demo.py +0 -162
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/.gitignore +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/.idea/.gitignore +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/.idea/inspectionProfiles/Project_Default.xml +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/.idea/misc.xml +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/.idea/modules.xml +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/.idea/pyflutter.iml +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/.idea/vcs.xml +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/README.md +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/__init__.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/__main__.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/assets/forms_config.json +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/excel/__init__.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/excel/_page_edit.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/excel/model.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/lib_toi.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/page_forms/__init__.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/page_forms/common.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/page_forms/model_forms.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/page_forms/service.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/table_widget.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/whatsapp/__init__.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/whatsapp/model.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/export_app.sh +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/pyflutter_ui/__init__.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/pyflutter_ui/core.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/pyflutter_ui/navigator.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/__init__.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/erros.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/hash_map.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/notifier.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/pattner/__init__.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/pattner/adapter.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/pattner/observer.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/sheet/__init__.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/sheet/check_mod.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/sheet/load.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/sheet/options.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/sheet/parse.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/sheet/save.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/state.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/sysfiles.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/thread.py +0 -0
- {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/workbook.py +0 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Any, Callable
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from table_stream.sysfiles import File, Directory, UserFileSystem, JsonConvert, JsonData
|
|
6
|
+
from table_stream import HashMapDict
|
|
7
|
+
from pyflutter_ui.theme import ThemeMode
|
|
8
|
+
from pyflutter_ui.core import ValueNotifier, ChangeNotifier
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class MapConfig:
|
|
13
|
+
|
|
14
|
+
initial_dir: Directory
|
|
15
|
+
last_dir: Directory
|
|
16
|
+
work_dir: Directory
|
|
17
|
+
documents_dir: Directory
|
|
18
|
+
theme_mode: ThemeMode
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class FactoryMapConfig(object):
|
|
23
|
+
|
|
24
|
+
def __init__(self) -> None:
|
|
25
|
+
self._conf: MapConfig = MapConfig(
|
|
26
|
+
initial_dir=UserFileSystem().get_user_downloads(),
|
|
27
|
+
last_dir=UserFileSystem().get_user_downloads(),
|
|
28
|
+
work_dir=UserFileSystem().get_user_downloads().concat("RFA", True),
|
|
29
|
+
documents_dir=UserFileSystem().get_user_downloads().concat("RFA", True),
|
|
30
|
+
theme_mode=ThemeMode.DARK,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
def create_default(self) -> MapConfig:
|
|
34
|
+
return self._conf
|
|
35
|
+
|
|
36
|
+
def create_from_dict(self, h: HashMapDict[str, str]) -> MapConfig:
|
|
37
|
+
if h.header().contains("initial_dir"):
|
|
38
|
+
self._conf.initial_dir = Directory(h["initial_dir"])
|
|
39
|
+
if h.header().contains("last_dir"):
|
|
40
|
+
self._conf.last_dir = Directory(h["last_dir"])
|
|
41
|
+
if h.header().contains("documents_dir"):
|
|
42
|
+
self._conf.last_dir = Directory(h["documents_dir"])
|
|
43
|
+
if h.header().contains("theme_mode"):
|
|
44
|
+
if h["theme_mode"] == "dark":
|
|
45
|
+
self._conf.theme_mode = ThemeMode.DARK
|
|
46
|
+
elif h["theme_mode"] == "light":
|
|
47
|
+
self._conf.theme_mode = ThemeMode.LIGHT
|
|
48
|
+
else:
|
|
49
|
+
self._conf.theme_mode = ThemeMode.SYSTEM
|
|
50
|
+
return self._conf
|
|
51
|
+
|
|
52
|
+
def create_from_file(self, file_json: File) -> MapConfig:
|
|
53
|
+
converter = JsonConvert.from_file(file_json)
|
|
54
|
+
map_data = converter.data.to_dict()
|
|
55
|
+
return self.create_from_dict(HashMapDict(map_data))
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class AppConfigNotifier(ValueNotifier[MapConfig]):
|
|
59
|
+
|
|
60
|
+
file_config: File = UserFileSystem().cache_dir().join_file("RFA-config.json")
|
|
61
|
+
|
|
62
|
+
def __init__(self, value: MapConfig = FactoryMapConfig().create_default()) -> None:
|
|
63
|
+
super().__init__(value)
|
|
64
|
+
#self._file_config: File = self.value.work_dir.concat("config", True).join_file("app_config.json")
|
|
65
|
+
|
|
66
|
+
def set_work_dir(self, d: Directory):
|
|
67
|
+
self._value.work_dir = d
|
|
68
|
+
self.notify_listeners()
|
|
69
|
+
|
|
70
|
+
def set_initial_dir(self, d: Directory):
|
|
71
|
+
self._value.initial_dir = d
|
|
72
|
+
self.notify_listeners()
|
|
73
|
+
|
|
74
|
+
def set_documents_dir(self, d: Directory):
|
|
75
|
+
self._value.documents_dir = d
|
|
76
|
+
self.notify_listeners()
|
|
77
|
+
|
|
78
|
+
def get_file_config(self) -> File:
|
|
79
|
+
return AppConfigNotifier.file_config
|
|
80
|
+
|
|
81
|
+
def get_dict_config(self) -> dict[str, str]:
|
|
82
|
+
final = dict()
|
|
83
|
+
final["initial_dir"] = self.value.initial_dir.absolute()
|
|
84
|
+
final["last_dir"] = self.value.last_dir.absolute()
|
|
85
|
+
final["work_dir"] = self.value.work_dir.absolute()
|
|
86
|
+
final["documents_dir"] = self.value.documents_dir.absolute()
|
|
87
|
+
final["theme_mode"] = self.value.theme_mode.value
|
|
88
|
+
return final
|
|
89
|
+
|
|
90
|
+
def save_config(self):
|
|
91
|
+
converter = JsonConvert.from_dict(self.get_dict_config())
|
|
92
|
+
converter.data.to_file(self.get_file_config())
|
|
93
|
+
print(f'Configurações salvas em ... {self.get_file_config().absolute()}')
|
|
94
|
+
|
|
95
|
+
def notify_listeners(self) -> None:
|
|
96
|
+
"""
|
|
97
|
+
Salvar a nova configuração em arquivo local e notificar os observadores.
|
|
98
|
+
"""
|
|
99
|
+
self.save_config()
|
|
100
|
+
return super().notify_listeners()
|
|
101
|
+
|
|
102
|
+
@classmethod
|
|
103
|
+
def create(cls) -> AppConfigNotifier:
|
|
104
|
+
src = Directory(cls.file_config.dirname())
|
|
105
|
+
src.mkdir()
|
|
106
|
+
|
|
107
|
+
config: MapConfig
|
|
108
|
+
if cls.file_config.exists():
|
|
109
|
+
print(f'Lendo configração em ... {cls.file_config.absolute()}')
|
|
110
|
+
config = FactoryMapConfig().create_from_file(cls.file_config)
|
|
111
|
+
else:
|
|
112
|
+
config = FactoryMapConfig().create_default()
|
|
113
|
+
return cls(config)
|
|
114
|
+
|
|
@@ -15,6 +15,7 @@ from table_stream.sysfiles import Directory, File
|
|
|
15
15
|
|
|
16
16
|
from pyflutter_ui import ChangeNotifier, CommandNotifier, ValueNotifier
|
|
17
17
|
from converter.excel.model import ExcelModel
|
|
18
|
+
from converter.config_app import AppConfigNotifier, MapConfig
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
class FileNotifier(ValueNotifier[HashMapDict[str, File]]):
|
|
@@ -31,6 +31,7 @@ from converter.excel._page_edit import PageEditExcel
|
|
|
31
31
|
# Páginas
|
|
32
32
|
from converter.page_forms import PageRespondsForms
|
|
33
33
|
from converter.page_forms import ControllerForms
|
|
34
|
+
from converter.config_app import MapConfig, AppConfigNotifier
|
|
34
35
|
|
|
35
36
|
|
|
36
37
|
class HomePage(StatelessWidget):
|
|
@@ -51,6 +52,7 @@ class _HomePageState(StatelessWidget):
|
|
|
51
52
|
type=FilePickerType.spreadsheet,
|
|
52
53
|
allow_multiple=True,
|
|
53
54
|
dialog_title="Escolha Planilhas",
|
|
55
|
+
initial_directory=self.app_config.value.initial_dir.absolute(),
|
|
54
56
|
)
|
|
55
57
|
|
|
56
58
|
self.mapping_csv_sep = HashMapDict[str, csvSeparator](
|
|
@@ -68,6 +70,11 @@ class _HomePageState(StatelessWidget):
|
|
|
68
70
|
"latin": "latin1"
|
|
69
71
|
})
|
|
70
72
|
|
|
73
|
+
@property
|
|
74
|
+
def app_config(self) -> AppConfigNotifier:
|
|
75
|
+
state = Provider.read(AppConfigNotifier)
|
|
76
|
+
return state
|
|
77
|
+
|
|
71
78
|
@property
|
|
72
79
|
def controller(self) -> ControllerHomePage:
|
|
73
80
|
return Provider.read(ControllerHomePage)
|
|
@@ -82,6 +89,8 @@ class _HomePageState(StatelessWidget):
|
|
|
82
89
|
if result is None:
|
|
83
90
|
return
|
|
84
91
|
|
|
92
|
+
self.app_config.set_initial_dir(Directory(self._pick.initial_directory))
|
|
93
|
+
|
|
85
94
|
files: list[PlatformFile] = result.files
|
|
86
95
|
final_files: ArrayList[File] = ArrayList()
|
|
87
96
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
from dataclasses import dataclass, field
|
|
3
3
|
from enum import Enum
|
|
4
|
-
from typing import Optional
|
|
4
|
+
from typing import Optional, Any
|
|
5
5
|
|
|
6
6
|
from table_stream.sysfiles import File, JsonConvert
|
|
7
|
+
from table_stream.hash_map import HashMapDict
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
class FieldType(Enum):
|
|
@@ -76,6 +77,70 @@ class FormField:
|
|
|
76
77
|
)
|
|
77
78
|
|
|
78
79
|
|
|
80
|
+
class DefaultConfig(HashMapDict[str, Any]):
|
|
81
|
+
|
|
82
|
+
config: dict = {
|
|
83
|
+
"form_url": "https://forms.office.com/pages/responsepage.aspx?id=hoDG-Fy5y0mdOO03lAq-9Q3te9L0aHxBnNMUUIYjxH9UMVFGS0ozVEVKVU84RlBDNTJXVlQ1UUZZRy4u",
|
|
84
|
+
"success_text": "Sua resposta foi enviada",
|
|
85
|
+
"wait_after_submit_ms": 2500,
|
|
86
|
+
"fields": [
|
|
87
|
+
{
|
|
88
|
+
"name": "uc",
|
|
89
|
+
"question_text": "uc",
|
|
90
|
+
"field_type": "text",
|
|
91
|
+
"column": None,
|
|
92
|
+
"options": [],
|
|
93
|
+
"multiple_files": False,
|
|
94
|
+
"date_format": "%d/%m/%Y",
|
|
95
|
+
"required": True
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"name": "toi",
|
|
99
|
+
"question_text": "toi",
|
|
100
|
+
"field_type": "text",
|
|
101
|
+
"column": None,
|
|
102
|
+
"options": [],
|
|
103
|
+
"multiple_files": False,
|
|
104
|
+
"date_format": "%d/%m/%Y",
|
|
105
|
+
"required": True
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"name": "local",
|
|
109
|
+
"question_text": "local de entrega",
|
|
110
|
+
"field_type": "radio",
|
|
111
|
+
"column": None,
|
|
112
|
+
"options": ["em mãos", "caixa de correios", "outro"],
|
|
113
|
+
"multiple_files": False,
|
|
114
|
+
"date_format": "%d/%m/%Y",
|
|
115
|
+
"required": True
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"name": "tipo",
|
|
119
|
+
"question_text": "tipo de documento",
|
|
120
|
+
"field_type": "dropdown",
|
|
121
|
+
"column": None,
|
|
122
|
+
"options": ["carta calculo fatura", "via toi", "cumprimento sentença"],
|
|
123
|
+
"multiple_files": False,
|
|
124
|
+
"date_format": "%d/%m/%Y",
|
|
125
|
+
"required": True
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"name": "data",
|
|
129
|
+
"question_text": "data",
|
|
130
|
+
"field_type": "date",
|
|
131
|
+
"column": None,
|
|
132
|
+
"options": [],
|
|
133
|
+
"multiple_files": False,
|
|
134
|
+
"date_format": "%d/%m/%Y",
|
|
135
|
+
"required": True
|
|
136
|
+
}
|
|
137
|
+
]
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
def __init__(self) -> None:
|
|
141
|
+
super().__init__(DefaultConfig.config)
|
|
142
|
+
|
|
143
|
+
|
|
79
144
|
@dataclass
|
|
80
145
|
class FormsConfig:
|
|
81
146
|
"""
|
|
@@ -127,3 +192,8 @@ class FormsConfig:
|
|
|
127
192
|
def load(cls, file: File) -> FormsConfig:
|
|
128
193
|
convert = JsonConvert.from_file(file)
|
|
129
194
|
return cls.from_dict(convert.data.to_dict())
|
|
195
|
+
|
|
196
|
+
@classmethod
|
|
197
|
+
def create_default(cls) -> FormsConfig:
|
|
198
|
+
return cls.from_dict(DefaultConfig().get_real_hash_map())
|
|
199
|
+
|
|
@@ -13,6 +13,7 @@ from pyflutter_ui.widgets import LinearProgress
|
|
|
13
13
|
from converter.page_forms.model_forms import ModelForms
|
|
14
14
|
from converter.page_forms.common import RowResult, RowStatus
|
|
15
15
|
from converter.page_forms.config import FormsConfig, FieldType, FormField, JsonConvert
|
|
16
|
+
from converter.config_app import AppConfigNotifier, MapConfig
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
class ValueNotifierDocuments(ValueNotifier[Directory]):
|
|
@@ -21,7 +22,7 @@ class ValueNotifierDocuments(ValueNotifier[Directory]):
|
|
|
21
22
|
super().__init__(value)
|
|
22
23
|
self._context_state: ContextState = ContextState()
|
|
23
24
|
self.model: ModelForms = model
|
|
24
|
-
|
|
25
|
+
self.app_config = Provider.read(AppConfigNotifier)
|
|
25
26
|
self.listener = ConsumerThread(
|
|
26
27
|
ThreadStateContext,
|
|
27
28
|
on_finish=self._set_context_thread,
|
|
@@ -42,6 +43,10 @@ class ValueNotifierDocuments(ValueNotifier[Directory]):
|
|
|
42
43
|
def set_dir_documents(self, d: Directory):
|
|
43
44
|
self.value = d
|
|
44
45
|
|
|
46
|
+
def notify_listeners(self) -> None:
|
|
47
|
+
self.app_config.set_documents_dir(self.value)
|
|
48
|
+
return super().notify_listeners()
|
|
49
|
+
|
|
45
50
|
def convert_documents_to_sheet(self) -> None:
|
|
46
51
|
if self.model.context_state.is_running():
|
|
47
52
|
self.msg_erro = "Existe outra operação em andamento, aguarde..."
|
|
@@ -69,8 +74,10 @@ class RunNotifier(ValueNotifier[ArrayList[RowResult]]):
|
|
|
69
74
|
|
|
70
75
|
self.current_index: int = -1
|
|
71
76
|
self.log_lines: ArrayList[str] = ArrayList()
|
|
72
|
-
self.file_config: File =
|
|
73
|
-
self.config: FormsConfig = FormsConfig.load(self.file_config)
|
|
77
|
+
#self.file_config: File =
|
|
78
|
+
#self.config: FormsConfig = FormsConfig.load(self.file_config)
|
|
79
|
+
self.forms_config: FormsConfig = FormsConfig.create_default()
|
|
80
|
+
self.app_config = Provider.read(AppConfigNotifier)
|
|
74
81
|
|
|
75
82
|
@property
|
|
76
83
|
def running(self) -> bool:
|
|
@@ -128,9 +135,10 @@ class ControllerForms(ChangeNotifier):
|
|
|
128
135
|
self.model.context_state.add_listener(self.listener_state)
|
|
129
136
|
|
|
130
137
|
# Arquivos e diretórios das cartas
|
|
131
|
-
self.
|
|
138
|
+
self.app_config: AppConfigNotifier = Provider.read(AppConfigNotifier)
|
|
139
|
+
|
|
132
140
|
self.value_notifier_docs: ValueNotifierDocuments = ValueNotifierDocuments(
|
|
133
|
-
self.
|
|
141
|
+
self.app_config.value.documents_dir,
|
|
134
142
|
self.model,
|
|
135
143
|
)
|
|
136
144
|
|
|
@@ -143,6 +151,10 @@ class ControllerForms(ChangeNotifier):
|
|
|
143
151
|
self.msg_erro: str = None
|
|
144
152
|
self._context_state = ThreadStateContext()
|
|
145
153
|
|
|
154
|
+
@property
|
|
155
|
+
def work_dir(self) -> Directory:
|
|
156
|
+
return self.app_config.value.work_dir
|
|
157
|
+
|
|
146
158
|
@property
|
|
147
159
|
def context_state(self) -> ThreadStateContext:
|
|
148
160
|
return self._context_state
|
|
@@ -151,10 +163,6 @@ class ControllerForms(ChangeNotifier):
|
|
|
151
163
|
def data(self) -> pd.DataFrame:
|
|
152
164
|
return self.data_notifier.value
|
|
153
165
|
|
|
154
|
-
@property
|
|
155
|
-
def dir_export_sheet(self) -> Directory:
|
|
156
|
-
return self.work_dir.concat('Planilhas Exportadas', True)
|
|
157
|
-
|
|
158
166
|
def _set_context(self, thread_context: ThreadStateContext):
|
|
159
167
|
self._context_state = thread_context
|
|
160
168
|
print(f'{__class__.__name__} Context atualizado ... {self.context_state.state.name}')
|
|
@@ -164,7 +172,7 @@ class ControllerForms(ChangeNotifier):
|
|
|
164
172
|
self.data_notifier.value = df # já dispara notify_listeners() (ValueNotifier.value.setter)
|
|
165
173
|
|
|
166
174
|
def set_work_dir(self, d: Directory):
|
|
167
|
-
self.
|
|
175
|
+
self.app_config.set_work_dir(d)
|
|
168
176
|
self.notify_listeners()
|
|
169
177
|
|
|
170
178
|
def get_table_documents(self) -> ParserData:
|
|
@@ -7,21 +7,26 @@ from converter.excel.model import ExcelModel
|
|
|
7
7
|
|
|
8
8
|
from converter.page_forms import ControllerForms
|
|
9
9
|
from converter.page_forms.model_forms import ModelForms
|
|
10
|
+
from converter.config_app import AppConfigNotifier, FactoryMapConfig, MapConfig
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
def main() -> None:
|
|
13
|
-
|
|
14
|
+
Provider.add_state(AppConfigNotifier.create()) # ValueNotifier/Configuração
|
|
15
|
+
|
|
16
|
+
excel_model = ExcelModel()
|
|
14
17
|
model_forms = ModelForms()
|
|
15
18
|
|
|
16
|
-
controller_excel = ControllerHomePage(
|
|
19
|
+
controller_excel = ControllerHomePage(excel_model)
|
|
17
20
|
controller_forms = ControllerForms(model_forms)
|
|
18
21
|
|
|
19
22
|
app = TkMaterialApp(home=HomePage())
|
|
20
23
|
#app.register_notifier(controller)
|
|
24
|
+
|
|
21
25
|
Provider.add_state(controller_excel)
|
|
22
26
|
Provider.add_state(controller_excel.data_columns)
|
|
23
27
|
Provider.add_state(controller_forms)
|
|
24
28
|
|
|
29
|
+
|
|
25
30
|
app.set_width(760)
|
|
26
31
|
app.set_height(480)
|
|
27
32
|
run_app(app)
|
|
@@ -13,7 +13,7 @@ function main(){
|
|
|
13
13
|
uv sync || exit 1
|
|
14
14
|
# Executa o build usando o ambiente gerenciado pelo uv
|
|
15
15
|
uv run python -m build || exit 1
|
|
16
|
-
#pip3 install build
|
|
16
|
+
# pip3 install build
|
|
17
17
|
#python3 -m build
|
|
18
18
|
|
|
19
19
|
echo -e "\nPara enviar ao PyPI use ->> python3 -m twine upload dist/*"
|
|
@@ -8,8 +8,8 @@ VENV_ACTIVATE="${LOCAL_DIR_VENV}/bin/activate"
|
|
|
8
8
|
source "${VENV_ACTIVATE}" || exit 1
|
|
9
9
|
|
|
10
10
|
function main(){
|
|
11
|
-
#pip3 install twine
|
|
12
|
-
uv add twine build
|
|
11
|
+
# pip3 install twine
|
|
12
|
+
# uv add twine build
|
|
13
13
|
echo -e "Enviando ao PyPI"
|
|
14
14
|
python3 -m twine upload --verbose dist/*
|
|
15
15
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
|
|
2
|
+
def test():
|
|
3
|
+
from table_stream.sysfiles import File, Directory, UserFileSystem
|
|
4
|
+
from table_stream.sysfiles import JsonConvert, JsonData
|
|
5
|
+
|
|
6
|
+
f = File("/home/bruno/GIT/pyflutter/converter/assets/forms_config.json")
|
|
7
|
+
|
|
8
|
+
data: JsonData = JsonConvert.from_file(f).data
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main() -> None:
|
|
13
|
+
from converter import run_ui
|
|
14
|
+
run_ui()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
if __name__ == '__main__':
|
|
18
|
+
main()
|
|
@@ -273,7 +273,7 @@ class SnackBar:
|
|
|
273
273
|
_step(popup.winfo_y(), 0)
|
|
274
274
|
|
|
275
275
|
|
|
276
|
-
def create_theme_provider() -> ThemeProvider:
|
|
276
|
+
def create_theme_provider(mode: ThemeMode = ThemeMode.DARK) -> ThemeProvider:
|
|
277
277
|
|
|
278
278
|
return ThemeProvider(
|
|
279
279
|
light_theme=ThemeData.light(color_scheme=ColorScheme.light()),
|
|
@@ -211,6 +211,12 @@ class FilePickerController:
|
|
|
211
211
|
raw = [path] if path else []
|
|
212
212
|
|
|
213
213
|
result = FilePickerResult(files=[PlatformFile(p) for p in raw]) if raw else None
|
|
214
|
+
if raw is not None:
|
|
215
|
+
first = raw[0] if len(raw) > 0 else None
|
|
216
|
+
if first is not None:
|
|
217
|
+
self.initial_directory = os.path.dirname(first)
|
|
218
|
+
print(f'{__class__.__name__} [INITIAL_DIR] ... {self.initial_directory}')
|
|
219
|
+
|
|
214
220
|
self.result_notifier.value = result
|
|
215
221
|
return result
|
|
216
222
|
|
|
@@ -41,9 +41,9 @@ class ThemeMode(Enum):
|
|
|
41
41
|
Equivalente ao ThemeMode do Flutter.
|
|
42
42
|
SYSTEM detecta a preferência do sistema operacional.
|
|
43
43
|
"""
|
|
44
|
-
LIGHT =
|
|
45
|
-
DARK =
|
|
46
|
-
SYSTEM =
|
|
44
|
+
LIGHT = "light"
|
|
45
|
+
DARK = "dark"
|
|
46
|
+
SYSTEM = "system"
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
def _detect_system_dark_mode() -> bool:
|
pyflutter_app-0.1.4/claude.py
DELETED
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
counter_app.py — App de contador no estilo Flutter
|
|
3
|
-
Demonstra: ChangeNotifier, Consumer, Provider, StatelessWidget
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
import sys
|
|
7
|
-
import os
|
|
8
|
-
|
|
9
|
-
# Adiciona o diretório do pyflutter ao path (ajuste se necessário)
|
|
10
|
-
# sys.path.insert(0, "/caminho/para/pyflutter")
|
|
11
|
-
|
|
12
|
-
from pyflutter_ui.core import (
|
|
13
|
-
ChangeNotifier,
|
|
14
|
-
BuildContext,
|
|
15
|
-
FlutterWidget,
|
|
16
|
-
StatelessElement,
|
|
17
|
-
StatelessWidget,
|
|
18
|
-
Element,
|
|
19
|
-
Provider,
|
|
20
|
-
Consumer,
|
|
21
|
-
inflate_widget,
|
|
22
|
-
)
|
|
23
|
-
from pyflutter_ui.widgets import (
|
|
24
|
-
TkMaterialApp,
|
|
25
|
-
Scaffold,
|
|
26
|
-
AppBar,
|
|
27
|
-
Text,
|
|
28
|
-
Column,
|
|
29
|
-
Row,
|
|
30
|
-
Center,
|
|
31
|
-
Padding,
|
|
32
|
-
SizedBox,
|
|
33
|
-
MainAxisAlignment,
|
|
34
|
-
CrossAxisAlignment,
|
|
35
|
-
ElevatedButton,
|
|
36
|
-
FloatingActionButton,
|
|
37
|
-
Expanded,
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
# ============================================================
|
|
42
|
-
# MODEL — CounterModel (ChangeNotifier)
|
|
43
|
-
# ============================================================
|
|
44
|
-
|
|
45
|
-
class CounterModel(ChangeNotifier):
|
|
46
|
-
"""
|
|
47
|
-
Estado global do contador.
|
|
48
|
-
Qualquer Consumer que observe este model
|
|
49
|
-
será reconstruído ao chamar notify_listeners().
|
|
50
|
-
"""
|
|
51
|
-
|
|
52
|
-
def __init__(self) -> None:
|
|
53
|
-
super().__init__()
|
|
54
|
-
self._count: int = 0
|
|
55
|
-
|
|
56
|
-
@property
|
|
57
|
-
def count(self) -> int:
|
|
58
|
-
return self._count
|
|
59
|
-
|
|
60
|
-
def increment(self) -> None:
|
|
61
|
-
self._count += 1
|
|
62
|
-
self.notify_listeners()
|
|
63
|
-
|
|
64
|
-
def decrement(self) -> None:
|
|
65
|
-
if self._count > 0:
|
|
66
|
-
self._count -= 1
|
|
67
|
-
self.notify_listeners()
|
|
68
|
-
|
|
69
|
-
def reset(self) -> None:
|
|
70
|
-
self._count = 0
|
|
71
|
-
self.notify_listeners()
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
# ============================================================
|
|
75
|
-
# WIDGETS DA UI
|
|
76
|
-
# ============================================================
|
|
77
|
-
|
|
78
|
-
class CounterDisplay(StatelessWidget):
|
|
79
|
-
"""
|
|
80
|
-
Exibe o valor atual do contador.
|
|
81
|
-
Reconstruído automaticamente via Consumer.
|
|
82
|
-
"""
|
|
83
|
-
|
|
84
|
-
def __init__(self, count: int) -> None:
|
|
85
|
-
super().__init__()
|
|
86
|
-
self.count = count
|
|
87
|
-
|
|
88
|
-
def build(self, context: BuildContext) -> FlutterWidget:
|
|
89
|
-
return Column(
|
|
90
|
-
children=[
|
|
91
|
-
Text("Você pressionou o botão"),
|
|
92
|
-
Text("esta quantidade de vezes:"),
|
|
93
|
-
SizedBox(height=12),
|
|
94
|
-
Text(str(self.count)),
|
|
95
|
-
],
|
|
96
|
-
main_axis_alignment=MainAxisAlignment.CENTER,
|
|
97
|
-
cross_axis_alignment=CrossAxisAlignment.CENTER,
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
def create_element(self) -> Element:
|
|
101
|
-
return self.build(None).create_element()
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
class CounterButtons(StatelessWidget):
|
|
105
|
-
"""
|
|
106
|
-
Linha de botões: decrementar, resetar, incrementar.
|
|
107
|
-
Acessa o CounterModel via context.read().
|
|
108
|
-
"""
|
|
109
|
-
|
|
110
|
-
def __init__(self, key: str | None = None) -> None:
|
|
111
|
-
super().__init__(key)
|
|
112
|
-
|
|
113
|
-
def build(self, context: BuildContext) -> FlutterWidget:
|
|
114
|
-
model: CounterModel = context.read(CounterModel)
|
|
115
|
-
|
|
116
|
-
return Row(
|
|
117
|
-
children=[
|
|
118
|
-
ElevatedButton(
|
|
119
|
-
text="-",
|
|
120
|
-
on_pressed=model.decrement,
|
|
121
|
-
),
|
|
122
|
-
SizedBox(width=12),
|
|
123
|
-
ElevatedButton(
|
|
124
|
-
text="Reset",
|
|
125
|
-
on_pressed=model.reset,
|
|
126
|
-
),
|
|
127
|
-
SizedBox(width=12),
|
|
128
|
-
ElevatedButton(
|
|
129
|
-
text="+",
|
|
130
|
-
on_pressed=model.increment,
|
|
131
|
-
),
|
|
132
|
-
],
|
|
133
|
-
main_axis_alignment=MainAxisAlignment.CENTER,
|
|
134
|
-
cross_axis_alignment=CrossAxisAlignment.CENTER,
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
class CounterPage(StatelessWidget):
|
|
140
|
-
"""
|
|
141
|
-
Página principal — monta a estrutura do Scaffold
|
|
142
|
-
e injeta o Consumer que observa o CounterModel.
|
|
143
|
-
"""
|
|
144
|
-
|
|
145
|
-
def __init__(self, key: str | None = None) -> None:
|
|
146
|
-
super().__init__(key)
|
|
147
|
-
|
|
148
|
-
def build(self, context: BuildContext) -> FlutterWidget:
|
|
149
|
-
|
|
150
|
-
counter_consumer = Consumer(
|
|
151
|
-
provider_type=CounterModel,
|
|
152
|
-
builder=lambda ctx, model: Column(
|
|
153
|
-
children=[
|
|
154
|
-
Expanded(
|
|
155
|
-
child=Center(
|
|
156
|
-
child=Padding(
|
|
157
|
-
padding=16,
|
|
158
|
-
child=CounterDisplay(count=model.count),
|
|
159
|
-
)
|
|
160
|
-
)
|
|
161
|
-
),
|
|
162
|
-
Padding(
|
|
163
|
-
padding=16,
|
|
164
|
-
child=CounterButtons(),
|
|
165
|
-
),
|
|
166
|
-
SizedBox(height=8),
|
|
167
|
-
],
|
|
168
|
-
main_axis_alignment=MainAxisAlignment.START,
|
|
169
|
-
cross_axis_alignment=CrossAxisAlignment.CENTER,
|
|
170
|
-
),
|
|
171
|
-
)
|
|
172
|
-
|
|
173
|
-
return Scaffold(
|
|
174
|
-
app_bar=AppBar(title="Flutter Counter — pyflutter"),
|
|
175
|
-
body=counter_consumer,
|
|
176
|
-
floating_action_button=FloatingActionButton(
|
|
177
|
-
text="+",
|
|
178
|
-
on_pressed=lambda: context.read(CounterModel).increment(),
|
|
179
|
-
),
|
|
180
|
-
)
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
# ============================================================
|
|
185
|
-
# ENTRY POINT
|
|
186
|
-
# ============================================================
|
|
187
|
-
|
|
188
|
-
def main() -> None:
|
|
189
|
-
app = TkMaterialApp(
|
|
190
|
-
home=CounterPage(),
|
|
191
|
-
title="Flutter Counter — pyflutter",
|
|
192
|
-
)
|
|
193
|
-
|
|
194
|
-
# Registra o CounterModel como provider global
|
|
195
|
-
app.register_notifier(CounterModel())
|
|
196
|
-
|
|
197
|
-
app.run()
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
if __name__ == "__main__":
|
|
201
|
-
main()
|
|
202
|
-
|
pyflutter_app-0.1.4/main.py
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
from pyflutter_ui import (
|
|
2
|
-
Provider, TkMaterialApp, run_app
|
|
3
|
-
)
|
|
4
|
-
from converter.excel.view import HomePage
|
|
5
|
-
from converter.excel.controller import ControllerHomePage
|
|
6
|
-
from converter.excel.model import ExcelModel
|
|
7
|
-
|
|
8
|
-
from converter.page_forms import ControllerForms
|
|
9
|
-
from converter.page_forms.model_forms import ModelForms
|
|
10
|
-
import pandas as pd
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def main() -> None:
|
|
14
|
-
model = ExcelModel()
|
|
15
|
-
model_forms = ModelForms()
|
|
16
|
-
|
|
17
|
-
controller_excel = ControllerHomePage(model)
|
|
18
|
-
controller_forms = ControllerForms(model_forms)
|
|
19
|
-
|
|
20
|
-
app = TkMaterialApp(home=HomePage())
|
|
21
|
-
#app.register_notifier(controller)
|
|
22
|
-
Provider.add_state(controller_excel)
|
|
23
|
-
Provider.add_state(controller_excel.data_columns)
|
|
24
|
-
Provider.add_state(controller_forms)
|
|
25
|
-
|
|
26
|
-
app.set_width(760)
|
|
27
|
-
app.set_height(480)
|
|
28
|
-
run_app(app)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if __name__ == '__main__':
|
|
32
|
-
main()
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
from pyflutter_ui.core import (
|
|
2
|
-
ChangeNotifier, BuildContext, FlutterWidget,
|
|
3
|
-
StatelessWidget, Consumer,
|
|
4
|
-
)
|
|
5
|
-
from pyflutter_ui.widgets import (
|
|
6
|
-
TkMaterialApp, Scaffold, AppBar, Text, Column, Row,
|
|
7
|
-
Center, Padding, SizedBox, ElevatedButton, FloatingActionButton,
|
|
8
|
-
Expanded, Divider, MainAxisAlignment, CrossAxisAlignment, TableView
|
|
9
|
-
)
|
|
10
|
-
from pyflutter_ui.theme import (
|
|
11
|
-
Theme, ThemeData, ThemeMode, ThemeProvider,
|
|
12
|
-
ColorScheme, make_themed_app,
|
|
13
|
-
)
|
|
14
|
-
from pyflutter_ui.app import run_app
|
|
15
|
-
|
|
16
|
-
import pandas as pd
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
# =============================================================================
|
|
20
|
-
# MODEL
|
|
21
|
-
# Responsável pelos dados e regras de negócio.
|
|
22
|
-
# Não conhece a View nem o Controller.
|
|
23
|
-
# =============================================================================
|
|
24
|
-
|
|
25
|
-
class ContadorModel(ChangeNotifier):
|
|
26
|
-
|
|
27
|
-
def __init__(self) -> None:
|
|
28
|
-
super().__init__()
|
|
29
|
-
self._count: int = 0
|
|
30
|
-
self._data: pd.DataFrame = self._load_data()
|
|
31
|
-
|
|
32
|
-
def _load_data(self) -> pd.DataFrame:
|
|
33
|
-
f = (
|
|
34
|
-
'/home/brunoc/Documentos/Analitico Ref Dez 2025 '
|
|
35
|
-
'(Formatado Mapas)/Analitico Ref Dez 2025/'
|
|
36
|
-
'Analitico Livros/EXCEL/11.xlsx'
|
|
37
|
-
)
|
|
38
|
-
return pd.read_excel(f)
|
|
39
|
-
|
|
40
|
-
# --- Getters (interface de leitura para o Controller) ---
|
|
41
|
-
|
|
42
|
-
@property
|
|
43
|
-
def count(self) -> int:
|
|
44
|
-
return self._count
|
|
45
|
-
|
|
46
|
-
@property
|
|
47
|
-
def data(self) -> pd.DataFrame:
|
|
48
|
-
return self._data
|
|
49
|
-
|
|
50
|
-
# --- Mutações (chamadas pelo Controller) ---
|
|
51
|
-
|
|
52
|
-
def increment(self) -> None:
|
|
53
|
-
self._count += 1
|
|
54
|
-
self.notify_listeners()
|
|
55
|
-
|
|
56
|
-
def reset(self) -> None:
|
|
57
|
-
self._count = 0
|
|
58
|
-
self.notify_listeners()
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
# =============================================================================
|
|
62
|
-
# CONTROLLER
|
|
63
|
-
# Intermediário entre Model e View.
|
|
64
|
-
# Recebe ações da View, delega ao Model e expõe dados prontos para exibição.
|
|
65
|
-
# O Controller é também o ChangeNotifier registrado no app, pois é ele que
|
|
66
|
-
# a View observa via Consumer.
|
|
67
|
-
# =============================================================================
|
|
68
|
-
|
|
69
|
-
class ContadorController(ChangeNotifier):
|
|
70
|
-
|
|
71
|
-
def __init__(self, model: ContadorModel) -> None:
|
|
72
|
-
super().__init__()
|
|
73
|
-
self._model = model
|
|
74
|
-
# Repassa as notificações do Model para os listeners do Controller.
|
|
75
|
-
self._model.add_listener(self._on_model_changed)
|
|
76
|
-
|
|
77
|
-
def _on_model_changed(self) -> None:
|
|
78
|
-
self.notify_listeners()
|
|
79
|
-
|
|
80
|
-
# --- Ações expostas para a View ---
|
|
81
|
-
|
|
82
|
-
def increment(self) -> None:
|
|
83
|
-
self._model.increment()
|
|
84
|
-
|
|
85
|
-
def reset(self) -> None:
|
|
86
|
-
self._model.reset()
|
|
87
|
-
|
|
88
|
-
# --- Dados formatados para a View ---
|
|
89
|
-
|
|
90
|
-
@property
|
|
91
|
-
def count_label(self) -> str:
|
|
92
|
-
return f'Você clicou: {self._model.count} vezes.'
|
|
93
|
-
|
|
94
|
-
@property
|
|
95
|
-
def table_columns(self) -> list:
|
|
96
|
-
return self._model.data.columns.tolist()
|
|
97
|
-
|
|
98
|
-
@property
|
|
99
|
-
def table_rows(self) -> list:
|
|
100
|
-
return self._model.data.values.tolist()
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
# =============================================================================
|
|
104
|
-
# VIEW
|
|
105
|
-
# Responsável apenas pela apresentação.
|
|
106
|
-
# Conhece o Controller, mas não o Model.
|
|
107
|
-
# =============================================================================
|
|
108
|
-
|
|
109
|
-
class Home(StatelessWidget):
|
|
110
|
-
|
|
111
|
-
def __init__(self, key: str | None = None) -> None:
|
|
112
|
-
super().__init__(key)
|
|
113
|
-
|
|
114
|
-
def _build_body(
|
|
115
|
-
self, context: BuildContext, controller: ContadorController
|
|
116
|
-
) -> FlutterWidget:
|
|
117
|
-
return Column(
|
|
118
|
-
[
|
|
119
|
-
Text(controller.count_label),
|
|
120
|
-
Divider(),
|
|
121
|
-
ElevatedButton('Limpar', on_pressed=controller.reset),
|
|
122
|
-
Row(
|
|
123
|
-
children=[
|
|
124
|
-
TableView(
|
|
125
|
-
columns=controller.table_columns,
|
|
126
|
-
rows=controller.table_rows,
|
|
127
|
-
),
|
|
128
|
-
],
|
|
129
|
-
),
|
|
130
|
-
],
|
|
131
|
-
main_axis_alignment=MainAxisAlignment.START,
|
|
132
|
-
)
|
|
133
|
-
|
|
134
|
-
def build(self, context: BuildContext) -> FlutterWidget:
|
|
135
|
-
controller = context.read(ContadorController)
|
|
136
|
-
|
|
137
|
-
return Scaffold(
|
|
138
|
-
Consumer(
|
|
139
|
-
ContadorController,
|
|
140
|
-
builder=self._build_body,
|
|
141
|
-
),
|
|
142
|
-
app_bar=AppBar("AppBar"),
|
|
143
|
-
floating_action_button=FloatingActionButton(
|
|
144
|
-
"+", on_pressed=controller.increment
|
|
145
|
-
),
|
|
146
|
-
)
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
# =============================================================================
|
|
150
|
-
# ENTRY POINT
|
|
151
|
-
# =============================================================================
|
|
152
|
-
|
|
153
|
-
def main() -> None:
|
|
154
|
-
model = ContadorModel()
|
|
155
|
-
controller = ContadorController(model)
|
|
156
|
-
|
|
157
|
-
app = TkMaterialApp(home=Home())
|
|
158
|
-
app.register_notifier(controller)
|
|
159
|
-
run_app(app)
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|