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.
Files changed (63) hide show
  1. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/PKG-INFO +1 -1
  2. pyflutter_app-0.1.6/converter/config_app.py +114 -0
  3. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/excel/controller.py +1 -0
  4. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/excel/view.py +9 -0
  5. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/page_forms/config.py +71 -1
  6. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/page_forms/controller_forms.py +18 -10
  7. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/run.py +7 -2
  8. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/local_build/linux.sh +1 -1
  9. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/local_build/send.sh +2 -2
  10. pyflutter_app-0.1.6/main.py +18 -0
  11. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/pyflutter_ui/app.py +1 -1
  12. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/pyflutter_ui/file_picker.py +6 -0
  13. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/pyflutter_ui/theme.py +3 -3
  14. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/pyflutter_ui/widgets.py +1 -1
  15. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/pyproject.toml +1 -1
  16. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/uv.lock +1 -1
  17. pyflutter_app-0.1.4/claude.py +0 -202
  18. pyflutter_app-0.1.4/main.py +0 -32
  19. pyflutter_app-0.1.4/theme_demo.py +0 -162
  20. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/.gitignore +0 -0
  21. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/.idea/.gitignore +0 -0
  22. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/.idea/inspectionProfiles/Project_Default.xml +0 -0
  23. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
  24. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/.idea/misc.xml +0 -0
  25. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/.idea/modules.xml +0 -0
  26. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/.idea/pyflutter.iml +0 -0
  27. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/.idea/vcs.xml +0 -0
  28. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/README.md +0 -0
  29. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/__init__.py +0 -0
  30. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/__main__.py +0 -0
  31. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/assets/forms_config.json +0 -0
  32. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/excel/__init__.py +0 -0
  33. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/excel/_page_edit.py +0 -0
  34. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/excel/model.py +0 -0
  35. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/lib_toi.py +0 -0
  36. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/page_forms/__init__.py +0 -0
  37. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/page_forms/common.py +0 -0
  38. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/page_forms/model_forms.py +0 -0
  39. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/page_forms/service.py +0 -0
  40. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/table_widget.py +0 -0
  41. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/whatsapp/__init__.py +0 -0
  42. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/converter/whatsapp/model.py +0 -0
  43. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/export_app.sh +0 -0
  44. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/pyflutter_ui/__init__.py +0 -0
  45. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/pyflutter_ui/core.py +0 -0
  46. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/pyflutter_ui/navigator.py +0 -0
  47. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/__init__.py +0 -0
  48. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/erros.py +0 -0
  49. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/hash_map.py +0 -0
  50. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/notifier.py +0 -0
  51. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/pattner/__init__.py +0 -0
  52. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/pattner/adapter.py +0 -0
  53. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/pattner/observer.py +0 -0
  54. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/sheet/__init__.py +0 -0
  55. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/sheet/check_mod.py +0 -0
  56. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/sheet/load.py +0 -0
  57. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/sheet/options.py +0 -0
  58. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/sheet/parse.py +0 -0
  59. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/sheet/save.py +0 -0
  60. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/state.py +0 -0
  61. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/sysfiles.py +0 -0
  62. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/thread.py +0 -0
  63. {pyflutter_app-0.1.4 → pyflutter_app-0.1.6}/table_stream/workbook.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pyflutter_app
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Summary: Bibliotecas Python para conversão de documentos, interface e processamento de tabelas.
5
5
  Requires-Python: >=3.14
6
6
  Requires-Dist: openpyxl>=3.1.5
@@ -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 = File("/home/bruno/GIT/pyflutter/converter/assets/forms_config.json")
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.work_dir: Directory = UserFileSystem().get_user_downloads().concat('RFA', True)
138
+ self.app_config: AppConfigNotifier = Provider.read(AppConfigNotifier)
139
+
132
140
  self.value_notifier_docs: ValueNotifierDocuments = ValueNotifierDocuments(
133
- self.work_dir.concat('CARTAS-TOI-NOMEADAS', True),
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.work_dir = d
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
- model = ExcelModel()
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(model)
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 = auto()
45
- DARK = auto()
46
- SYSTEM = auto()
44
+ LIGHT = "light"
45
+ DARK = "dark"
46
+ SYSTEM = "system"
47
47
 
48
48
 
49
49
  def _detect_system_dark_mode() -> bool:
@@ -18,7 +18,7 @@ class TkMaterialApp(BaseMaterialApp):
18
18
  def __init__(
19
19
  self,
20
20
  home: FlutterWidget, *,
21
- title: str = "Conversor",
21
+ title: str = "MyApp",
22
22
  theme: Any = None,
23
23
  height: int = 350,
24
24
  width: int = 480,
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pyflutter_app"
3
- version = "0.1.4"
3
+ version = "0.1.6"
4
4
  description = "Bibliotecas Python para conversão de documentos, interface e processamento de tabelas."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.14"
@@ -454,7 +454,7 @@ wheels = [
454
454
 
455
455
  [[package]]
456
456
  name = "pyflutter-app"
457
- version = "0.1.4"
457
+ version = "0.1.6"
458
458
  source = { editable = "." }
459
459
  dependencies = [
460
460
  { name = "openpyxl" },
@@ -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
-
@@ -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