├── .github └── workflows │ └── python-publish.yml ├── .gitignore ├── LICENSE ├── MANIFEST.in ├── README.md ├── __init__.py ├── assets ├── IMG_3260.PNG └── README.md ├── docs └── get_bard_token.md ├── fletsb ├── __init__.py ├── __main__.py ├── edit.py ├── engines │ ├── __init__.py │ ├── bardai_engine.py │ ├── edit_subwidgets_engine.py │ ├── edit_widget_engine.py │ ├── suggesting_engine.py │ └── viewer_engine.py ├── load_storyboard.py ├── pages │ ├── Settings │ │ ├── __init__.py │ │ └── pages.py │ ├── __init__.py │ ├── create_new_file.py │ ├── main_page.py │ └── settings.py ├── sections │ ├── __init__.py │ ├── edit_section.py │ ├── left_section.py │ └── preview_section.py ├── tools │ ├── __init__.py │ ├── color_picker.py │ ├── create_storyboard.py │ ├── get_url_icon.py │ ├── list_picker.py │ ├── page_info.py │ └── storyboard_class.py ├── ui_toolkit │ ├── __init__.py │ └── widget_browser_frame.py └── widgets │ ├── All.py │ ├── __init__.py │ └── widgets │ ├── __init__.py │ ├── button.py │ ├── column.py │ ├── image.py │ ├── label.py │ ├── markdown.py │ ├── navigator.py │ ├── open_url.py │ ├── padding.py │ ├── paragraph.py │ ├── row.py │ ├── textfield.py │ └── title.py ├── pyproject.toml ├── rules ├── about_me.json ├── all.json └── signin_rules.json └── setup.py /.github/workflows/python-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will upload a Python Package using Twine when a release is created 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries 3 | 4 | # This workflow uses actions that are not certified by GitHub. 5 | # They are provided by a third-party and are governed by 6 | # separate terms of service, privacy policy, and support 7 | # documentation. 8 | 9 | name: Upload Python Package 10 | 11 | on: 12 | release: 13 | types: [published] 14 | 15 | permissions: 16 | contents: read 17 | 18 | jobs: 19 | deploy: 20 | 21 | runs-on: ubuntu-latest 22 | 23 | steps: 24 | - uses: actions/checkout@v3 25 | - name: Set up Python 26 | uses: actions/setup-python@v3 27 | with: 28 | python-version: '3.x' 29 | - name: Install dependencies 30 | run: | 31 | python -m pip install --upgrade pip 32 | pip install build 33 | - name: Build package 34 | run: python -m build 35 | - name: Publish package 36 | uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 37 | with: 38 | user: __token__ 39 | password: ${{ secrets.PYPI_API_TOKEN }} 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Yousef Aladwani 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include fletsb/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flet StoryBoard 2 | Flet StoryBoard is a python library that have an easy to use tools for building graphical interfaces based on python `flet` library. Powerful interfaces with simple usability. Build the UI with ease of `fletsb`, then connect it with your back-end! 3 | 4 | ## Goal 🏁 5 | My goal is to allow programmers to focus on the back-end, and build the front-end using just a simple easy-to-use window without any front-end coding require. 6 | 7 | ## installation ⬇️ 8 | - Python > 3.7 9 | 10 | You can try Flet_StoryBoard on web!, just click here: [fletsb on web](https://skbarbon.github.io/wfletsb/) 11 | 12 | For install: 13 | > `pip install Flet_StoryBoard` 14 | 15 | for Upgrade: 16 | > `pip install Flet_StoryBoard --upgrade` 17 | 18 | ## Little Peek 19 | 20 | Screenshot 2023-04-26 at 12 17 33 PM 21 | 22 | ## What's new on `Flet_StoryBoard` `1.0` 🎉 23 | - ReSupport custom widgets with flet. 24 | - Multiple pages support. 25 | - New Suggestions 26 | - New way to load the StoryBoard on your app. 27 | - The ability to add external `flet` controls inside the StoryBoard. 28 | - New Feature called `Smart suggestions`. It gets your goal then suggest things based on it. 29 | - Support templates. A template is a file contain pre-set props for all StoryBoard's widgets, like fonts and default text color. - soon - 30 | - ReBuild the architecture of the library. 31 | * Please read the docs to know more about library usage. [docs page](https://github.com/SKbarbon/Flet_StoryBoard/wiki) 32 | * if there is any another issues not fixed yet, please create an issue here: [issues page](https://github.com/SKbarbon/Flet_StoryBoard/issues) 33 | 34 | 35 | ## usage & examples 🤝 36 | You can use the editor just from the web!, click here to start: 37 | [fletsb on web](https://skbarbon.github.io/wfletsb) 38 | 39 | There is a very simple docs here about library usage. 40 | [docs page](https://github.com/SKbarbon/Flet_StoryBoard/wiki) 41 | 42 | ### create/edit your own StoryBoard 43 | ```cmd 44 | python3 -m fletsb.edit myUI.fletsb 45 | ``` 46 | It will edit the existing one or create a new one if not. 47 | 48 | ### load a StoryBoard 49 | To load your StoryBoard on your app, you can do this example code: 50 | 51 | ```python 52 | from fletsb import LoadStoryBoard, StoryBoard 53 | 54 | def main (storyBoard:StoryBoard): 55 | pass 56 | 57 | LoadStoryBoard(target_function=main, storyboard_file_path="myUI.fletsb") 58 | ``` 59 | 60 | To know more about the `StoryBoard` class, follow the [docs page](https://github.com/SKbarbon/Flet_StoryBoard/wiki) . -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SKbarbon/Flet_StoryBoard/85fbe95030d7def96f59b0ad37ea32f324f2af87/__init__.py -------------------------------------------------------------------------------- /assets/IMG_3260.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SKbarbon/Flet_StoryBoard/85fbe95030d7def96f59b0ad37ea32f324f2af87/assets/IMG_3260.PNG -------------------------------------------------------------------------------- /assets/README.md: -------------------------------------------------------------------------------- 1 | assets dir 2 | -------------------------------------------------------------------------------- /docs/get_bard_token.md: -------------------------------------------------------------------------------- 1 | # How to get bard API token ? 2 | To get your bard API token, open google bard page: (Google bard)[https://bard.google.com/], then open the inspector. 3 | 4 | Screenshot 2023-05-28 at 7 37 35 PM 5 | 6 | Then open the "Application" page, then find the `https://bard.google.com` section that under the cookies. Then search for `__Secure-1PSID` then copy its value. 7 | 8 | Screenshot 2023-05-28 at 7 38 03 PM 9 | 10 | ## Dont share it with any one! 11 | -------------------------------------------------------------------------------- /fletsb/__init__.py: -------------------------------------------------------------------------------- 1 | from .load_storyboard import LoadStoryBoard 2 | from .tools.storyboard_class import StoryBoard -------------------------------------------------------------------------------- /fletsb/__main__.py: -------------------------------------------------------------------------------- 1 | print(""" 2 | These are all 'Flet_StoryBoard' commands: 3 | 4 | .edit: For create/edit an exist storyboard => python3 -m Flet_StoryBoard.edit 5 | 6 | """) -------------------------------------------------------------------------------- /fletsb/edit.py: -------------------------------------------------------------------------------- 1 | from .pages.create_new_file import CreateNewFile 2 | from .pages.main_page import mainPage 3 | import sys 4 | import os 5 | import flet 6 | 7 | cmd_args = sys.argv 8 | debug_mode = False 9 | if "--debug" in cmd_args: 10 | debug_mode = True 11 | 12 | 13 | class manage_edit: 14 | def __init__(self) -> None: 15 | self.cmd_args = sys.argv 16 | self.file_name = None 17 | flet.app(target=self.CNF) 18 | 19 | if self.file_name is None and debug_mode: 20 | print("Debug alert: Unexpected exit, no errors.") 21 | sys.exit("Exit.") 22 | return 23 | 24 | if self.file_name is None: 25 | sys.exit("Exit.") 26 | return 27 | 28 | if not str(self.file_name).endswith(".fletsb"): 29 | self.file_name = str(self.file_name) + ".fletsb" 30 | 31 | if debug_mode: 32 | print("Debug alert: About to run the editor.") 33 | 34 | mainPage(self.file_name) 35 | 36 | def CNF(self, page): 37 | CreateNewFile(page, manage_class=self) 38 | 39 | 40 | if len(cmd_args) == 1: 41 | # To create a new file. 42 | if debug_mode: 43 | print("Debug alert: About to show the 'CreateNewFile' window.") 44 | manage_edit() 45 | else: 46 | # To edit an existing File. 47 | full_path = "" 48 | for i in range(1, len(cmd_args)): 49 | if full_path == "": 50 | full_path = full_path + cmd_args[i] 51 | else: 52 | full_path = full_path + " " + cmd_args[i] 53 | 54 | full_path = full_path.replace(" --debug", "") 55 | full_path = full_path.replace("--debug", "") 56 | 57 | if os.path.isfile(full_path): 58 | if debug_mode: 59 | print("Debug alert: About to run the editor.") 60 | mainPage(full_path) 61 | else: 62 | print(f"Warning: File not found '{full_path}', so create a new one.") 63 | if debug_mode: 64 | print("Debug alert: About to show the 'CreateNewFile' window.") 65 | manage_edit() 66 | -------------------------------------------------------------------------------- /fletsb/engines/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SKbarbon/Flet_StoryBoard/85fbe95030d7def96f59b0ad37ea32f324f2af87/fletsb/engines/__init__.py -------------------------------------------------------------------------------- /fletsb/engines/bardai_engine.py: -------------------------------------------------------------------------------- 1 | """ 2 | The bardAPI integration. 3 | """ 4 | from bardapi import Bard 5 | import os, flet, random, time, json, requests 6 | 7 | 8 | new_widgets_template = """ 9 | You are an AI for UI builder in a software called `Flet_StoryBoard`. Users will ask you to make something on their storyboard. The storyboard is a actually a json file that contain a UI stuff. Note that all your responses must be as json syntax. If a user tell you anything that unrelated to your job, return a `ok=false` on json. You can add new widgets. If the user ask you to put a widget that is not defined down bellow, then you choose one of the available widgets bellow that are similar to it. 10 | Please make sure that you are making a good UI/UX practice with the widgets properties. For example if the title is on center alianment then make the paragraph alianment also in center. The page color is , so make sure that you are not using the same color of the page color for the text color so the user can see the text. 11 | 12 | The widgets are available are with their own properties: 13 | - Title: title, title_color, size, width, italic, bold, hide, expand, alignment, text_align. 14 | - Paragraph: text, text_color, size, width, italic, bold, hide, alignment, text_align. 15 | - Button: text, function_name, text_color, bgcolor, alignment, width, height, hide. 16 | - Markdown: content, width, height, alignment. 17 | - Open Url: text, url, text_color, bgcolor, alignment, width, height, border_radius, hide. 18 | - Image: src, width, height, border_radius, alignment. 19 | - TextField: text, label, hint_text, width, height, border_radius, bgcolor, color, alignment. 20 | 21 | Note: do NOT set the `widget_class_name` to a name that does not exists above. 22 | 23 | This is an example of how your json responses must look like: 24 | ```json 25 | { 26 | "all" : [ 27 | { 28 | "widget_class_name": "Title", 29 | "properties": { 30 | "title": "myTitle", 31 | "title_color": "white", 32 | "size": 23, 33 | "width": 350, 34 | "italic": false, 35 | "bold": true, 36 | "hide": false, 37 | "expand": false, 38 | "alignment": "center", 39 | "text_align": "left" 40 | } 41 | }, 42 | { 43 | "widget_class_name": "Title", 44 | "properties": { 45 | "title": "myTitle2", 46 | "title_color": "white", 47 | "size": 23, 48 | "width": 350, 49 | "italic": false, 50 | "bold": true, 51 | "hide": false, 52 | "expand": false, 53 | "alignment": "center", 54 | "text_align": "left" 55 | } 56 | } 57 | ] 58 | } 59 | ``` 60 | 61 | The user message is: 62 | ```user_message 63 | 64 | ``` 65 | 66 | Try not to put the user message on any widget except if he did ask for it. 67 | Please make sure that you are making a good UI/UX practice with the widgets properties. For example if the title is on center alianment then make the paragraph alianment also in center. The page color is , so make sure that you are not using the same color of the page color for the text color so the user can see the text. 68 | Use each widget for its correct job. For example if you want a link to open in the browser, use the `Open Url` widget. 69 | Dont set the `widget_class_name` on the json to a name that does not exists above, For example if the user ask for a text, there is no Text widget, so you must search for a similar supported widget like the `title`. 70 | Do not use any widget name except: Title, Button, Markdown, Open Url, Image or TextField. 71 | Put all the widgets as shown on the previous json example. 72 | """ 73 | 74 | class BardapiSupport: 75 | def __init__(self) -> None: 76 | self.bard_init() 77 | 78 | def push_ui (self, push_on_top_views_function, main_class): 79 | main_class.main_row.opacity = 0.2 80 | main_class.main_row.update() 81 | 82 | self.main_class = main_class 83 | container = flet.Container(on_click=self.close_the_input) 84 | self.container = container 85 | 86 | if self.get_bard_token() == None: 87 | bard_token = flet.TextField(hint_text="Put your bard Token..", 88 | bgcolor="white", color="black", on_submit=self.save_the_token) 89 | container.content = flet.Column([ 90 | flet.Row([flet.Text("Your Bard Token")], alignment="center"), 91 | flet.Row([bard_token], alignment="center"), 92 | flet.Row([flet.Container(flet.Text("How to get the API token? Its totally free!", color="blue"), on_click=self.how_to_get_bard_token_page)], alignment="center") 93 | ], alignment="center") 94 | self.ress = push_on_top_views_function(self.container) 95 | if bard_token.page != None: 96 | bard_token.focus() 97 | else: 98 | ai_message_input = flet.TextField( 99 | border_radius=18, 100 | hint_text="", 101 | bgcolor="white", 102 | on_submit=self.on_message_submit, 103 | color="black" 104 | ) 105 | 106 | container.content = flet.Column([ 107 | flet.Row([ai_message_input], alignment="center"), 108 | flet.Row([flet.Text("The Bard AI", color="white")], alignment="center") 109 | ], alignment="center") 110 | self.ress = push_on_top_views_function(self.container) 111 | 112 | if ai_message_input.page != None: 113 | ai_message_input.focus() 114 | 115 | texts = ["Image with random cat image..", "A title that contain a cat emoji..", "A simple sign in page.."] 116 | for i in str(random.choice(texts)): 117 | ai_message_input.hint_text = ai_message_input.hint_text + i 118 | ai_message_input.update() 119 | time.sleep(0.02) 120 | 121 | def on_message_submit (self, e): 122 | e.control.disabled = True 123 | e.control.update() 124 | 125 | try: result = self.ask_bard(e.control.value) 126 | except: 127 | print("Error with connecting with bard."); self.close_the_input(self.container); return 128 | 129 | try: 130 | result = self.load_the_respone_to_dict(result) 131 | except Exception as e: 132 | print(f"Error:\n{e}") 133 | self.close_the_input(self.container) 134 | return 135 | 136 | for new_widget in result['all']: 137 | wid = self.main_class.add_new_widget(new_widget["widget_class_name"]) 138 | wid.update(new_widget['properties']) 139 | self.main_class.preview_section.update_preview(self.main_class.current_page_name) 140 | self.main_class.edit_a_widget(len(self.main_class.dict_content["pages"][self.main_class.current_page_name]["widgets"]) - 1) 141 | self.main_class.page.update() 142 | 143 | self.close_the_input(self.container) 144 | 145 | def close_the_input (self, e): 146 | self.main_class.main_row.opacity = 1.0 147 | self.main_class.main_row.update() 148 | self.ress() 149 | 150 | def get_bard_token (self): 151 | if not os.path.isfile (".bardapi"): 152 | return None 153 | 154 | bardapi_token = open(".bardapi", encoding="utf-8").read() 155 | 156 | return bardapi_token 157 | 158 | def bard_init(self): 159 | token = self.get_bard_token() 160 | if token is None: 161 | return False 162 | 163 | os.environ['_BARD_API_KEY'] = str(token) 164 | 165 | session = requests.Session() 166 | self.session = session 167 | session.headers = { 168 | "Host": "bard.google.com", 169 | "X-Same-Domain": "1", 170 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36", 171 | "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8", 172 | "Origin": "https://bard.google.com", 173 | "Referer": "https://bard.google.com/", 174 | } 175 | session.cookies['__Secure-1PSID'] = os.environ.get("_BARD_API_KEY") 176 | self.bard = Bard(session=session, timeout=12) 177 | 178 | def ask_bard (self, message): 179 | self.container.content = flet.Column([flet.Row([ 180 | flet.Text("The AI is thinking 😃!", weight="bold", size=26, color="white") 181 | ], alignment="center")], alignment="center") 182 | self.container.update() 183 | 184 | token = self.get_bard_token() 185 | if token == None: 186 | return False 187 | 188 | os.environ['_BARD_API_KEY'] = f"{token}" 189 | message_new = new_widgets_template.replace("", message) 190 | message_new = str(message_new).replace("", str(self.main_class.page.bgcolor)) 191 | return str(self.bard.get_answer(message_new)['content']) 192 | 193 | def load_the_respone_to_dict (self, respone:str): 194 | full_string = "" 195 | found_it = False 196 | for i in str(respone).split("\n"): 197 | if found_it: 198 | if str(i).startswith("```"): 199 | break 200 | full_string = full_string + f"\n{i}" 201 | 202 | if str(i).startswith("```json"): 203 | found_it = True 204 | 205 | return json.loads(full_string) 206 | 207 | def how_to_get_bard_token_page (self, e): 208 | p : flet.Page = e.page 209 | p.launch_url("https://github.com/SKbarbon/Flet_StoryBoard/blob/main/docs/get_bard_token.md") 210 | self.close_the_input(e) 211 | 212 | def save_the_token (self, token): 213 | token = token.control.value 214 | open(".bardapi", "w+", encoding="utf-8").write(token) 215 | self.close_the_input(token) -------------------------------------------------------------------------------- /fletsb/engines/edit_subwidgets_engine.py: -------------------------------------------------------------------------------- 1 | import flet 2 | 3 | from ..widgets.All import all_widgets 4 | from ..tools.color_picker import ColorPicker 5 | from ..tools.list_picker import ListPopup 6 | 7 | 8 | # main_widget_mother_class: is the widgets mother like row or column. 9 | class EditSubWidgetsEngine: 10 | def __init__(self, main_class, main_widget_mother_class, section_view: flet.Column, widget_number) -> None: 11 | self.main_class = main_class 12 | self.main_widget_mother_class = main_widget_mother_class 13 | self.section_view = section_view 14 | self.widget_number = widget_number 15 | 16 | self.all_fields = {} 17 | 18 | self.show_edit_tools() 19 | 20 | def show_edit_tools(self): 21 | # Update the ViewerEngine. 22 | self.main_class.preview_section.update_preview(self.main_class.current_page_name) 23 | 24 | # start 25 | self.section_view.clean() 26 | content = self.main_widget_mother_class.template["widgets"] 27 | class_name = content[self.widget_number]["widget_class_name"] 28 | widget_content = content[self.widget_number] 29 | 30 | # widget not found 31 | if class_name not in all_widgets: 32 | self.section_view.controls.append( 33 | flet.Row( 34 | [ 35 | flet.Text( 36 | f"There is no supported\nwidget named '{class_name}'.", 37 | color=flet.colors.WHITE 38 | ) 39 | ] 40 | ) 41 | ) 42 | return 43 | 44 | the_class = all_widgets[class_name]["class"] 45 | the_class = the_class( 46 | self.main_class, 47 | self.main_widget_mother_class.preview_section, 48 | widget_number=self.widget_number 49 | ) 50 | default_args = the_class.args 51 | 52 | title = flet.Text(f"Edit {class_name}", size=25, weight=flet.FontWeight.BOLD, color=flet.colors.WHITE) 53 | self.section_view.controls.append(title) 54 | 55 | for t in widget_content["properties"]: 56 | prop_name = t 57 | prop_value = widget_content["properties"][t] 58 | if prop_name not in default_args: 59 | print("Error while load widget properties in edit engine.") 60 | self.section_view.clean() 61 | return 62 | prop_type = default_args[prop_name]["type"] 63 | 64 | # This statement below is for adding the fields for edit a widget. 65 | if isinstance(prop_type(), str): 66 | tf = flet.TextField(width=160, bgcolor=flet.colors.WHITE, color=flet.colors.BLACK, label=prop_name) 67 | tf.value = prop_value 68 | self.section_view.controls.append(flet.Row([tf], alignment=flet.MainAxisAlignment.CENTER)) 69 | self.all_fields[prop_name] = tf 70 | if "multi_line" in default_args[prop_name]: 71 | tf.multiline = True 72 | 73 | elif isinstance(prop_type(), int): 74 | slid = flet.Slider(min=0, max=500, divisions=500, label="{value}", width=160) 75 | slid.value = int(prop_value) 76 | self.section_view.controls.append( 77 | flet.Row( 78 | [flet.Text(f"{prop_name}:", color=flet.colors.WHITE, width=150)], 79 | alignment=flet.MainAxisAlignment.CENTER 80 | ) 81 | ) 82 | self.section_view.controls.append(flet.Row([slid], alignment=flet.MainAxisAlignment.CENTER)) 83 | self.all_fields[prop_name] = slid 84 | 85 | elif isinstance(prop_type(), bool): 86 | tog = flet.Switch() 87 | tog.value = prop_value 88 | self.section_view.controls.append( 89 | flet.Row([flet.Text(f"{prop_name}", color=flet.colors.WHITE, size=13), tog], 90 | alignment=flet.MainAxisAlignment.CENTER, spacing=25)) 91 | self.all_fields[prop_name] = tog 92 | 93 | elif type(prop_type()) == type(ColorPicker()): 94 | self.section_view.controls.append(flet.Text("")) 95 | colp = ColorPicker( 96 | self.section_view, 97 | selected_color=prop_value, 98 | add_it=False, 99 | title_name=prop_name, 100 | drop_width=120 101 | ) 102 | self.section_view.controls.append(flet.Row([colp.v], alignment=flet.MainAxisAlignment.CENTER)) 103 | self.all_fields[prop_name] = colp 104 | 105 | elif isinstance(prop_type(), list): 106 | dr = flet.Dropdown(width=160, label=prop_name) 107 | for i in default_args[prop_name]["options"]: 108 | dr.options.append(flet.dropdown.Option(f"{i}")) 109 | dr.value = prop_value 110 | self.section_view.controls.append(flet.Row([dr], alignment=flet.MainAxisAlignment.CENTER)) 111 | self.all_fields[prop_name] = dr 112 | 113 | elif type(prop_type()) == type(ListPopup()): 114 | lp = ListPopup(default_args[prop_name]["options"], self.main_class, prop_value, prop_name) 115 | self.section_view.controls.append(flet.Row([lp.self_ui], alignment=flet.MainAxisAlignment.CENTER)) 116 | self.all_fields[prop_name] = lp 117 | 118 | # This button below for widgets that support sub-widgets. 119 | if hasattr(the_class, "support_sub_widgets"): 120 | add_sub_widget_button = flet.TextButton("Add sub-widget", on_click=the_class.widgets_to_add_in) 121 | self.section_view.controls.append( 122 | flet.Row([add_sub_widget_button], alignment=flet.MainAxisAlignment.CENTER)) 123 | 124 | # This slider below is for rearranging the widget on the page. 125 | rearrange_slider = flet.Slider( 126 | min=0, 127 | max=len(content), 128 | value=self.widget_number, 129 | label="{value}", 130 | width=160, 131 | divisions=len(content) 132 | ) 133 | self.section_view.controls.append( 134 | flet.Row([flet.Text(f"reArrange:", color=flet.colors.WHITE, width=150)], 135 | alignment=flet.MainAxisAlignment.CENTER)) 136 | self.section_view.controls.append(flet.Row([rearrange_slider], alignment=flet.MainAxisAlignment.CENTER)) 137 | self.rearrange_slider = rearrange_slider 138 | 139 | self.section_view.controls.append(flet.Text("\n")) 140 | # Down bellow is for done_button and delete_btn. 141 | done_button = flet.ElevatedButton( 142 | "Done", 143 | bgcolor=flet.colors.WHITE, 144 | color=flet.colors.BLACK, 145 | width=150, 146 | height=40, 147 | on_click=self.done_edit 148 | ) 149 | self.section_view.controls.append(flet.Row([done_button], alignment=flet.MainAxisAlignment.CENTER)) 150 | 151 | delete_button = flet.TextButton( 152 | content=flet.Text( 153 | "delete", 154 | color=flet.colors.RED, 155 | size=13 156 | ), 157 | on_click=self.delete_widget 158 | ) 159 | self.section_view.controls.append(flet.Row([delete_button], alignment=flet.MainAxisAlignment.CENTER)) 160 | 161 | def done_edit(self, *args): 162 | new_widget_properties_dict = {} 163 | for P in self.all_fields: 164 | new_widget_properties_dict[P] = self.all_fields[P].value 165 | 166 | if int(self.widget_number) == int(self.rearrange_slider.value): 167 | # If the widget arrange is the same. 168 | self.main_widget_mother_class.template["widgets"][self.widget_number]["properties"].update( 169 | new_widget_properties_dict) 170 | else: 171 | # If the widget arrange is NOT the same. 172 | if int(self.rearrange_slider.value) >= int(len(self.main_widget_mother_class.template["widgets"])): 173 | self.main_widget_mother_class.template["widgets"][self.widget_number]["properties"].update( 174 | new_widget_properties_dict) 175 | copy_of_content = self.main_widget_mother_class.template["widgets"][self.widget_number] 176 | del self.main_widget_mother_class.template["widgets"][self.widget_number] 177 | 178 | self.main_widget_mother_class.template["widgets"].append(copy_of_content) 179 | 180 | self.widget_number = int(len(self.main_widget_mother_class.template["widgets"]) - 1) 181 | else: 182 | self.main_widget_mother_class.template["widgets"][self.widget_number]["properties"].update( 183 | new_widget_properties_dict) 184 | copy_of_content = self.main_widget_mother_class.template["widgets"][self.widget_number] 185 | 186 | self.main_widget_mother_class.template["widgets"][int(self.rearrange_slider.value)] = copy_of_content 187 | del self.main_widget_mother_class.template["widgets"][self.widget_number] 188 | 189 | self.widget_number = int(self.rearrange_slider.value) 190 | 191 | # Update the viewer engine to see the edit changes. 192 | self.main_widget_mother_class.update_preview() 193 | self.main_class.preview_section.update_preview(self.main_class.current_page_name) 194 | self.main_class.page.update() 195 | 196 | # Reopen the editor again 197 | EditSubWidgetsEngine( 198 | main_class=self.main_class, 199 | main_widget_mother_class=self.main_widget_mother_class, 200 | section_view=self.section_view, 201 | widget_number=self.widget_number 202 | ) 203 | self.main_class.page.update() 204 | 205 | def delete_widget(self, *args): 206 | del self.main_widget_mother_class.template["widgets"][self.widget_number] 207 | self.section_view.clean() 208 | 209 | # Update the ViewerEngine to see the edit changes. 210 | self.main_class.preview_section.update_preview(self.main_class.current_page_name) 211 | self.main_class.page.update() 212 | -------------------------------------------------------------------------------- /fletsb/engines/edit_widget_engine.py: -------------------------------------------------------------------------------- 1 | import flet 2 | 3 | from ..widgets.All import all_widgets 4 | from ..tools.color_picker import ColorPicker 5 | from ..tools.list_picker import ListPopup 6 | 7 | 8 | class EditWidgetsEngine: 9 | def __init__(self, main_class, section_view: flet.Column, widget_number) -> None: 10 | self.main_class = main_class 11 | self.section_view = section_view 12 | self.widget_number = widget_number 13 | 14 | self.current_page_name = self.main_class.current_page_name 15 | self.all_fields = {} 16 | 17 | self.show_edit_tools() 18 | 19 | def show_edit_tools(self): 20 | self.section_view.clean() 21 | content = self.main_class.dict_content 22 | class_name = content["pages"][self.current_page_name]["widgets"][self.widget_number]["widget_class_name"] 23 | widget_content = content["pages"][self.current_page_name]["widgets"][self.widget_number] 24 | 25 | if class_name not in all_widgets: 26 | # if widget not found. 27 | self.section_view.controls.append( 28 | flet.Row( 29 | [flet.Text(f"There is no supported\nwidget named '{class_name}'.", color=flet.colors.WHITE)] 30 | ) 31 | ) 32 | return 33 | 34 | the_class = all_widgets[class_name]["class"] 35 | the_class = the_class( 36 | self.main_class, 37 | self.main_class.preview_section.main_view, 38 | widget_number=self.widget_number 39 | ) 40 | default_args = the_class.args 41 | 42 | title = flet.Text(f"Edit {class_name}", size=25, weight=flet.FontWeight.BOLD, color=flet.colors.WHITE) 43 | self.section_view.controls.append(title) 44 | 45 | # ---Remove the not defualt arg----- 46 | props_updated = dict(widget_content["properties"]) 47 | for checker in widget_content["properties"]: 48 | if checker not in default_args: 49 | props_updated.pop(checker) 50 | widget_content["properties"] = dict(props_updated) 51 | # ---Remove the not defualt arg----- 52 | 53 | for t in widget_content["properties"]: 54 | prop_name = t 55 | prop_value = widget_content["properties"][t] 56 | if prop_name not in default_args: 57 | print("Error while load widget properties in edit engine.") 58 | self.section_view.clean() 59 | return 60 | prop_type = default_args[prop_name]["type"] 61 | 62 | # These statements below are for adding the fields for edit a widget. 63 | if isinstance(prop_type(), str): 64 | tf = flet.TextField(width=160, bgcolor=flet.colors.WHITE, color=flet.colors.BLACK, label=prop_name) 65 | tf.value = prop_value 66 | self.section_view.controls.append(flet.Row([tf], alignment=flet.MainAxisAlignment.CENTER)) 67 | self.all_fields[prop_name] = tf 68 | if "multi_line" in default_args[prop_name]: 69 | tf.multiline = True 70 | 71 | elif type(prop_type()) == type(int()): 72 | slid = flet.Slider(min=0, max=500, divisions=500, label="{value}", width=160) 73 | slid.value = int(prop_value) 74 | self.section_view.controls.append( 75 | flet.Row( 76 | [ 77 | flet.Text( 78 | f"{prop_name}:", 79 | color=flet.colors.WHITE, 80 | width=150 81 | ) 82 | ], alignment=flet.MainAxisAlignment.CENTER 83 | ) 84 | ) 85 | self.section_view.controls.append( 86 | flet.Row( 87 | [slid], 88 | alignment=flet.MainAxisAlignment.CENTER 89 | ) 90 | ) 91 | self.all_fields[prop_name] = slid 92 | 93 | elif type(prop_type()) == type(bool()): 94 | tog = flet.Switch() 95 | tog.value = prop_value 96 | self.section_view.controls.append( 97 | flet.Row([flet.Text(f"{prop_name}", color=flet.colors.WHITE, size=13), tog], 98 | alignment=flet.MainAxisAlignment.CENTER, spacing=25)) 99 | self.all_fields[prop_name] = tog 100 | 101 | elif type(prop_type()) == type(ColorPicker()): 102 | self.section_view.controls.append(flet.Text("")) 103 | colp = ColorPicker(self.section_view, selected_color=prop_value, add_it=False, title_name=prop_name, 104 | drop_width=120) 105 | self.section_view.controls.append(flet.Row([colp.v], alignment=flet.MainAxisAlignment.CENTER)) 106 | self.all_fields[prop_name] = colp 107 | 108 | elif isinstance(prop_type(), list): 109 | dr = flet.Dropdown(width=160, label=prop_name) 110 | for i in default_args[prop_name]["options"]: 111 | dr.options.append(flet.dropdown.Option(f"{i}")) 112 | dr.value = prop_value 113 | self.section_view.controls.append(flet.Row([dr], alignment=flet.MainAxisAlignment.CENTER)) 114 | self.all_fields[prop_name] = dr 115 | 116 | elif type(prop_type()) == type(ListPopup()): 117 | lp = ListPopup(default_args[prop_name]["options"], self.main_class, prop_value, prop_name) 118 | self.section_view.controls.append(flet.Row([lp.self_ui], alignment=flet.MainAxisAlignment.CENTER)) 119 | self.all_fields[prop_name] = lp 120 | 121 | # This button below for widgets that support sub-widgets. 122 | if hasattr(the_class, "support_sub_widgets"): 123 | add_sub_widget_button = flet.TextButton("Add sub-widget", on_click=the_class.widgets_to_add_in) 124 | self.section_view.controls.append( 125 | flet.Row( 126 | [add_sub_widget_button], 127 | alignment=flet.MainAxisAlignment.CENTER 128 | ) 129 | ) 130 | 131 | # This slider bellow is for rearrange the widget on the page. 132 | rearrange_slider = flet.Slider( 133 | min=0, 134 | max=len(content["pages"][self.current_page_name]["widgets"]), 135 | value=self.widget_number, 136 | label="{value}", 137 | width=160, 138 | divisions=len(content["pages"][self.current_page_name]["widgets"]) 139 | ) 140 | self.section_view.controls.append( 141 | flet.Row( 142 | [flet.Text(f"reArrange:", color=flet.colors.WHITE, width=150)], 143 | alignment=flet.MainAxisAlignment.CENTER 144 | ) 145 | ) 146 | self.section_view.controls.append(flet.Row([rearrange_slider], alignment=flet.MainAxisAlignment.CENTER)) 147 | self.rearrange_slider = rearrange_slider 148 | 149 | self.section_view.controls.append(flet.Text("\n")) 150 | # Down bellow is for done_button and delete_btn. 151 | done_button = flet.ElevatedButton( 152 | "Done", 153 | bgcolor=flet.colors.WHITE, 154 | color=flet.colors.BLACK, 155 | width=150, 156 | height=40, 157 | on_click=self.done_edit 158 | ) 159 | self.section_view.controls.append( 160 | flet.Row( 161 | [done_button], 162 | alignment=flet.MainAxisAlignment.CENTER 163 | ) 164 | ) 165 | 166 | delete_button = flet.TextButton( 167 | content=flet.Text("delete", color=flet.colors.RED, size=13), 168 | on_click=self.delete_widget 169 | ) 170 | self.section_view.controls.append( 171 | flet.Row( 172 | [delete_button], 173 | alignment=flet.MainAxisAlignment.CENTER 174 | ) 175 | ) 176 | 177 | def done_edit(self, *args): 178 | new_widget_properties_dict = {} 179 | for P in self.all_fields: 180 | new_widget_properties_dict[P] = self.all_fields[P].value 181 | 182 | if int(self.widget_number) == int(self.rearrange_slider.value): 183 | # If the widget arrange is the same. 184 | self.main_class.dict_content["pages"][self.current_page_name]["widgets"][self.widget_number][ 185 | "properties"].update(new_widget_properties_dict) 186 | else: 187 | # If the widget arrange is NOT the same. 188 | if int(self.rearrange_slider.value) >= int( 189 | len(self.main_class.dict_content["pages"][self.main_class.current_page_name]["widgets"])): 190 | self.main_class.dict_content["pages"][self.current_page_name]["widgets"][self.widget_number][ 191 | "properties"].update(new_widget_properties_dict) 192 | copy_of_content = self.main_class.dict_content["pages"][self.current_page_name]["widgets"][ 193 | self.widget_number] 194 | del self.main_class.dict_content["pages"][self.current_page_name]["widgets"][self.widget_number] 195 | 196 | self.main_class.dict_content["pages"][self.current_page_name]["widgets"].append(copy_of_content) 197 | 198 | self.widget_number = int( 199 | len(self.main_class.dict_content["pages"][self.current_page_name]["widgets"]) - 1) 200 | else: 201 | self.main_class.dict_content["pages"][self.current_page_name]["widgets"][self.widget_number][ 202 | "properties"].update(new_widget_properties_dict) 203 | copy_of_content = self.main_class.dict_content["pages"][self.current_page_name]["widgets"][ 204 | self.widget_number] 205 | 206 | self.main_class.dict_content["pages"][self.current_page_name]["widgets"][ 207 | int(self.rearrange_slider.value)] = copy_of_content 208 | del self.main_class.dict_content["pages"][self.current_page_name]["widgets"][self.widget_number] 209 | 210 | self.widget_number = int(self.rearrange_slider.value) 211 | 212 | # Update the viewer engine to see the edit changes. 213 | self.main_class.preview_section.update_preview(self.main_class.current_page_name) 214 | self.main_class.page.update() 215 | 216 | # ReOpen the editor again 217 | EditWidgetsEngine( 218 | main_class=self.main_class, 219 | section_view=self.section_view, 220 | widget_number=self.widget_number 221 | ) 222 | self.main_class.page.update() 223 | 224 | def delete_widget(self, *args): 225 | del self.main_class.dict_content["pages"][self.current_page_name]["widgets"][self.widget_number] 226 | self.section_view.clean() 227 | 228 | # Update the viewer engine to see the edit changes. 229 | self.main_class.preview_section.update_preview(self.main_class.current_page_name) 230 | self.main_class.page.update() 231 | -------------------------------------------------------------------------------- /fletsb/engines/suggesting_engine.py: -------------------------------------------------------------------------------- 1 | import json 2 | import flet 3 | import random 4 | import os 5 | import requests 6 | 7 | 8 | class SuggestingEngine: 9 | def __init__(self, main_class): 10 | self.main_class = main_class 11 | 12 | self.main_col = flet.Column( 13 | width=self.main_class.left_section.main_container.width, 14 | height=self.main_class.left_section.main_container.height, 15 | # issue: True is not a valid value for the scroll mode. Use flet.SCROLL_MODE 16 | scroll=True 17 | ) 18 | 19 | def push_new_suggestion(self): 20 | settings = self.main_class.dict_content["storyboard_settings"] 21 | applied = settings["storyboard_suggestions"] 22 | 23 | # if `storyboard suggestions` is off. 24 | if not applied: 25 | return 26 | 27 | suggestions_rules_name = self.main_class.dict_content["pages"][self.main_class.current_page_name]["settings"][ 28 | "suggestions_rules"] 29 | 30 | if suggestions_rules_name == "none": 31 | return 32 | 33 | # Get the rules file 34 | if not os.path.isdir("rules"): 35 | os.mkdir("rules") 36 | 37 | if not os.path.isfile(f"rules/{suggestions_rules_name}.json"): 38 | all_rules = requests.get("https://raw.githubusercontent.com/SKbarbon/Flet_StoryBoard/main/rules/all.json").text 39 | all_rules = json.loads(all_rules) 40 | 41 | if suggestions_rules_name not in all_rules["all_rules"]: 42 | return 43 | else: 44 | rf = requests.get(all_rules["all_rules"][suggestions_rules_name]).text 45 | open(f"rules/{suggestions_rules_name}.json", "w+", encoding="utf-8").write(rf) 46 | 47 | rules_file = json.loads(open(f"rules/{suggestions_rules_name}.json", encoding="utf-8").read()) 48 | 49 | # step1: Get current widgets. 50 | current_widgets = list(self.main_class.dict_content["pages"][self.main_class.current_page_name]["widgets"]) 51 | 52 | # step2: Count classes on widgets. 53 | classes_in_widgets = {} 54 | for c in current_widgets: 55 | if c["widget_class_name"] not in classes_in_widgets: 56 | classes_in_widgets[c["widget_class_name"]] = 1 57 | else: 58 | classes_in_widgets[c["widget_class_name"]] = classes_in_widgets[c["widget_class_name"]] + 1 59 | 60 | # step3: Search for the correct case on the rules file. 61 | for rule in rules_file["rules"]: 62 | if rule["case"] == classes_in_widgets: 63 | self.change_left_section_into_suggestion(rule["sugs"]) 64 | break 65 | 66 | def change_left_section_into_suggestion(self, suggestions): 67 | def go_back(e): 68 | if last_on_section == self.main_col: 69 | self.main_class.left_section.show_all_widgets() 70 | else: 71 | self.main_class.left_section.show_new_content(last_on_section) 72 | 73 | main_col = self.main_col 74 | main_col.controls.clear() 75 | 76 | back_btn = flet.TextButton("< Back", on_click=go_back) 77 | main_col.controls.append(back_btn) 78 | 79 | title = flet.Text("Suggestions ✨", weight=flet.FontWeight.BOLD, size=22, color=flet.colors.WHITE) 80 | main_col.controls.append(title) 81 | 82 | main_col.controls.append( 83 | flet.Row( 84 | [flet.Text("", color=flet.colors.WHITE, size=13)], 85 | alignment=flet.MainAxisAlignment.CENTER 86 | ) 87 | ) 88 | 89 | for sug in suggestions: 90 | sc = self.suggestion_card(sug, go_back) 91 | main_col.controls.append( 92 | flet.Row( 93 | [sc], 94 | alignment=flet.MainAxisAlignment.CENTER 95 | ) 96 | ) 97 | 98 | last_on_section = self.main_class.left_section.main_container 99 | self.main_class.left_section.show_new_content(self.main_col) 100 | 101 | def suggestion_card(self, suggestion_dict, go_back_function): 102 | def add_widget(e): 103 | go_back_function(e) 104 | w = self.main_class.add_new_widget(suggestion_dict["class"]) 105 | w.update(suggestion_dict["props"]) 106 | self.main_class.preview_section.update_preview(self.main_class.current_page_name) 107 | self.main_class.edit_a_widget(len(self.main_class.dict_content["pages"][self.main_class.current_page_name]["widgets"]) - 1) 108 | self.main_class.page.update() 109 | 110 | colors = [flet.colors.WHITE, "#F5DEE5", flet.colors.YELLOW] 111 | 112 | card_container = flet.Container( 113 | bgcolor=random.choice(colors), 114 | width=170, 115 | height=225, 116 | border_radius=13 117 | ) 118 | column = flet.Column() 119 | card_container.content = column 120 | 121 | class_name = suggestion_dict["class"] 122 | why_to_add = suggestion_dict["about"] 123 | 124 | title = flet.Text( 125 | value=f"\n {class_name}", 126 | size=23, 127 | weight=flet.FontWeight.BOLD, 128 | color=flet.colors.BLACK, 129 | width=card_container.width 130 | ) 131 | about = flet.Text( 132 | value=f"{why_to_add}", 133 | size=13, 134 | color=flet.colors.BLACK, 135 | width=card_container.width - 37, 136 | height=90 137 | ) 138 | apply_button = flet.Container( 139 | flet.Row( 140 | [flet.Text("Add", color="white")], 141 | alignment=flet.MainAxisAlignment.CENTER 142 | ), 143 | bgcolor=flet.colors.BLACK, 144 | width=card_container.width - 15, 145 | height=40, 146 | border_radius=13, 147 | on_click=add_widget 148 | ) 149 | 150 | column.controls.append(title) 151 | column.controls.append(flet.Row([about], alignment=flet.MainAxisAlignment.CENTER)) 152 | column.controls.append( 153 | flet.Row( 154 | [apply_button], 155 | alignment=flet.MainAxisAlignment.CENTER 156 | ) 157 | ) 158 | 159 | # issue: column is not updated: column.update() 160 | 161 | return card_container 162 | -------------------------------------------------------------------------------- /fletsb/engines/viewer_engine.py: -------------------------------------------------------------------------------- 1 | from flet import Page, Container 2 | import flet 3 | 4 | from ..widgets.All import all_widgets 5 | 6 | 7 | class viewerEngine: 8 | def __init__ (self, main_class, content_dict:dict, page_name, parent_view, widgets_parent_view, development=True): 9 | """ 10 | This is the engine of preview. 11 | parent_view -> is the Container in the develop case, and Page in the production case 12 | widgets_parent_view -> is the Column in the develop case, and Page in the production case 13 | """ 14 | self.main_class = main_class 15 | self.content = content_dict 16 | self.page_name = page_name 17 | self.parent_view = parent_view 18 | self.widgets_parent_view = widgets_parent_view 19 | self.development = development 20 | 21 | self.last_clicked = None # last widget clicked to edit. this is for make a border color around it to know its selected. 22 | 23 | self.update_page() 24 | self.push_views() 25 | 26 | def push_views (self): 27 | page_name : str = self.page_name 28 | content = self.content["pages"][page_name] 29 | sub_widgets = content["widgets"] 30 | 31 | self.widgets_parent_view.controls.clear() 32 | num = 0 33 | for widget in sub_widgets: 34 | if widget["widget_class_name"] in all_widgets: 35 | widget_class = all_widgets[widget["widget_class_name"]]["class"] 36 | widget_class = widget_class(self.main_class, self.widgets_parent_view, widget_number=num) 37 | if hasattr(widget_class, "support_sub_widgets"): 38 | widget_class.update(widget["properties"], widget["widgets"]) 39 | else: 40 | widget_class.update(widget["properties"]) 41 | if self.development: 42 | self.create_development_container(widget_class.return_widget(), num) 43 | else: 44 | self.widgets_parent_view.controls.append(widget_class.return_widget()) 45 | num = num + 1 46 | 47 | 48 | def update_page (self): 49 | p : flet.Container = self.parent_view 50 | page_settings = self.content["pages"][self.page_name]["settings"] 51 | bgcolor = page_settings["bgcolor"] 52 | p.bgcolor = bgcolor 53 | 54 | if "allow_scroll" in self.main_class.dict_content["storyboard_settings"]: 55 | self.widgets_parent_view.scroll = self.main_class.dict_content["storyboard_settings"]["allow_scroll"] 56 | 57 | def create_development_container (self, cls, widget_number): 58 | def on_click (cls): 59 | if self.last_clicked != None: 60 | self.last_clicked.border = None 61 | self.last_clicked = c 62 | self.last_clicked.border = flet.border.all(2, flet.colors.BLUE_100) 63 | #? This function will call the main_page edit. 64 | self.main_class.edit_a_widget(widget_number) 65 | 66 | c = flet.Container(cls, on_click=on_click, border_radius=8) 67 | self.widgets_parent_view.controls.append(c) 68 | return c -------------------------------------------------------------------------------- /fletsb/load_storyboard.py: -------------------------------------------------------------------------------- 1 | from .engines.viewer_engine import viewerEngine 2 | from .tools.storyboard_class import StoryBoard 3 | from .widgets.All import all_widgets 4 | import json 5 | import flet 6 | 7 | 8 | class LoadStoryBoard: 9 | def __init__(self, target_function, storyboard_file_path: str, view=flet.FLET_APP): 10 | # set up the important props 11 | self.current_page_name = "main" 12 | self.file_path = storyboard_file_path 13 | self.development_mode = False 14 | self.all_widgets = all_widgets 15 | self.dict_content = json.loads(open(self.file_path, encoding="utf-8").read()) 16 | self.target_function = target_function 17 | 18 | # copy of things 19 | self.viewerEngine = viewerEngine 20 | # Run the app. 21 | flet.app(target=self.run, view=view) 22 | 23 | def run(self, page: flet.Page): 24 | self.storyboard_class = StoryBoard(page=page, main_class=self) 25 | page.vertical_alignment = page.vertical_alignment = flet.MainAxisAlignment.CENTER 26 | self.page = page 27 | ve = viewerEngine(self, self.dict_content, self.current_page_name, page, page, self.development_mode) 28 | self.target_function(self.storyboard_class) 29 | page.update() -------------------------------------------------------------------------------- /fletsb/pages/Settings/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SKbarbon/Flet_StoryBoard/85fbe95030d7def96f59b0ad37ea32f324f2af87/fletsb/pages/Settings/__init__.py -------------------------------------------------------------------------------- /fletsb/pages/Settings/pages.py: -------------------------------------------------------------------------------- 1 | import flet 2 | 3 | from ...tools.color_picker import ColorPicker 4 | 5 | 6 | def page_settings_page(settings_class): 7 | def allow_scrolling(e): 8 | settings_class.main_class.dict_content["storyboard_settings"]["allow_scroll"] = e.control.value 9 | page: flet.Page = settings_class.page 10 | page.show_snack_bar( 11 | flet.SnackBar( 12 | flet.Text(f"Done! But this is not saved, you must go click 'Save' on the editor."), 13 | open=True 14 | ) 15 | ) 16 | settings_class.main_class.preview_section.update_preview() 17 | page.update() 18 | 19 | def on_change_bgcolor(color): 20 | settings_class.main_class.dict_content["pages"][current_page_name]["settings"]["bgcolor"] = color 21 | page: flet.Page = settings_class.page 22 | page.show_snack_bar( 23 | flet.SnackBar( 24 | flet.Text(f"Done! But this is not saved, you must go click 'Save' on the editor."), 25 | open=True 26 | ) 27 | ) 28 | settings_class.main_class.preview_section.update_preview() 29 | page.update() 30 | 31 | v = settings_class.page_viewing_section 32 | v.clean() 33 | 34 | current_page_name = settings_class.main_class.current_page_name 35 | title = flet.Text( 36 | f"\n Pages - {current_page_name}", 37 | color=flet.colors.WHITE, 38 | weight=flet.FontWeight.BOLD, 39 | size=28 40 | ) 41 | v.controls.append(title) 42 | 43 | if "allow_scroll" not in settings_class.main_class.dict_content["storyboard_settings"]: 44 | settings_class.main_class.dict_content["storyboard_settings"]["allow_scroll"] = False 45 | 46 | row_allow_scrolling = flet.Row( 47 | [ 48 | flet.Text("Allow scrolling", color="white", width=300), 49 | flet.Switch( 50 | on_change=allow_scrolling, 51 | value=settings_class.main_class.dict_content["storyboard_settings"]["allow_scroll"] 52 | ) 53 | ], 54 | alignment=flet.MainAxisAlignment.CENTER 55 | ) 56 | v.controls.append(row_allow_scrolling) 57 | 58 | cp = ColorPicker(v, settings_class.main_class.dict_content["pages"][current_page_name]["settings"]["bgcolor"], 59 | on_choose_color=on_change_bgcolor, add_it=False, title_name="bgcolor") 60 | v.controls.append( 61 | flet.Container( 62 | flet.Row( 63 | [cp.v], 64 | alignment=flet.MainAxisAlignment.CENTER 65 | ), 66 | bgcolor=flet.colors.BLACK 67 | ) 68 | ) 69 | 70 | v.update() 71 | -------------------------------------------------------------------------------- /fletsb/pages/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SKbarbon/Flet_StoryBoard/85fbe95030d7def96f59b0ad37ea32f324f2af87/fletsb/pages/__init__.py -------------------------------------------------------------------------------- /fletsb/pages/create_new_file.py: -------------------------------------------------------------------------------- 1 | import flet 2 | import time 3 | import os 4 | import json 5 | import requests 6 | 7 | from ..tools.create_storyboard import Create_StoryBoard 8 | 9 | 10 | class CreateNewFile: 11 | def __init__(self, page: flet.Page, manage_class): 12 | page.window_resizable = False 13 | page.update() 14 | page.window_center() 15 | 16 | # Set page prop 17 | page.bgcolor = flet.colors.BLACK 18 | 19 | # Setup Content's mother. 20 | self.manage_class = manage_class 21 | self.page = page 22 | self.mother = flet.AnimatedSwitcher( 23 | expand=True, 24 | content=flet.Text(""), 25 | transition=flet.AnimatedSwitcherTransition.FADE, 26 | duration=500, 27 | reverse_duration=250, 28 | switch_in_curve=flet.AnimationCurve.EASE_IN 29 | ) 30 | page.add(self.mother) 31 | 32 | time.sleep(0.3) 33 | # Run the first page. 34 | self.page_one() 35 | 36 | def page_one(self): 37 | page = self.page 38 | mother = self.mother 39 | main_column = flet.Column() 40 | mother.content = main_column 41 | 42 | main_column.controls.append(flet.Text("\n\n")) 43 | 44 | title_1 = flet.Text( 45 | "\n Let's imagine 😃,\n What if there is a ...", 46 | color=flet.colors.WHITE, 47 | size=36, 48 | weight=flet.FontWeight.BOLD 49 | ) 50 | describe = flet.Text( 51 | " Everything start from the imagine skill.\n With Flet_StoryBoard you will make the impossible ✨.\n", 52 | color=flet.colors.WHITE60, 53 | size=15 54 | ) 55 | next_button = flet.Container( 56 | flet.Row( 57 | [flet.Text("Start", color=flet.colors.BLACK)], 58 | alignment=flet.MainAxisAlignment.CENTER 59 | ), 60 | bgcolor=flet.colors.WHITE, 61 | width=100, 62 | height=35, 63 | border_radius=11, 64 | on_click=self.page_two 65 | ) 66 | 67 | main_column.controls.append(title_1) 68 | main_column.controls.append(describe) 69 | main_column.controls.append( 70 | flet.Column( 71 | [ 72 | flet.Row( 73 | [next_button], 74 | alignment=flet.MainAxisAlignment.END 75 | ) 76 | ], 77 | alignment=flet.MainAxisAlignment.END, 78 | expand=True 79 | ) 80 | ) 81 | 82 | page.update() 83 | 84 | def page_two(self, *args): 85 | def on_type(event): 86 | if event.control.value == "": 87 | next_button.tooltip = "You must pick a name." 88 | next_button.disabled = True 89 | next_button.update() 90 | else: 91 | next_button.tooltip = "Click to generate the file." 92 | next_button.disabled = False 93 | page.title = "Flet StoryBoard - " + str(event.control.value) 94 | if os.path.isfile(f"{page.title}.fletsb"): 95 | page.title = page.title + " | Warning: File name exist" 96 | page.update() 97 | self.file_name = str(event.control.value) 98 | 99 | page = self.page 100 | mother = self.mother 101 | main_column = flet.Column() 102 | mother.content = main_column 103 | 104 | main_column.controls.append(flet.Text("\n\n")) 105 | 106 | Title1 = flet.Text("\n Hey sir 🎩,\n What is the name ?", color=flet.colors.WHITE, size=36, weight="bold") 107 | main_column.controls.append(Title1) 108 | 109 | describe = flet.Text( 110 | " Lets choose a name of our UI.\n This name is the same as StoryBoad file name!.\n", 111 | color=flet.colors.WHITE60, size=15) 112 | main_column.controls.append(describe) 113 | 114 | StoryBoard_Name = flet.TextField(label="UI name", border_color=flet.colors.BLACK, cursor_color=flet.colors.BLACK, 115 | bgcolor=flet.colors.WHITE, border_radius=19, width=350, height=60, on_change=on_type, 116 | color=flet.colors.BLACK, on_submit=self.page_three) 117 | main_column.controls.append(flet.Row([StoryBoard_Name], alignment="center")) 118 | 119 | next_button = flet.Container(flet.Row([flet.Text("Generate", color=flet.colors.BLACK)], alignment="center"), 120 | bgcolor=flet.colors.WHITE, width=100, height=35, border_radius=11, on_click=self.page_three, 121 | disabled=True) 122 | main_column.controls.append( 123 | flet.Column([flet.Row([next_button], alignment="END")], alignment="END", expand=True)) 124 | 125 | mother.update() 126 | page.update() 127 | 128 | def page_three(self, *args): 129 | page = self.page 130 | page.title = page.title 131 | mother = self.mother 132 | main_column = flet.Column() 133 | mother.content = main_column 134 | 135 | main_column.controls.append(flet.Text("\n\n")) 136 | 137 | Title1 = flet.Text("\n Now🪄,\n Just choose a template!!", color=flet.colors.WHITE, size=36, weight="bold") 138 | main_column.controls.append(Title1) 139 | 140 | describe = flet.Text( 141 | " Ok, what is a template ?.\n A template is a theme and pre-set page that make it quick to start.\n", 142 | color=flet.colors.WHITE60, size=15) 143 | main_column.controls.append(describe) 144 | 145 | r = flet.Row([ 146 | self.make_a_template_button(flet.colors.WHITE24, "Blank new - default", "ADD_ROUNDED"), 147 | self.make_a_template_button(flet.colors.WHITE24, "Import template - soon", "GET_APP_OUTLINED", disable=True) 148 | ], alignment="center", spacing=15) 149 | main_column.controls.append(r) 150 | 151 | mother.update() 152 | page.update() 153 | 154 | def page_four(self, *args): 155 | page = self.page 156 | page.title = page.title 157 | mother = self.mother 158 | main_column = flet.Column() 159 | mother.content = main_column 160 | 161 | main_column.controls.append(flet.Text("\n\n")) 162 | 163 | Title1 = flet.Text("\n Wait😄,\n Building things for you.", color=flet.colors.WHITE, size=36, weight="bold") 164 | main_column.controls.append(Title1) 165 | 166 | mother.update() 167 | page.update() 168 | time.sleep(1) 169 | self.apply_suggestion_page() 170 | 171 | def apply_suggestion_page(self, *a): 172 | def dont_apply(e): 173 | Create_StoryBoard(self.file_name, "default", False) 174 | self.manage_class.file_name = self.file_name 175 | self.page.window_close() 176 | 177 | def apply_it(e): 178 | self.final_page_with_storyboard_suggest() 179 | 180 | page = self.page 181 | page.vertical_alignment = flet.MainAxisAlignment.CENTER 182 | page.title = page.title 183 | mother = self.mother 184 | main_column = flet.Column() 185 | mother.content = main_column 186 | col = main_column 187 | 188 | col.controls.append(flet.Row([flet.Text("", height=15)], alignment="center")) 189 | 190 | image = flet.Image(src="https://raw.githubusercontent.com/SKbarbon/Flet_StoryBoard/main/assets/IMG_3260.PNG", 191 | width=250, height=250) 192 | col.controls.append(flet.Row([image], alignment="center")) 193 | 194 | title = flet.Text("Apply StoryBoard suggestions", size=20, weight="bold", color=flet.colors.WHITE) 195 | col.controls.append(flet.Row([title], alignment="center")) 196 | 197 | describe = flet.Text(""" 198 | These are suggestions based on smart rules that help 199 | you build your interface by suggesting 200 | widgets based on your goal. 201 | """, size=13, color=flet.colors.WHITE) 202 | col.controls.append(flet.Row([describe], alignment="center")) 203 | 204 | apply_button = flet.ElevatedButton("Apply", bgcolor=flet.colors.WHITE, color=flet.colors.BLACK, width=250, on_click=apply_it) 205 | col.controls.append(flet.Row([apply_button], alignment="center")) 206 | 207 | no_btn = flet.TextButton(content=flet.Text("no thanks", color="red"), on_click=dont_apply) 208 | col.controls.append(flet.Row([no_btn], alignment="center")) 209 | 210 | mother.update() 211 | page.update() 212 | 213 | def final_page_with_storyboard_suggest(self): 214 | def apply_and_start(rule_name, rule_install_url): 215 | rules_file_content = requests.get(rule_install_url).text 216 | if not os.path.isdir("rules"): 217 | os.mkdir("rules") 218 | open(f"rules/{rule_name}.json", "w+", encoding="utf-8").write(str(rules_file_content)) 219 | Create_StoryBoard(self.file_name, "default", True, rule_name) 220 | self.manage_class.file_name = self.file_name 221 | self.page.window_close() 222 | 223 | # ------ 224 | page = self.page 225 | page.title = page.title 226 | mother = self.mother 227 | main_column = flet.Column() 228 | mother.content = main_column 229 | col = main_column 230 | col.scroll = True 231 | 232 | main_column.controls.append(flet.Text("\n\n")) 233 | 234 | Title1 = flet.Text("Choose your case.", color=flet.colors.WHITE, size=36, weight="bold") 235 | main_column.controls.append(flet.Row([Title1], alignment="center")) 236 | mother.update() 237 | describe = flet.Text(""" 238 | Choose your 'main' page goal from the 239 | options down bellow. This will install the right suggestions rules 240 | for your main page case. 241 | """, size=13, color=flet.colors.WHITE) 242 | col.controls.append(flet.Row([describe], alignment="center")) 243 | mother.update() 244 | 245 | all_rules = requests.get("https://raw.githubusercontent.com/SKbarbon/Flet_StoryBoard/main/rules/all.json").text 246 | all_rules = json.loads(all_rules) 247 | 248 | for rule_option in all_rules["all_rules"]: 249 | col.controls.append( 250 | self.make_a_rule_button_option(rule_option, all_rules["all_rules"][rule_option], apply_and_start)) 251 | 252 | col.scroll = True 253 | mother.update() 254 | 255 | def make_a_template_button(self, bgcolor, name, icon, disable=False): 256 | def on_hov(event): 257 | if event.data == "true": 258 | event.control.bgcolor = flet.colors.WHITE12 259 | elif event.data == "false": 260 | event.control.bgcolor = flet.colors.WHITE24 261 | event.control.update() 262 | event.control.update() 263 | 264 | cc = flet.Column(alignment="center", disabled=disable) 265 | c = flet.Container(width=220, height=140, bgcolor=bgcolor, border_radius=10, on_click=self.page_four, 266 | on_hover=on_hov) 267 | cc.controls.append(c) 268 | 269 | Icon = flet.Icon(icon, size=20, color=flet.colors.WHITE) 270 | c.content = flet.Row([Icon], alignment="center") 271 | 272 | name_it = flet.Text(name, color=flet.colors.WHITE, size=13, text_align="center") 273 | cc.controls.append(flet.Row([name_it], alignment="center")) 274 | 275 | return cc 276 | 277 | def make_a_rule_button_option(self, name, url, on_click): 278 | def on_choose(e): 279 | on_click(name, url) 280 | 281 | b = flet.ElevatedButton(f"{name}", on_click=on_choose, bgcolor=flet.colors.WHITE, color=flet.colors.BLACK, width=150, height=45) 282 | 283 | return flet.Row([b], alignment="center") 284 | -------------------------------------------------------------------------------- /fletsb/pages/main_page.py: -------------------------------------------------------------------------------- 1 | #! This is the editing page of a storyboard. 2 | from flet import Page, Row, Text 3 | from ..widgets.All import all_widgets 4 | import flet 5 | import os 6 | import json 7 | import time 8 | import requests 9 | 10 | 11 | #* local imports 12 | from ..sections.left_section import leftSection 13 | from ..sections.preview_section import PreviewSection 14 | from ..sections.edit_section import editSection 15 | from ..engines.edit_widget_engine import EditWidgetsEngine 16 | from ..engines.edit_subwidgets_engine import EditSubWidgetsEngine 17 | from ..engines.suggesting_engine import SuggestingEngine 18 | from ..widgets.All import all_widgets 19 | from ..pages.settings import SettingsPage 20 | from ..engines.bardai_engine import BardapiSupport 21 | 22 | 23 | class mainPage: 24 | def __init__(self, file_path): 25 | if not os.path.isfile(file_path): 26 | raise FileExistsError(f"There is no Flet StoryBoard on path '{file_path}' .") 27 | 28 | 29 | self.current_page_name = "main" 30 | self.file_path = file_path 31 | self.development_mode = True 32 | self.dict_content = json.loads(open(file_path, encoding="utf-8").read()) 33 | 34 | #? Copy of classes 35 | self.bard_support_bridge = BardapiSupport() 36 | self.all_widgets = all_widgets 37 | self._editWidgetsEngine = EditWidgetsEngine 38 | self._editSubWidgetsEngine = EditSubWidgetsEngine 39 | 40 | #? Run the app 41 | flet.app(target=self.app) 42 | 43 | def app (self, page:Page): 44 | page.title = f"Flet StoryBoard - {self.file_path}" 45 | page.spacing = 0 46 | page.bgcolor = "black" 47 | page.vertical_alignment = flet.MainAxisAlignment.CENTER 48 | page.window_width = 850 49 | page.window_height = 650 50 | page.window_min_width = 850 51 | page.window_min_height = 640 52 | self.page = page 53 | page.appbar = self.generate_app_bar() 54 | page.window_center() 55 | page.update() 56 | 57 | # main stack 58 | self.main_stack = flet.Stack(expand=True) 59 | page.add(self.main_stack) 60 | 61 | # The main row 62 | self.main_row = Row(scroll=False) 63 | # page.add(self.main_row) 64 | self.main_stack.controls.append(self.main_row) 65 | page.update() 66 | 67 | #? append the sections 68 | self.left_section = leftSection(page, self, self.main_row) 69 | self.preview_section = PreviewSection(page, self, self.main_row) 70 | self.edit_section = editSection(page, self, self.main_row) 71 | 72 | #? Set finals of page. 73 | page.on_resize = self.on_page_resize 74 | page.on_keyboard_event = self.manage_keyboard_commands 75 | 76 | 77 | #? Setup the storyboard suggestions engine. 78 | self.suggesting_engine = SuggestingEngine(self) 79 | time.sleep(0.5) 80 | self.suggesting_engine.push_new_suggestion() 81 | 82 | def on_page_resize (self, *event): 83 | page = self.page 84 | self.left_section.main_container.width = self.page.width / 4 - 30 85 | self.left_section.main_container.height = self.page.height - 70 86 | self.preview_section.main_view.width = page.width-(page.width/4)*2 87 | self.preview_section.main_view.height = page.height-150 88 | self.edit_section.main_column.width = self.page.width / 4 - 10 89 | self.edit_section.main_column.height = page.height - 70 90 | 91 | self.page.update() 92 | 93 | def pages_browser (self): 94 | def create_a_page (e): 95 | self.create_new_page(str(e.control.value)) 96 | self.page.appbar = self.generate_app_bar() 97 | self.page.update() 98 | def open_a_page (e): 99 | page_name = str(e.control.content.controls[0].value) 100 | if page_name in self.dict_content["pages"]: 101 | self.current_page_name = page_name 102 | self.preview_section.update_preview(self.current_page_name) 103 | self.last_checked_page_button.bgcolor = flet.colors.GREY_700 104 | self.last_checked_page_button = e.control 105 | e.control.bgcolor = "blue" 106 | time.sleep(0.3) 107 | self.suggesting_engine.push_new_suggestion() 108 | self.page.update() 109 | def ask_for_new_page_name (e): 110 | mr.scroll = False 111 | tf = flet.TextField(label="Page name", on_submit=create_a_page, height=40, color="white") 112 | mr.controls = [tf] 113 | mr.update() 114 | tf.focus() 115 | mr = flet.Row([], width=250, scroll=True) 116 | mr.controls.append(flet.TextButton(content=flet.Text("✨", size=18), on_click=self.edit_page_suggestion_state, width=35)) 117 | new_page_button = flet.Container(flet.Row([flet.Text("+ Page", size=12, color="black")], alignment="center"), on_click=ask_for_new_page_name, 118 | bgcolor="white", width=60, height=30, border_radius=12) 119 | mr.controls.append(new_page_button) 120 | 121 | for p in self.dict_content["pages"]: 122 | c = flet.Container(flet.Row([ 123 | flet.Text(p, color="white", size=12) 124 | ], alignment="center"), bgcolor=flet.colors.GREY_700, width=60, height=30, border_radius=12, on_click=open_a_page) 125 | mr.controls.append(c) 126 | if str(p) == str(self.current_page_name): 127 | c.bgcolor = "blue" 128 | self.last_checked_page_button = c 129 | 130 | return mr 131 | 132 | def generate_app_bar (self): 133 | a = flet.AppBar( 134 | bgcolor=self.page.bgcolor, 135 | leading=flet.Row([ 136 | Text(" "), 137 | flet.Icon(flet.icons.DASHBOARD_ROUNDED, size=18, color="white"), 138 | Text("Flet StoryBoard", color="white", weight="bold", size=15) 139 | ], spacing=15 140 | ), 141 | actions=[ 142 | Row([ 143 | flet.TextButton(content=flet.Text("Settings", size=12, color="white"), 144 | on_click=self.open_settings_page), 145 | flet.ElevatedButton("Save", bgcolor="white", color="black", width=100, height=35, 146 | on_click=self.save_all, tooltip="click to save | also control + S"), 147 | Text(" ") 148 | ], alignment=15) 149 | ], 150 | title=self.pages_browser(), 151 | center_title=True 152 | ) 153 | 154 | return a 155 | 156 | 157 | def manage_keyboard_commands (self, event): 158 | key = event.key # It would be a key like: 'A' or 'Enter'. 159 | shift = event.shift # It would be a bool value of where the shift key is clicked or not. 160 | ctrl = event.ctrl # It would be a bool value of where the control key is clicked or not. 161 | alt = event.alt # It would be a bool value of where the option key is clicked or not. 162 | meta = event.meta # It would be a bool value of where the command key is clicked or not. 163 | 164 | if str(key).lower() == "s" and ctrl: 165 | #? Clicked to save file 166 | self.save_all() 167 | elif str(key).lower() == "s" and meta: 168 | #? Clicked to save file 169 | self.save_all() 170 | elif str(key).lower() == "b" and ctrl: 171 | #? push bard input 172 | self.bard_support_bridge.push_ui(self.push_on_top_views, self) 173 | elif str(key).lower() == "b" and meta: 174 | #? push bard input 175 | self.bard_support_bridge.push_ui(self.push_on_top_views, self) 176 | 177 | 178 | def save_all (self, *args): 179 | new_content = json.dumps(self.dict_content) 180 | file = open(self.file_path, "w+", encoding="utf-8") 181 | file.write(new_content) 182 | 183 | page = self.page 184 | page.snack_bar = flet.SnackBar( 185 | content=flet.Text(f"This Flet StoryBoard '{self.file_path}' is saved!"), 186 | action="Alright!" 187 | ) 188 | page.snack_bar.open = True 189 | page.update() 190 | 191 | 192 | def add_new_widget (self, widget_name, page_name=None): 193 | widget_number = len(self.dict_content["pages"][self.current_page_name]["widgets"])-1 194 | widget_class = all_widgets[widget_name]["class"] 195 | widget_class = widget_class(self, self.preview_section.main_view_column, widget_number=widget_number) 196 | 197 | self.dict_content["pages"][self.current_page_name]["widgets"].append(widget_class.template) 198 | 199 | self.preview_section.update_preview(self.current_page_name) 200 | self.page.update() 201 | 202 | self.edit_a_widget(len(self.dict_content["pages"][self.current_page_name]["widgets"])-1) 203 | 204 | time.sleep(0.5) 205 | self.suggesting_engine.push_new_suggestion() 206 | 207 | return widget_class 208 | 209 | def edit_a_widget (self, widget_number_on_content): 210 | self.edit_section.edit_widget_using_engine(widget_number_on_content) 211 | self.page.update() 212 | 213 | 214 | def create_new_page (self, page_name): 215 | page_dict = { 216 | "settings" : { 217 | "bgcolor" : "black", 218 | "suggestions_rules" : "none" 219 | }, 220 | "widgets" : [ 221 | 222 | ] 223 | } 224 | self.dict_content["pages"][page_name] = page_dict 225 | self.current_page_name = str(page_name) 226 | self.page.appbar = self.generate_app_bar() 227 | self.preview_section.update_preview(self.current_page_name) 228 | 229 | 230 | def edit_page_suggestion_state (self, *a): 231 | def go_back (e): 232 | self.left_section.show_new_content(last_content) 233 | self.page.update() 234 | 235 | def apply_and_start (name_of_sug): 236 | self.dict_content["pages"][self.current_page_name]["settings"]["suggestions_rules"] = str(name_of_sug) 237 | go_back("") 238 | self.suggesting_engine.push_new_suggestion() 239 | 240 | def make_a_rule_button_option (name): 241 | def on_choose (e): 242 | apply_and_start(name) 243 | b = flet.ElevatedButton(f"{name}", on_click=on_choose, bgcolor="white", color="blacK", width=150, height=45) 244 | return flet.Row([b], alignment="center") 245 | 246 | last_content = self.left_section.main_container 247 | c = flet.Column(width=last_content.width, height=last_content.height) 248 | 249 | back_btn = flet.TextButton("< Back", on_click=go_back) 250 | c.controls.append(back_btn) 251 | 252 | title = flet.Text("Chose the suggestion rules for this page.", color="white", size=17, weight="bold") 253 | c.controls.append(title) 254 | 255 | all_rules = requests.get("https://raw.githubusercontent.com/SKbarbon/Flet_StoryBoard/main/rules/all.json").text 256 | all_rules = json.loads(all_rules) 257 | 258 | for rule_option in all_rules["all_rules"]: 259 | c.controls.append(make_a_rule_button_option(rule_option)) 260 | 261 | c.controls.append(flet.Row([flet.Text("more will come soon", color="white", size=13)], alignment="center")) 262 | c.scroll = True 263 | self.left_section.show_new_content(c) 264 | 265 | def open_settings_page (self, *e): 266 | SettingsPage(self.page, self) 267 | 268 | 269 | def push_on_top_views (self, container:flet.Container): 270 | def erase_all (): 271 | self.main_stack.controls.remove(col) 272 | self.main_stack.update() 273 | 274 | container.width = self.page.width 275 | container.height = self.page.height 276 | col = flet.Column([ 277 | flet.Row([container], alignment="center") 278 | ], alignment="center") 279 | self.main_stack.controls.append( 280 | col 281 | ) 282 | if self.main_stack.page != None: 283 | self.main_stack.update() 284 | 285 | return erase_all -------------------------------------------------------------------------------- /fletsb/pages/settings.py: -------------------------------------------------------------------------------- 1 | from flet import Page 2 | import flet 3 | import time 4 | 5 | from .Settings.pages import page_settings_page 6 | 7 | class SettingsPage: 8 | def __init__(self, page:Page, main_class) -> None: 9 | self.page : Page = page 10 | self.main_class = main_class 11 | #? Create a copy of things. 12 | self.__last_keyboard_manager = main_class.manage_keyboard_commands 13 | self.__last_controls = list(page.controls) 14 | self.__lat_appbar = page.appbar 15 | self.__last_on_resize_function = main_class.on_page_resize 16 | 17 | #? For keyboard events 18 | self.current_selected_page = None 19 | self.page_opend = True 20 | #? Hide all page controls 21 | self.hide_all() 22 | 23 | #? ReSet all page controls 24 | page.on_keyboard_event = self.keyboard_keys_manager 25 | page.on_resize = self.on_page_resize 26 | page.controls.clear() 27 | page.appbar = None 28 | page.bgcolor = "black" 29 | page.update() 30 | 31 | main_row = flet.Row(alignment="center") 32 | page.add(main_row) 33 | 34 | #? pages browseing section 35 | pages_browser_container = flet.Container(border_radius=12) 36 | self.pages_broswer = flet.Column(width=page.width/3, height=page.height-50, scroll=True) 37 | pages_browser_container.content = self.pages_broswer 38 | main_row.controls.append(pages_browser_container) 39 | page.update() 40 | 41 | #? viewing selected page section 42 | page_viewing_section_container = flet.Container(bgcolor="#1C1C1E", border_radius=12) 43 | self.page_viewing_section = flet.Column(width=page.width-(page.width/3)-50, height=page.height-50, scroll=True) 44 | page_viewing_section_container.content = self.page_viewing_section 45 | main_row.controls.append(page_viewing_section_container) 46 | page.update() 47 | 48 | #? The title and back_btn 49 | title = flet.Text(" Settings", size=28, weight="bold", color="white") 50 | self.pages_broswer.controls.append(flet.Row([ 51 | flet.IconButton("CLOSE_ROUNDED", on_click=self.go_back, icon_color="white", width=30), title 52 | ], spacing=0)) 53 | 54 | self.pages_broswer.controls.append(flet.Text("")) 55 | 56 | #? show all settings pages 57 | for p in self.get_all_settings_pages(): 58 | self.pages_broswer.controls.append(page_navigator_frame_button(p, self.get_all_settings_pages()[p]["icon"], self.get_all_settings_pages()[p]["function"],self)) 59 | 60 | page.update() 61 | 62 | def open_new_settings_page(self, control): 63 | """Open a new sub-page on settings page""" 64 | pass 65 | 66 | def route_to_page (self): 67 | """Use flet Route to a page""" 68 | 69 | def hide_all (self): 70 | page : Page = self.page 71 | for i in range(10): 72 | for c in page.controls: 73 | c.opacity = c.opacity - 0.1 74 | page.appbar.opacity = page.appbar.opacity - 0.1 75 | c.update() 76 | for ac in page.appbar.actions: 77 | ac.opacity = ac.opacity - 0.1 78 | ac.update() 79 | page.appbar.leading.opacity = page.appbar.leading.opacity - 0.1 80 | page.appbar.leading.update() 81 | page.appbar.title.opacity = page.appbar.title.opacity - 0.1 82 | page.appbar.title.update() 83 | time.sleep(0.01) 84 | 85 | def go_back (self, *e): 86 | self.page_opend = False 87 | page : Page = self.page 88 | page.on_keyboard_event = self.__last_keyboard_manager 89 | page.controls.clear() 90 | page.bgcolor = "black" 91 | page.appbar = self.__lat_appbar 92 | 93 | for c in self.__last_controls: 94 | c.opacity = 1.0 95 | page.controls.append(c) 96 | 97 | for ac in page.appbar.actions: 98 | ac.opacity = 1.0 99 | 100 | page.appbar.leading.opacity = 1.0 101 | page.appbar.title.opacity = 1.0 102 | 103 | page.on_resize = self.__last_on_resize_function 104 | page.update() 105 | 106 | def on_page_resize (self, e): 107 | page = self.page 108 | self.pages_broswer.width = page.width/3 - 50 109 | self.pages_broswer.height = self.page.height - 50 110 | self.page_viewing_section.width = page.width-(page.width/3-50)-50 111 | self.page_viewing_section.height = page.height-50 112 | self.page.update() 113 | 114 | def get_all_settings_pages (self): 115 | return { 116 | "Pages" : {"icon":"PREVIEW_ROUNDED", "function":page_settings_page, "name":"Pages"}, 117 | "Editor" : {"icon":"SETTINGS_ROUNDED", "function":editor_page, "name":"Editor"} 118 | } 119 | 120 | def keyboard_keys_manager (self, e): 121 | if self.page_opend == False: return 122 | pass 123 | 124 | 125 | #? Generate page button 126 | def page_navigator_frame_button (name:str, icon, function, settings_class:SettingsPage, as_a_click=False): 127 | def on_hov (e): 128 | if str(e.data) == "true": 129 | container.bgcolor = flet.colors.WHITE60 130 | else: 131 | container.bgcolor = None 132 | container.update() 133 | if e.control == settings_class.current_selected_page: 134 | e.control.bgcolor = "blue" 135 | e.control.update() 136 | 137 | def on_click (e): 138 | if settings_class.current_selected_page == None: 139 | settings_class.current_selected_page = container 140 | container.bgcolor = "blue" 141 | if container.page == None: 142 | settings_class.page.update() 143 | else: 144 | container.update() 145 | else: 146 | settings_class.current_selected_page.bgcolor = None 147 | if settings_class.current_selected_page.page != None: 148 | settings_class.current_selected_page.update() 149 | settings_class.current_selected_page = container 150 | container.bgcolor = "blue" 151 | if container.page == None: 152 | settings_class.page.update() 153 | else: 154 | container.update() 155 | 156 | function(settings_class) 157 | 158 | 159 | 160 | container = flet.Container(width=200, height=40, border_radius=12, expand=True, 161 | on_hover=on_hov, on_click=on_click) 162 | r = flet.Row([flet.Text(" ")], alignment="center", width=200) 163 | container.content = r 164 | 165 | ICON = flet.Icon(icon, size=20, color="white") 166 | r.controls.append(ICON) 167 | 168 | NAME = flet.Text(name, size=17, color="white", expand=True, text_align="left") 169 | r.controls.append(NAME) 170 | 171 | if as_a_click: 172 | container.bgcolor = "blue" 173 | on_click(container) 174 | 175 | return flet.Row([container], alignment="center") 176 | 177 | 178 | #? Pages 179 | 180 | 181 | def editor_page (settings_class:SettingsPage): 182 | v = settings_class.page_viewing_section 183 | v.clean() 184 | v.controls.append(flet.Text("soon", color="white")) 185 | v.update() -------------------------------------------------------------------------------- /fletsb/sections/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SKbarbon/Flet_StoryBoard/85fbe95030d7def96f59b0ad37ea32f324f2af87/fletsb/sections/__init__.py -------------------------------------------------------------------------------- /fletsb/sections/edit_section.py: -------------------------------------------------------------------------------- 1 | from flet import Column, Page, Row 2 | import flet 3 | 4 | from ..engines.edit_widget_engine import EditWidgetsEngine 5 | 6 | 7 | class editSection: 8 | def __init__(self, page:Page, main_class, main_row:Row) -> None: 9 | self.page : Page = page 10 | self.main_class = main_class 11 | self.main_row : Row = main_row 12 | 13 | self.main_column = Column(width=page.width/4, height=page.height,scroll=True) 14 | 15 | main_row.controls.append(self.main_column) 16 | 17 | def edit_widget_using_engine (self, widget_number): 18 | ee = EditWidgetsEngine(main_class=self.main_class, section_view=self.main_column, widget_number=widget_number) -------------------------------------------------------------------------------- /fletsb/sections/left_section.py: -------------------------------------------------------------------------------- 1 | # This is the left section part. 2 | from flet import Page, AnimatedSwitcher, Container, Row, Column 3 | import flet 4 | import time 5 | 6 | from ..widgets.All import all_widgets 7 | from ..ui_toolkit.widget_browser_frame import Widget_Browse_Frame 8 | 9 | class leftSection: 10 | def __init__(self, page:Page, main_class, main_row:Row) -> None: 11 | self.page : Page = page 12 | self.main_class = main_class 13 | self.main_row = main_row 14 | 15 | self.self_ui = AnimatedSwitcher(transition=flet.AnimatedSwitcherTransition.FADE, duration=500, reverse_duration=250, switch_in_curve=flet.AnimationCurve.EASE, switch_out_curve=flet.AnimationCurve.EASE_IN_BACK) 16 | self.main_container = Container(bgcolor=page.bgcolor, width=page.width/4-30, height=page.height) 17 | self.self_ui.content = self.main_container 18 | main_row.controls.append(self.self_ui) 19 | 20 | #? Show all widgets. 21 | self.show_all_widgets() 22 | 23 | 24 | def show_new_content (self, container:Container): 25 | self.main_container = container 26 | self.self_ui.content = container 27 | 28 | if self.self_ui.page != None: 29 | self.self_ui.update() 30 | else: 31 | self.page.update() 32 | 33 | if hasattr(self.main_class, "on_page_resize"): 34 | try: self.main_class.on_page_resize() 35 | except: pass 36 | 37 | 38 | def show_all_widgets (self): 39 | page = self.page 40 | #* This is the default section. 41 | 42 | col = Column(scroll=True) 43 | title = flet.Text("Widgets", size=25, weight="bold", color="white") 44 | col.controls.append(title) 45 | for wid in all_widgets: 46 | w = Widget_Browse_Frame(wid, all_widgets[wid], self.main_class.add_new_widget, self.main_class.current_page_name) 47 | col.controls.append(w) 48 | 49 | 50 | self.main_container = Container(bgcolor=page.bgcolor, width=page.width/4, height=page.height) 51 | self.main_container.content = col 52 | self.show_new_content(self.main_container) 53 | self.page.update() 54 | 55 | 56 | def show_the_suggestions (self): 57 | pass -------------------------------------------------------------------------------- /fletsb/sections/preview_section.py: -------------------------------------------------------------------------------- 1 | import flet 2 | from ..engines.viewer_engine import viewerEngine 3 | 4 | 5 | class PreviewSection: 6 | def __init__(self, page: flet.Page, main_class, main_row: flet.Row): 7 | self.page: flet.Page = page 8 | self.main_class = main_class 9 | 10 | self.main_view = flet.Container( 11 | width=page.width - (page.width / 4) * 2, 12 | height=page.height - 80, 13 | border=flet.border.all(0.4, flet.colors.WHITE60), 14 | border_radius=12 15 | ) 16 | main_row.controls.append(self.main_view) 17 | 18 | self.main_view_column = flet.Column(alignment=flet.MainAxisAlignment.CENTER) 19 | self.main_view.content = self.main_view_column 20 | 21 | self.update_preview() 22 | page.update() 23 | 24 | def update_preview(self, page_name="main"): 25 | ve = viewerEngine( 26 | self.main_class, 27 | self.main_class.dict_content, 28 | page_name, 29 | self.main_view, 30 | self.main_view_column 31 | ) 32 | -------------------------------------------------------------------------------- /fletsb/tools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SKbarbon/Flet_StoryBoard/85fbe95030d7def96f59b0ad37ea32f324f2af87/fletsb/tools/__init__.py -------------------------------------------------------------------------------- /fletsb/tools/color_picker.py: -------------------------------------------------------------------------------- 1 | from flet import Container, Row, Column 2 | import flet 3 | 4 | 5 | def none(*args): 6 | pass 7 | 8 | 9 | class ColorPicker: 10 | 11 | def __init__( 12 | self, 13 | main_view=None, 14 | selected_color="white", 15 | on_choose_color=none, 16 | add_it=True, 17 | title_name="select color", 18 | drop_width=200, 19 | color_prev_width=50 20 | ) -> None: 21 | 22 | if main_view is None: 23 | return 24 | self.__all_colors = ["None", "white", "black", "pink", "red", "green", "yellow", "blue", "hex-color"] 25 | 26 | self.drop_width = drop_width 27 | self.on_choose_color = on_choose_color 28 | self.main_view = main_view 29 | self.selected_color = selected_color 30 | 31 | v = Container() 32 | self.v = v 33 | 34 | main_dropdown = flet.Dropdown(width=drop_width, value=selected_color, label=title_name, 35 | on_change=self.on_choose) 36 | for i in self.__all_colors: 37 | main_dropdown.options.append(flet.dropdown.Option(i)) 38 | self.mainDropdown = main_dropdown 39 | 40 | color_preview = flet.Container(width=color_prev_width, height=50, bgcolor=self.selected_color, border_radius=8, 41 | border=flet.border.all(0.1, "white")) 42 | self.color_preview = color_preview 43 | 44 | main_row = Row( 45 | controls=[ 46 | main_dropdown, 47 | color_preview 48 | ] 49 | ) 50 | self.main_row = main_row 51 | 52 | v.content = main_row 53 | if add_it: 54 | main_view.controls.append(v) 55 | 56 | def on_choose(self, me): 57 | def on_change_color(me): 58 | tfc.value = str(tfc.value).replace(" ", "") 59 | tfc.update() 60 | if tfc.value != "#": 61 | new_color_selected = tfc.value 62 | self.selected_color = tfc.value 63 | self.color_preview.bgcolor = tfc.value 64 | self.on_choose_color(tfc.value) 65 | self.v.update() 66 | 67 | def back_to_orig(me): 68 | self.color_preview.on_click = None 69 | self.selected_color = "white" 70 | self.mainDropdown.value = self.selected_color 71 | self.color_preview.bgcolor = self.selected_color 72 | self.main_row.controls[0] = self.mainDropdown 73 | self.v.update() 74 | 75 | new_color_selected = me.control.value 76 | tfc = flet.TextField( 77 | label="hex-color", 78 | value="#0", 79 | width=self.drop_width, 80 | on_change=on_change_color, 81 | on_submit=on_change_color 82 | ) 83 | 84 | if str(new_color_selected) == "hex-color": 85 | self.main_row.controls[0] = tfc 86 | self.color_preview.on_click = back_to_orig 87 | elif str(new_color_selected) == "None": 88 | self.color_preview.bgcolor = None 89 | self.selected_color = None 90 | self.on_choose_color(new_color_selected) 91 | else: 92 | self.color_preview.bgcolor = new_color_selected 93 | self.selected_color = new_color_selected 94 | self.on_choose_color(new_color_selected) 95 | 96 | self.v.update() 97 | 98 | def update(self): 99 | self.mainDropdown.value = self.selected_color 100 | self.color_preview.bgcolor = self.selected_color 101 | self.v.update() 102 | 103 | @property 104 | def value(self): 105 | return self.selected_color 106 | -------------------------------------------------------------------------------- /fletsb/tools/create_storyboard.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | 4 | def Create_StoryBoard(file_name, template="default", storyboard_suggestions=False, 5 | main_page_suggestions_rules="none", support_bard_ai=False): 6 | 7 | if template == "default": 8 | storyboard_default_template = { 9 | "storyboard_settings": { 10 | "template": "default", 11 | "storyboard_suggestions": storyboard_suggestions, 12 | "allow_scroll": False, 13 | "support_bard" : support_bard_ai 14 | }, 15 | "pages": { 16 | "main": { 17 | "settings": { 18 | "bgcolor": "black", 19 | "suggestions_rules": f"{main_page_suggestions_rules}" 20 | }, 21 | "widgets": [ 22 | 23 | ] 24 | } 25 | } 26 | } 27 | 28 | file = open(f"{file_name}.fletsb", "w+", encoding="utf-8") 29 | file.write(json.dumps(storyboard_default_template)) 30 | return True 31 | else: 32 | print("External templates are nor supported yet.") 33 | -------------------------------------------------------------------------------- /fletsb/tools/get_url_icon.py: -------------------------------------------------------------------------------- 1 | from bs4 import BeautifulSoup 2 | import requests 3 | import urllib3 4 | from requests.packages.urllib3.exceptions import InsecureRequestWarning 5 | 6 | requests.packages.urllib3.disable_warnings(InsecureRequestWarning) 7 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 8 | 9 | 10 | def get_site_favicon(url): 11 | response = requests.get(url, verify=False) 12 | soup = BeautifulSoup(response.text, 'html.parser') 13 | favicon_link = soup.find('link', rel='icon') or soup.find('link', rel='shortcut icon') or soup.find('link', rel='apple-touch-icon') 14 | try: 15 | favicon_url = favicon_link['href'] 16 | if str(favicon_url).startswith("http"): 17 | return f"{favicon_url}" 18 | else: 19 | return f"{url}/{favicon_url}" 20 | except: 21 | return None 22 | -------------------------------------------------------------------------------- /fletsb/tools/list_picker.py: -------------------------------------------------------------------------------- 1 | import flet 2 | 3 | 4 | class ListPopup: 5 | def __init__(self, the_list=None, main_class=None, default_choice=None, title=None): 6 | if the_list is None: 7 | return 8 | 9 | self.title = title 10 | self.page: flet.Page = main_class.page 11 | self.main_class = main_class 12 | self.self_ui = flet.TextButton(f"{title}: f{default_choice}", on_click=self.show_popup) 13 | self.the_list = the_list 14 | self.__selected = default_choice 15 | 16 | def show_popup(self, *args): 17 | def on_search(e): 18 | for i in self.all_list_choices: 19 | col.controls.remove(i) 20 | 21 | self.all_list_choices = [] 22 | 23 | if search_field.value == "": 24 | for icon in self.the_list: 25 | name = str(icon) 26 | if name.startswith("__"): 27 | pass 28 | else: 29 | self.all_list_choices.append(self.generate_new(name, col)) 30 | col.update() 31 | return 32 | 33 | self.all_list_choices = [] 34 | self.all_list_choices.clear() 35 | s = str(search_field.value).lower() 36 | 37 | for i in self.the_list: 38 | name = str(i) 39 | if str(i).lower().startswith(s): 40 | self.all_list_choices.append(self.generate_new(name, col)) 41 | col.update() 42 | 43 | page: flet.Page = self.main_class.page 44 | 45 | cont = flet.Container(bgcolor=flet.colors.BLACK, border_radius=12) 46 | loading_text = flet.Text("Loading..", color=flet.colors.WHITE) 47 | cont.content = flet.Row([loading_text], alignment=flet.MainAxisAlignment.CENTER, height=100) 48 | 49 | page.dialog = flet.AlertDialog() 50 | page.dialog.content = cont 51 | page.dialog.open = True 52 | page.update() 53 | 54 | col = flet.ListView(width=450, height=500) 55 | col.controls.append(flet.Text("Choose one:", color="white", size=28, weight=flet.FontWeight.BOLD)) 56 | 57 | search_field = flet.TextField(label="Search", on_change=on_search) 58 | col.controls.append(search_field) 59 | 60 | self.all_list_choices = [] 61 | for icon in self.the_list: 62 | name = str(icon) 63 | if name.startswith("__"): 64 | pass 65 | else: 66 | self.all_list_choices.append(self.generate_new(name, col)) 67 | 68 | cont.content = col 69 | page.update() 70 | 71 | def generate_new(self, value_name, col): 72 | def on_choose(e): 73 | self.self_ui.text = f"{self.title}: f{value_name}" 74 | self.__selected = value_name 75 | self.page.dialog.open = False 76 | self.page.update() 77 | 78 | r = flet.Row( 79 | [ 80 | flet.Icon(value_name, size=22, color=flet.colors.WHITE), 81 | flet.Text(f"{value_name}", color=flet.colors.WHITE) 82 | ] 83 | ) 84 | cc = flet.Container(content=r, on_click=on_choose) 85 | col.controls.append(cc) 86 | return cc 87 | 88 | @property 89 | def value(self): 90 | return self.__selected 91 | -------------------------------------------------------------------------------- /fletsb/tools/page_info.py: -------------------------------------------------------------------------------- 1 | 2 | def get_page_bgcolor (content_dict, page_name): 3 | return content_dict["pages"][page_name]["settings"]["bgcolor"] 4 | -------------------------------------------------------------------------------- /fletsb/tools/storyboard_class.py: -------------------------------------------------------------------------------- 1 | import flet 2 | 3 | 4 | class StoryBoard: 5 | def __init__(self, page, main_class): 6 | self.__page: flet.Page = page 7 | self.__main_class = main_class 8 | self.functions = {} 9 | 10 | def add_function(self, function_name, function): 11 | """ 12 | Define function, so the storyboard's widgets can access to. Like `function name` property of the `Button` widget need to have a Defined function. 13 | """ 14 | self.functions[function_name] = function 15 | self.points = {} 16 | 17 | def add_flet_control(self, control, on_centered=True): 18 | """ 19 | Add a flet control to the storyboard. 20 | if `on_centered = True` that means that the control will center the storyboard. 21 | """ 22 | if on_centered: 23 | r = flet.Row([control], alignment=flet.MainAxisAlignment.CENTER) 24 | self.__page.add(r) 25 | self.__page.update() 26 | else: 27 | self.__page.add(control) 28 | 29 | def get_point(self, point_name: str): 30 | """ 31 | The point is a place you choose to store some data in. 32 | You will get `None` as a return if the point have nothing yet. 33 | """ 34 | if point_name not in self.points: 35 | return None 36 | else: 37 | return self.points[point_name] 38 | 39 | def navigate_to_page(self, page_name: str): 40 | """ 41 | Go to a page name 42 | """ 43 | if page_name not in self.__main_class.dict_content["pages"]: 44 | raise KeyError(f"Page '{page_name}' is not found.") 45 | 46 | viewerEngine = self.__main_class.viewerEngine 47 | viewerEngine = viewerEngine( 48 | self.__main_class, 49 | self.__main_class.dict_content, 50 | page_name, 51 | self.__page, 52 | self.__page, 53 | self.__main_class.development_mode 54 | ) 55 | self.__page.update() 56 | 57 | def close_window(self): 58 | """Close the window""" 59 | self.__page.window_close() -------------------------------------------------------------------------------- /fletsb/ui_toolkit/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SKbarbon/Flet_StoryBoard/85fbe95030d7def96f59b0ad37ea32f324f2af87/fletsb/ui_toolkit/__init__.py -------------------------------------------------------------------------------- /fletsb/ui_toolkit/widget_browser_frame.py: -------------------------------------------------------------------------------- 1 | import flet 2 | 3 | 4 | def Widget_Browse_Frame(widget_name, widget_info_dict, on_click, page_name): 5 | def action(event): 6 | on_click(widget_name, page_name) 7 | 8 | def on_hover(event): 9 | event.control.bgcolor = "#474747" if event.data == "true" else "#5C5C5C" 10 | event.control.update() 11 | 12 | r = flet.Row( 13 | [ 14 | flet.Text(" "), 15 | flet.Icon(widget_info_dict["icon"], size=18, color=flet.colors.WHITE), 16 | flet.Text(widget_name, size=13, color=flet.colors.WHITE) 17 | ], 18 | spacing=12 19 | ) 20 | 21 | c = flet.Container( 22 | content=r, 23 | width=170, 24 | height=35, 25 | bgcolor="#5C5C5C", 26 | on_click=action, 27 | expand=True, 28 | on_hover=on_hover, 29 | border_radius=12 30 | ) 31 | 32 | return flet.Row([c], alignment=flet.MainAxisAlignment.CENTER) 33 | -------------------------------------------------------------------------------- /fletsb/widgets/All.py: -------------------------------------------------------------------------------- 1 | from .widgets.title import Title 2 | from .widgets.open_url import Open_Url 3 | from .widgets.button import Button 4 | from .widgets.label import Label 5 | from .widgets.markdown import Markdown 6 | from .widgets.paragraph import Paragraph 7 | from .widgets.row import Row 8 | from .widgets.column import Column 9 | from .widgets.image import Image 10 | from .widgets.padding import Padding 11 | from .widgets.textfield import TextField 12 | from .widgets.navigator import Navigator 13 | 14 | all_widgets = { 15 | "Title": {"icon": "TEXT_FIELDS_ROUNDED", "class": Title}, 16 | "TextField": {"icon": "INPUT_ROUNDED", "class": TextField}, 17 | "Open Url": {"icon": "INSERT_LINK_SHARP", "class": Open_Url}, 18 | "Button": {"icon": "SMART_BUTTON_ROUNDED", "class": Button}, 19 | "Label": {"icon": "MEDICAL_INFORMATION_OUTLINED", "class": Label}, 20 | "Markdown": {"icon": "TEXT_SNIPPET_ROUNDED", "class": Markdown}, 21 | "Paragraph": {"icon": "SHORT_TEXT_ROUNDED", "class": Paragraph}, 22 | "Row": {"icon": "VIEW_COLUMN_OUTLINED", "class": Row}, 23 | "Column" : {"icon":"TABLE_ROWS_SHARP", "class":Column}, 24 | "Image": {"icon": "IMAGE_OUTLINED", "class": Image}, 25 | "Padding": {"icon": "SPACE_BAR_ROUNDED", "class": Padding}, 26 | "Navigator": {"icon": "NAVIGATE_NEXT", "class": Navigator} 27 | } 28 | -------------------------------------------------------------------------------- /fletsb/widgets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SKbarbon/Flet_StoryBoard/85fbe95030d7def96f59b0ad37ea32f324f2af87/fletsb/widgets/__init__.py -------------------------------------------------------------------------------- /fletsb/widgets/widgets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SKbarbon/Flet_StoryBoard/85fbe95030d7def96f59b0ad37ea32f324f2af87/fletsb/widgets/widgets/__init__.py -------------------------------------------------------------------------------- /fletsb/widgets/widgets/button.py: -------------------------------------------------------------------------------- 1 | import flet 2 | from ...tools.color_picker import ColorPicker 3 | 4 | 5 | class Button(object): 6 | def __init__(self, main_class, parent, *args, **kwargs) -> None: 7 | self.parent = parent 8 | self.main_class = main_class 9 | self.self_object = flet.ElevatedButton(on_click=self.on_button_click) 10 | 11 | # all args 12 | self.args = { 13 | "text": {"type": str, "default_value": "click me"}, 14 | "function name": {"type": str, "default_value": ""}, 15 | "text_color": {"type": ColorPicker, "default_value": "black"}, 16 | "bgcolor": {"type": ColorPicker, "default_value": "white"}, 17 | "alignment": {"type": list, "options": ["left", "center", "right"], "default_value": "center"}, 18 | "width": {"type": int, "default_value": 95}, 19 | "height": {"type": int, "default_value": 40}, 20 | "hide": {"type": bool, "default_value": False} 21 | } 22 | 23 | # Template dict 24 | # This is where the widget data will be stored. 25 | self.template = { 26 | "widget_class_name": "Button", 27 | "properties": {} 28 | } 29 | for p in self.args: 30 | self.template["properties"][p] = self.args[p]["default_value"] 31 | 32 | self.update() 33 | 34 | def update(self, new_props: dict = None): 35 | t = self.self_object 36 | props = self.template["properties"] 37 | 38 | if new_props is not None: 39 | for i in new_props: 40 | self.template["properties"][i] = new_props[i] 41 | 42 | t.text = props["text"] 43 | t.color = props["text_color"] 44 | t.bgcolor = props["bgcolor"] 45 | t.width = props["width"] 46 | t.height = props["height"] 47 | t.visible = props["hide"] == False 48 | 49 | if self.self_object.page is not None: 50 | self.self_object.update() 51 | 52 | def on_button_click(self, event): 53 | if self.main_class.development_mode: 54 | return 55 | else: 56 | props = self.template["properties"] 57 | if props["function name"] == "": 58 | return 59 | 60 | if props["function name"] in self.main_class.storyboard_class.functions: 61 | self.main_class.storyboard_class.functions[props["function name"]]() 62 | else: 63 | fn = props["function name"] 64 | print(f"Pass error: There is not function found called {fn}") 65 | 66 | def return_widget(self): 67 | props = self.template["properties"] 68 | if self.main_class.development_mode: 69 | self.self_object.disabled = True 70 | if props["alignment"] == "left": 71 | return flet.Row([flet.Text(" "), self.self_object]) 72 | elif props["alignment"] == "center": 73 | return flet.Row([self.self_object], alignment=flet.MainAxisAlignment.CENTER) 74 | else: 75 | return flet.Row([self.self_object, flet.Text(" ")], alignment=flet.alignment.center_right) 76 | -------------------------------------------------------------------------------- /fletsb/widgets/widgets/column.py: -------------------------------------------------------------------------------- 1 | import flet 2 | from ...ui_toolkit.widget_browser_frame import Widget_Browse_Frame 3 | 4 | 5 | class Column(object): 6 | def __init__(self, main_class, parent, *args, **kwargs) -> None: 7 | self.parent = parent 8 | self.main_class = main_class 9 | self.self_object = flet.Column() 10 | 11 | self.widget_number = kwargs["widget_number"] 12 | 13 | # Column Special args. 14 | self.dont_border_subs = True 15 | self.last_added = None 16 | self.support_sub_widgets = True 17 | 18 | if main_class.development_mode: 19 | self.development_mode = True 20 | else: 21 | self.development_mode = False 22 | 23 | # all args 24 | self.args = { 25 | "width": {"type": int, "default_value": 23}, 26 | "height": {"type": int, "default_value": 150}, 27 | "hide": {"type": bool, "default_value": False}, 28 | "scroll": {"type": bool, "default_value": False}, 29 | "auto_scroll_to_end": {"type": bool, "default_value": True}, 30 | "expand": {"type": bool, "default_value": True}, 31 | "alignment": {"type": list, "options": ["left", "center", "right"], "default_value": "center"}, 32 | "sub_widgets_alignment": {"type": list, "options": ["left", "center", "right"], "default_value": "center"}, 33 | } 34 | 35 | # Template dict 36 | # This is where the widget data will be stored. 37 | self.template = { 38 | "widget_class_name": "Column", 39 | "properties": {}, 40 | "widgets": [] 41 | } 42 | for p in self.args: 43 | self.template["properties"][p] = self.args[p]["default_value"] 44 | 45 | self.update() 46 | 47 | def update(self, new_props: dict = None, new_sub_widgets: dict = None): 48 | c = self.self_object 49 | props = self.template["properties"] 50 | 51 | if new_props is not None: 52 | for i in new_props: 53 | self.template["properties"][i] = new_props[i] 54 | 55 | if new_sub_widgets is not None: 56 | for w in new_sub_widgets: 57 | self.template["widgets"].append(w) 58 | 59 | c.width = props["width"] 60 | c.height = props["height"] 61 | c.visible = props["hide"] == False 62 | c.expand = props["expand"] 63 | c.scroll = props["scroll"] 64 | c.alignment = props["sub_widgets_alignment"] 65 | c.auto_scroll = props["auto_scroll_to_end"] 66 | 67 | if self.self_object.page is not None: 68 | self.self_object.update() 69 | 70 | self.update_preview() 71 | 72 | # Column tools 73 | def widgets_to_add_in(self, *args): 74 | """To show all widgets that are available to add to the Column.""" 75 | for i in args: 76 | i.control.visible = False 77 | i.control.update() 78 | 79 | def go_back(*e): 80 | self.main_class.left_section.show_new_content(copy_of_last_container) 81 | if self.last_added is not None: 82 | if self.last_added.page is None: 83 | self.last_added.border = None 84 | self.main_class.page.update() 85 | else: 86 | self.last_added.border = None 87 | self.last_added.update() 88 | self.main_class.on_page_resize() 89 | for i in args: 90 | i.control.visible = True 91 | i.control.update() 92 | 93 | page = self.main_class.page 94 | # This is the default section. 95 | 96 | col = flet.Column(scroll=True) 97 | col.controls.append(flet.TextButton("< Back", on_click=go_back)) 98 | title = flet.Text("Widgets in Column", size=25, weight=flet.FontWeight.BOLD, color="white") 99 | col.controls.append(title) 100 | all_widgets = self.main_class.all_widgets 101 | for wid in all_widgets: 102 | w = Widget_Browse_Frame(wid, all_widgets[wid], self.add_new_widget, self.main_class.current_page_name) 103 | col.controls.append(w) 104 | 105 | main_container = flet.Container( 106 | content=col, 107 | bgcolor=page.bgcolor, 108 | width=page.width / 4, 109 | height=page.height 110 | ) 111 | 112 | copy_of_last_container = self.main_class.left_section.self_ui.content 113 | self.main_class.left_section.show_new_content(main_container) 114 | self.main_class.on_page_resize() 115 | self.main_class.page.update() 116 | 117 | def add_new_widget(self, widget_name, page_name): 118 | """To add the widget, and open the edit to edit this new sub-widget.""" 119 | self.dont_border_subs = False 120 | all_widgets = self.main_class.all_widgets 121 | widget_class = all_widgets[widget_name]["class"] 122 | widget_class = widget_class( 123 | self, self.preview_section, 124 | widget_number=len(self.template["widgets"]) - 1, 125 | is_a_sub=True 126 | ) 127 | 128 | self.template["widgets"].append(widget_class.template) 129 | self.main_class.dict_content["pages"][self.main_class.current_page_name]["widgets"][self.widget_number]["widgets"] = self.template["widgets"] 130 | 131 | self.update_preview() 132 | editSubWidgetsEngine = self.main_class._editSubWidgetsEngine 133 | editSubWidgetsEngine = editSubWidgetsEngine( 134 | self.main_class, 135 | self, 136 | self.main_class.edit_section.main_column, 137 | len(self.template["widgets"]) - 1 138 | ) 139 | self.main_class.page.update() 140 | 141 | def update_preview(self): 142 | all_widgets = self.main_class.all_widgets 143 | self.preview_section.controls.clear() 144 | sub_widgets = self.template["widgets"] 145 | num = 0 146 | 147 | for widget in sub_widgets: 148 | if widget["widget_class_name"] in all_widgets: 149 | widget_class = all_widgets[widget["widget_class_name"]]["class"] 150 | widget_class = widget_class(self.main_class, self.preview_section) 151 | if hasattr(widget_class, "support_sub_widgets"): 152 | widget_class.update(widget["properties"], widget["widgets"]) 153 | else: 154 | widget_class.update(widget["properties"]) 155 | if self.development_mode: 156 | self.create_development_container(widget_class.return_widget(), num) 157 | else: 158 | self.preview_section.controls.append(widget_class.return_widget()) 159 | num = num + 1 160 | 161 | self.main_class.page.update() 162 | 163 | @property 164 | def preview_section(self): 165 | return self.self_object 166 | 167 | def return_widget(self): 168 | props = self.template["properties"] 169 | 170 | if props["alignment"] == "left": 171 | return flet.Row([flet.Text(" "), self.self_object]) 172 | elif props["alignment"] == "center": 173 | return flet.Row([self.self_object], alignment=flet.MainAxisAlignment.CENTER, spacing=0) 174 | else: 175 | return flet.Row([self.self_object, flet.Text(" ")], alignment=flet.MainAxisAlignment.END) 176 | 177 | def create_development_container(self, cls, widget_number): 178 | if self.last_added is None: 179 | c = flet.Container(cls, border_radius=8, border=flet.border.all(2, flet.colors.YELLOW_300)) 180 | self.last_added = c 181 | else: 182 | self.last_added.border = None 183 | c = flet.Container(cls, border_radius=8, border=flet.border.all(2, flet.colors.YELLOW_300)) 184 | self.last_added = c 185 | 186 | self.preview_section.controls.append(c) 187 | return c 188 | -------------------------------------------------------------------------------- /fletsb/widgets/widgets/image.py: -------------------------------------------------------------------------------- 1 | import flet 2 | 3 | 4 | class Image(object): 5 | def __init__(self, main_class, parent, *args, **kwargs) -> None: 6 | self.parent = parent 7 | self.main_class = main_class 8 | self.self_object = flet.Image(fit=flet.ImageFit.COVER) 9 | 10 | # all args 11 | self.args = { 12 | "src": {"type": str, "default_value": "https://picsum.photos/id/237/200/300"}, 13 | "width": {"type": int, "default_value": 150}, 14 | "height": {"type": int, "default_value": 150}, 15 | "border_radius": {"type": int, "default_value": 75}, 16 | "alignment": {"type": list, "options": ["left", "center", "right"], "default_value": "center"}, 17 | } 18 | 19 | # Template dict 20 | # This is where the widget data will be stored. 21 | self.template = { 22 | "widget_class_name": "Image", 23 | "properties": {} 24 | } 25 | for p in self.args: 26 | self.template["properties"][p] = self.args[p]["default_value"] 27 | 28 | self.update() 29 | 30 | def update(self, new_props: dict = None): 31 | img = self.self_object 32 | props = self.template["properties"] 33 | 34 | if new_props is not None: 35 | for i in new_props: 36 | self.template["properties"][i] = new_props[i] 37 | 38 | img.src = props["src"] 39 | img.width = props["width"] 40 | img.height = props["height"] 41 | img.border_radius = props["border_radius"] 42 | 43 | if self.self_object.page is not None: 44 | self.self_object.update() 45 | 46 | def return_widget(self): 47 | props = self.template["properties"] 48 | if props["alignment"] == "left": 49 | return flet.Row([flet.Text(" "), self.self_object]) 50 | elif props["alignment"] == "center": 51 | return flet.Row([self.self_object], alignment=flet.MainAxisAlignment.CENTER) 52 | else: 53 | return flet.Row([self.self_object, flet.Text(" ")], alignment=flet.alignment.center_right) 54 | -------------------------------------------------------------------------------- /fletsb/widgets/widgets/label.py: -------------------------------------------------------------------------------- 1 | import flet 2 | from ...tools.color_picker import ColorPicker 3 | from ...tools.list_picker import ListPopup 4 | 5 | 6 | class Label(object): 7 | def __init__(self, main_class, parent, *args, **kwargs) -> None: 8 | self.parent = parent 9 | self.main_class = main_class 10 | self.self_object = flet.Row() 11 | self.title_object = flet.Text() 12 | self.icon_object = flet.Icon() 13 | 14 | self.self_object.controls.append(self.icon_object) 15 | self.self_object.controls.append(self.title_object) 16 | 17 | # all args 18 | all_icons = [] 19 | for icon in flet.icons.__dict__: 20 | name = str(icon) 21 | if name.startswith("__"): 22 | pass 23 | else: 24 | all_icons.append(name) 25 | 26 | self.args = { 27 | "title": {"type": str, "default_value": "Just me and coffee"}, 28 | "icon": {"type": ListPopup, "options": all_icons, "default_value": "EMOJI_FOOD_BEVERAGE_ROUNDED"}, 29 | "title_color": {"type": ColorPicker, "default_value": "white"}, 30 | "icon_color": {"type": ColorPicker, "default_value": "white"}, 31 | "title_size": {"type": int, "default_value": 18}, 32 | "icon_size": {"type": int, "default_value": 18}, 33 | "spacing": {"type": int, "default_value": 15}, 34 | "title_bold": {"type": int, "default_value": True}, 35 | "alignment": {"type": list, "options": ["left", "center", "right"], "default_value": "center"} 36 | } 37 | 38 | # Template dict 39 | # This is where the widget data will be stored. 40 | self.template = { 41 | "widget_class_name": "Label", 42 | "properties": {} 43 | } 44 | for p in self.args: 45 | self.template["properties"][p] = self.args[p]["default_value"] 46 | 47 | self.update() 48 | 49 | def update(self, new_props: dict = None): 50 | r = self.self_object 51 | t = self.title_object 52 | I = self.icon_object 53 | props = self.template["properties"] 54 | 55 | if new_props is not None: 56 | for i in new_props: 57 | self.template["properties"][i] = new_props[i] 58 | 59 | r.spacing = props["spacing"] 60 | 61 | t.value = props["title"] 62 | t.color = props["title_color"] 63 | t.size = props["title_size"] 64 | 65 | if props["title_bold"]: 66 | t.weight = "bold" 67 | else: 68 | t.weight = "normal" 69 | 70 | I.name = props["icon"] 71 | I.color = props["icon_color"] 72 | I.size = props["icon_size"] 73 | 74 | if self.self_object.page is not None: 75 | self.self_object.update() 76 | 77 | def return_widget(self): 78 | props = self.template["properties"] 79 | if props["alignment"] == "left": 80 | return flet.Row([flet.Text(" "), self.self_object]) 81 | elif props["alignment"] == "center": 82 | return flet.Row([self.self_object], alignment=flet.MainAxisAlignment.CENTER) 83 | else: 84 | return flet.Row([self.self_object, flet.Text(" ")], alignment=flet.alignment.center_right) 85 | -------------------------------------------------------------------------------- /fletsb/widgets/widgets/markdown.py: -------------------------------------------------------------------------------- 1 | import flet 2 | 3 | 4 | class Markdown(object): 5 | def __init__(self, main_class, parent, *args, **kwargs) -> None: 6 | self.parent = parent 7 | self.main_class = main_class 8 | self.self_object = flet.Markdown( 9 | selectable=True, 10 | extension_set=flet.MarkdownExtensionSet.GITHUB_WEB, 11 | code_style=flet.TextStyle(font_family="Roboto Mono", color="blue") 12 | ) 13 | 14 | # all args 15 | self.args = { 16 | "content": {"type": str, "default_value": "", "multi_line": True}, 17 | "code_theme": {"type": list, "options": ["a11y-dark", "arta", "atom-one-dark", "dark", "default"], 18 | "default_value": "default"}, 19 | "width": {"type": int, "default_value": 150}, 20 | "height": {"type": int, "default_value": 150}, 21 | "alignment": {"type": list, "options": ["left", "center", "right"], "default_value": "left"} 22 | } 23 | 24 | # Template dict 25 | # This is where the widget data will be stored. 26 | self.template = { 27 | "widget_class_name": "Markdown", 28 | "properties": {} 29 | } 30 | for p in self.args: 31 | self.template["properties"][p] = self.args[p]["default_value"] 32 | 33 | self.update() 34 | 35 | def update(self, new_props: dict = None): 36 | m = self.self_object 37 | props = self.template["properties"] 38 | 39 | if new_props is not None: 40 | for i in new_props: 41 | self.template["properties"][i] = new_props[i] 42 | 43 | m.value = props["content"] 44 | m.width = props["width"] 45 | m.height = props["height"] 46 | 47 | if self.self_object.page is not None: 48 | self.self_object.update() 49 | 50 | def return_widget(self): 51 | props = self.template["properties"] 52 | if props["alignment"] == "left": 53 | return flet.Row([flet.Text(" "), self.self_object]) 54 | elif props["alignment"] == "center": 55 | return flet.Row([self.self_object], alignment=flet.MainAxisAlignment.CENTER) 56 | else: 57 | return flet.Row([self.self_object, flet.Text(" ")], alignment=flet.alignment.center_right) 58 | -------------------------------------------------------------------------------- /fletsb/widgets/widgets/navigator.py: -------------------------------------------------------------------------------- 1 | import flet 2 | from ...tools.color_picker import ColorPicker 3 | 4 | 5 | class Navigator(object): 6 | def __init__(self, main_class, parent, *args, **kwargs) -> None: 7 | self.parent = parent 8 | self.main_class = main_class 9 | self.self_object = flet.ElevatedButton(on_click=self.on_button_click) 10 | 11 | # all args 12 | all_pages = [] 13 | for i in self.main_class.dict_content["pages"]: 14 | all_pages.append(i) 15 | self.args = { 16 | "text": {"type": str, "default_value": "click me"}, 17 | "page name": {"type": list, "options": all_pages, "default_value": "main"}, 18 | "width": {"type": int, "default_value": 150}, 19 | "height": {"type": int, "default_value": 45}, 20 | "alignment": {"type": list, "options": ["left", "center", "right"], "default_value": "center"}, 21 | "bgcolor": {"type": ColorPicker, "default_value": "black"}, 22 | "text_color": {"type": ColorPicker, "default_value": "blue"} 23 | } 24 | 25 | # Template dict 26 | # This is where the widget data will be stored. 27 | self.template = { 28 | "widget_class_name": "Navigator", 29 | "properties": {} 30 | } 31 | for p in self.args: 32 | self.template["properties"][p] = self.args[p]["default_value"] 33 | 34 | self.update() 35 | 36 | def update(self, new_props: dict = None): 37 | t = self.self_object 38 | props = self.template["properties"] 39 | 40 | if new_props is not None: 41 | for i in new_props: 42 | self.template["properties"][i] = new_props[i] 43 | 44 | t.text = props["text"] 45 | t.color = props["text_color"] 46 | t.bgcolor = props["bgcolor"] 47 | t.width = props["width"] 48 | t.height = props["height"] 49 | 50 | if self.self_object.page is not None: 51 | self.self_object.update() 52 | 53 | def on_button_click(self, event): 54 | if self.main_class.development_mode: 55 | return 56 | else: 57 | props = self.template["properties"] 58 | self.main_class.storyboard_class.navigate_to_page(props["page name"]) 59 | 60 | def return_widget(self): 61 | props = self.template["properties"] 62 | if self.main_class.development_mode: 63 | self.self_object.disabled = True 64 | if props["alignment"] == "left": 65 | return flet.Row([flet.Text(" "), self.self_object]) 66 | elif props["alignment"] == "center": 67 | return flet.Row([self.self_object], alignment=flet.MainAxisAlignment.CENTER) 68 | else: 69 | return flet.Row([self.self_object, flet.Text(" ")], alignment=flet.alignment.center_right) 70 | -------------------------------------------------------------------------------- /fletsb/widgets/widgets/open_url.py: -------------------------------------------------------------------------------- 1 | import flet 2 | from ...tools.color_picker import ColorPicker 3 | from ...tools.list_picker import ListPopup 4 | 5 | 6 | class Open_Url(object): 7 | def __init__(self, main_class, parent, *args, **kwargs) -> None: 8 | self.parent = parent 9 | self.main_class = main_class 10 | self.self_object = flet.Container(on_click=self.open_url) 11 | self.url_text = flet.Text() 12 | self.url_icon = flet.Icon(size=12) 13 | self.self_object.content = flet.Row([self.url_icon, self.url_text], alignment=flet.MainAxisAlignment.CENTER) 14 | 15 | # all args 16 | all_icons = [] 17 | for icon in flet.icons.__dict__: 18 | name = str(icon) 19 | if name.startswith("__"): 20 | pass 21 | else: 22 | all_icons.append(name) 23 | 24 | self.args = { 25 | "text": {"type": str, "default_value": "example url"}, 26 | "url": {"type": str, "default_value": "https://example.com"}, 27 | "link icon": {"type": ListPopup, "options": all_icons, "default_value": "INSERT_LINK_OUTLINED"}, 28 | "text_color": {"type": ColorPicker, "default_value": "blue"}, 29 | "icon_color": {"type": ColorPicker, "default_value": "blue"}, 30 | "bgcolor": {"type": ColorPicker, "default_value": "black"}, 31 | "alignment": {"type": list, "options": ["left", "center", "right"], "default_value": "center"}, 32 | "width": {"type": int, "default_value": 130}, 33 | "height": {"type": int, "default_value": 30}, 34 | "text_size": {"type": int, "default_value": 15}, 35 | "icon_size": {"type": int, "default_value": 15}, 36 | "border_radius": {"type": int, "default_value": 10}, 37 | "hide": {"type": bool, "default_value": False} 38 | } 39 | 40 | # Template dict 41 | # This is where the widget data will be stored. 42 | self.template = { 43 | "widget_class_name": "Open Url", 44 | "properties": {} 45 | } 46 | for p in self.args: 47 | self.template["properties"][p] = self.args[p]["default_value"] 48 | 49 | self.update() 50 | 51 | def update(self, new_props: dict = None): 52 | c = self.self_object 53 | t = self.url_text 54 | ii = self.url_icon 55 | props = self.template["properties"] 56 | 57 | if new_props is not None: 58 | for i in new_props: 59 | self.template["properties"][i] = new_props[i] 60 | 61 | url = props["url"] 62 | c.tooltip = f"open '{url}'" 63 | c.width = props["width"] 64 | c.bgcolor = props["bgcolor"] 65 | c.border_radius = props["border_radius"] 66 | c.height = props["height"] 67 | c.visible = props["hide"] == False 68 | 69 | t.value = props["text"] 70 | t.color = props["text_color"] 71 | t.text_align = props["text_color"] 72 | t.size = props["text_size"] 73 | 74 | ii.name = props["link icon"] 75 | ii.color = props["icon_color"] 76 | ii.size = props["icon_size"] 77 | if self.self_object.page is not None: 78 | self.self_object.update() 79 | 80 | def open_url(self, event): 81 | if self.main_class.development_mode: return 82 | url = self.template["properties"]["url"] 83 | event.control.page.launch_url(url) 84 | 85 | def return_widget(self): 86 | props = self.template["properties"] 87 | if props["alignment"] == "left": 88 | return flet.Row([flet.Text(" "), self.self_object]) 89 | elif props["alignment"] == "center": 90 | return flet.Row([self.self_object], alignment=flet.MainAxisAlignment.CENTER) 91 | else: 92 | # issue: right is not a valid value 93 | return flet.Row([self.self_object, flet.Text(" ")], alignment="right") 94 | -------------------------------------------------------------------------------- /fletsb/widgets/widgets/padding.py: -------------------------------------------------------------------------------- 1 | import flet 2 | 3 | 4 | class Padding(object): 5 | def __init__(self, main_class, parent, *args, **kwargs) -> None: 6 | self.parent = parent 7 | self.main_class = main_class 8 | self.self_object = flet.Text("") 9 | 10 | # all args 11 | self.args = { 12 | "width": {"type": int, "default_value": 50}, 13 | "height": {"type": int, "default_value": 50}, 14 | "alignment": {"type": list, "options": ["left", "center", "right"], "default_value": "center"} 15 | } 16 | 17 | # Template dict 18 | # This is where the widget data will be stored. 19 | self.template = { 20 | "widget_class_name": "Padding", 21 | "properties": {} 22 | } 23 | for p in self.args: 24 | self.template["properties"][p] = self.args[p]["default_value"] 25 | 26 | self.update() 27 | 28 | def update(self, new_props: dict = None): 29 | p = self.self_object 30 | props = self.template["properties"] 31 | 32 | if new_props is not None: 33 | for i in new_props: 34 | self.template["properties"][i] = new_props[i] 35 | 36 | p.width = props["width"] 37 | p.height = props["height"] 38 | 39 | if self.self_object.page is not None: 40 | self.self_object.update() 41 | 42 | def return_widget(self): 43 | props = self.template["properties"] 44 | if props["alignment"] == "left": 45 | return flet.Row([flet.Text(" "), self.self_object]) 46 | elif props["alignment"] == "center": 47 | return flet.Row([self.self_object], alignment=flet.MainAxisAlignment.CENTER) 48 | else: 49 | return flet.Row([self.self_object, flet.Text(" ")], alignment=flet.alignment.center_right) 50 | -------------------------------------------------------------------------------- /fletsb/widgets/widgets/paragraph.py: -------------------------------------------------------------------------------- 1 | import flet 2 | from ...tools.color_picker import ColorPicker 3 | 4 | 5 | class Paragraph(object): 6 | def __init__(self, main_class, parent, *args, **kwargs) -> None: 7 | self.parent = parent 8 | self.main_class = main_class 9 | self.self_object = flet.Text("") 10 | 11 | # all args 12 | self.args = { 13 | "text": {"type": str, 14 | "default_value": "dude,\nThere is no one who loves pain itself, who seeks after it and wants to have it, simply because it is pain 🙃...", 15 | "multi_line": True}, 16 | "text_color": {"type": ColorPicker, "default_value": "white"}, 17 | "size": {"type": int, "default_value": 16}, 18 | "width": {"type": int, "default_value": 300}, 19 | "italic": {"type": bool, "default_value": False}, 20 | "bold": {"type": bool, "default_value": False}, 21 | "hide": {"type": bool, "default_value": False}, 22 | "expand": {"type": bool, "default_value": False}, 23 | "alignment": {"type": list, "options": ["left", "center", "right"], "default_value": "center"}, 24 | "text_align": {"type": list, "options": ["left", "center", "right"], "default_value": "left"} 25 | } 26 | 27 | # Template dict 28 | # This is where the widget data will be stored. 29 | self.template = { 30 | "widget_class_name": "Paragraph", 31 | "properties": {} 32 | } 33 | for p in self.args: 34 | self.template["properties"][p] = self.args[p]["default_value"] 35 | 36 | self.update() 37 | 38 | def update(self, new_props: dict = None): 39 | t = self.self_object 40 | props = self.template["properties"] 41 | 42 | if new_props is not None: 43 | for i in new_props: 44 | self.template["properties"][i] = new_props[i] 45 | 46 | t.value = props["text"] 47 | t.size = props["size"] 48 | t.color = props["text_color"] 49 | t.width = props["width"] 50 | t.expand = props["expand"] 51 | t.italic = props["italic"] 52 | t.visible = props["hide"] == False 53 | 54 | if str(props["text_align"]).lower() == "left": 55 | t.text_align = flet.TextAlign.LEFT 56 | elif str(props["text_align"]).lower() == "center": 57 | t.text_align = flet.TextAlign.CENTER 58 | elif str(props["text_align"]).lower() == "right": 59 | t.text_align = flet.TextAlign.RIGHT 60 | 61 | if props["bold"]: 62 | t.weight = "bold" 63 | else: 64 | t.weight = "normal" 65 | 66 | if self.self_object.page is not None: 67 | self.self_object.update() 68 | 69 | def return_widget(self): 70 | props = self.template["properties"] 71 | if props["alignment"] == "left": 72 | return flet.Row([flet.Text(" "), self.self_object]) 73 | elif props["alignment"] == "center": 74 | return flet.Row([self.self_object], alignment=flet.MainAxisAlignment.CENTER) 75 | else: 76 | return flet.Row([self.self_object, flet.Text(" ")], alignment=flet.alignment.center_right) 77 | -------------------------------------------------------------------------------- /fletsb/widgets/widgets/row.py: -------------------------------------------------------------------------------- 1 | import flet 2 | from ...ui_toolkit.widget_browser_frame import Widget_Browse_Frame 3 | 4 | 5 | class Row(object): 6 | def __init__(self, main_class, parent, *args, **kwargs) -> None: 7 | self.parent = parent 8 | self.main_class = main_class 9 | self.self_object = flet.Row() 10 | 11 | self.widget_number = kwargs["widget_number"] 12 | 13 | # Row Special args. 14 | self.dont_border_subs = True 15 | self.last_added = None 16 | self.support_sub_widgets = True 17 | 18 | if main_class.development_mode: 19 | self.development_mode = True 20 | else: 21 | self.development_mode = False 22 | 23 | # all args 24 | self.args = { 25 | "width": {"type": int, "default_value": 23}, 26 | "height": {"type": int, "default_value": 150}, 27 | "hide": {"type": bool, "default_value": False}, 28 | "scroll": {"type": bool, "default_value": False}, 29 | "auto_scroll_to_end": {"type": bool, "default_value": True}, 30 | "expand": {"type": bool, "default_value": True}, 31 | "alignment": {"type": list, "options": ["left", "center", "right"], "default_value": "center"}, 32 | "sub_widgets_alignment": {"type": list, "options": ["left", "center", "right"], "default_value": "center"}, 33 | } 34 | 35 | # Template dict 36 | # This is where the widget data will be stored. 37 | self.template = { 38 | "widget_class_name": "Row", 39 | "properties": {}, 40 | "widgets": [] 41 | } 42 | for p in self.args: 43 | self.template["properties"][p] = self.args[p]["default_value"] 44 | 45 | self.update() 46 | 47 | def update(self, new_props: dict = None, new_sub_widgets: dict = None): 48 | r = self.self_object 49 | props = self.template["properties"] 50 | 51 | if new_props is not None: 52 | for i in new_props: 53 | self.template["properties"][i] = new_props[i] 54 | 55 | if new_sub_widgets is not None: 56 | for w in new_sub_widgets: 57 | self.template["widgets"].append(w) 58 | 59 | r.width = props["width"] 60 | r.height = props["height"] 61 | r.visible = props["hide"] == False 62 | r.expand = props["expand"] 63 | r.scroll = props["scroll"] 64 | r.alignment = props["sub_widgets_alignment"] 65 | r.auto_scroll = props["auto_scroll_to_end"] 66 | 67 | if self.self_object.page is not None: 68 | self.self_object.update() 69 | 70 | self.update_preview() 71 | 72 | # Row tools 73 | def widgets_to_add_in(self, *args): 74 | """To show all widgets that are available to add to the row.""" 75 | for i in args: 76 | i.control.visible = False 77 | i.control.update() 78 | 79 | def go_back(*e): 80 | self.main_class.left_section.show_new_content(copy_of_last_container) 81 | if self.last_added is not None: 82 | if self.last_added.page is None: 83 | self.last_added.border = None 84 | self.main_class.page.update() 85 | else: 86 | self.last_added.border = None 87 | self.last_added.update() 88 | self.main_class.on_page_resize() 89 | for i in args: 90 | i.control.visible = True 91 | i.control.update() 92 | 93 | page = self.main_class.page 94 | # This is the default section. 95 | 96 | # issue: scroll has not attribute True 97 | col = flet.Column(scroll=True) 98 | col.controls.append(flet.TextButton("< Back", on_click=go_back)) 99 | title = flet.Text("Widgets in row", size=25, weight=flet.FontWeight.BOLD, color="white") 100 | col.controls.append(title) 101 | all_widgets = self.main_class.all_widgets 102 | for wid in all_widgets: 103 | w = Widget_Browse_Frame(wid, all_widgets[wid], self.add_new_widget, self.main_class.current_page_name) 104 | col.controls.append(w) 105 | 106 | main_container = flet.Container( 107 | content=col, 108 | bgcolor=page.bgcolor, 109 | width=page.width / 4, 110 | height=page.height 111 | ) 112 | 113 | copy_of_last_container = self.main_class.left_section.self_ui.content 114 | self.main_class.left_section.show_new_content(main_container) 115 | self.main_class.on_page_resize() 116 | self.main_class.page.update() 117 | 118 | def add_new_widget(self, widget_name, page_name): 119 | """To add the widget, and open the edit to edit this new sub-widget.""" 120 | self.dont_border_subs = False 121 | all_widgets = self.main_class.all_widgets 122 | widget_class = all_widgets[widget_name]["class"] 123 | widget_class = widget_class( 124 | self, self.preview_section, 125 | widget_number=len(self.template["widgets"]) - 1, 126 | is_a_sub=True 127 | ) 128 | 129 | self.template["widgets"].append(widget_class.template) 130 | self.main_class.dict_content["pages"][self.main_class.current_page_name]["widgets"][self.widget_number]["widgets"] = self.template["widgets"] 131 | 132 | self.update_preview() 133 | editSubWidgetsEngine = self.main_class._editSubWidgetsEngine 134 | editSubWidgetsEngine = editSubWidgetsEngine( 135 | self.main_class, 136 | self, 137 | self.main_class.edit_section.main_column, 138 | len(self.template["widgets"]) - 1 139 | ) 140 | self.main_class.page.update() 141 | 142 | def update_preview(self): 143 | all_widgets = self.main_class.all_widgets 144 | self.preview_section.controls.clear() 145 | sub_widgets = self.template["widgets"] 146 | num = 0 147 | 148 | for widget in sub_widgets: 149 | if widget["widget_class_name"] in all_widgets: 150 | widget_class = all_widgets[widget["widget_class_name"]]["class"] 151 | widget_class = widget_class(self.main_class, self.preview_section) 152 | if hasattr(widget_class, "support_sub_widgets"): 153 | widget_class.update(widget["properties"], widget["widgets"]) 154 | else: 155 | widget_class.update(widget["properties"]) 156 | if self.development_mode: 157 | self.create_development_container(widget_class.return_widget(), num) 158 | else: 159 | self.preview_section.controls.append(widget_class.return_widget()) 160 | num = num + 1 161 | 162 | self.main_class.page.update() 163 | 164 | @property 165 | def preview_section(self): 166 | return self.self_object 167 | 168 | def return_widget(self): 169 | props = self.template["properties"] 170 | 171 | if props["alignment"] == "left": 172 | return flet.Row([flet.Text(" "), self.self_object]) 173 | elif props["alignment"] == "center": 174 | return flet.Row([self.self_object], alignment=flet.MainAxisAlignment.CENTER, spacing=0) 175 | else: 176 | return flet.Row([self.self_object, flet.Text(" ")], alignment=flet.MainAxisAlignment.END) 177 | 178 | def create_development_container(self, cls, widget_number): 179 | if self.last_added is None: 180 | c = flet.Container(cls, border_radius=8, border=flet.border.all(2, flet.colors.YELLOW_300)) 181 | self.last_added = c 182 | else: 183 | self.last_added.border = None 184 | c = flet.Container(cls, border_radius=8, border=flet.border.all(2, flet.colors.YELLOW_300)) 185 | self.last_added = c 186 | 187 | self.preview_section.controls.append(c) 188 | return c 189 | -------------------------------------------------------------------------------- /fletsb/widgets/widgets/textfield.py: -------------------------------------------------------------------------------- 1 | import flet 2 | from ...tools.color_picker import ColorPicker 3 | 4 | 5 | class TextField(object): 6 | def __init__(self, main_class, parent, *args, **kwargs) -> None: 7 | self.parent = parent 8 | self.main_class = main_class 9 | self.self_object = flet.TextField( 10 | on_focus=self.on_start_type, 11 | on_change=self.on_change_text, 12 | on_submit=self.on_end_type, 13 | selection_color=flet.colors.BLACK, 14 | cursor_color=flet.colors.BLACK 15 | ) 16 | 17 | # all args 18 | self.args = { 19 | "text": {"type": str, "default_value": ""}, 20 | "label": {"type": str, "default_value": "text.."}, 21 | "hint_text": {"type": str, "default_value": "text.."}, 22 | "can_reveal_password": {"type": bool, "default_value": True}, 23 | "password": {"type": bool, "default_value": False}, 24 | "width": {"type": int, "default_value": 200}, 25 | "height": {"type": int, "default_value": 65}, 26 | "border_radius": {"type": int, "default_value": 12}, 27 | "bgcolor": {"type": ColorPicker, "default_value": "white"}, 28 | "color": {"type": ColorPicker, "default_value": "black"}, 29 | "alignment": {"type": list, "options": ["left", "center", "right"], "default_value": "center"}, 30 | "on start": {"type": str, "default_value": ""}, 31 | "on change": {"type": str, "default_value": ""}, 32 | "on end": {"type": str, "default_value": ""}, 33 | "point name": {"type": str, "default_value": ""} 34 | } 35 | 36 | # Template dict 37 | # This is where the widget data will be stored. 38 | self.template = { 39 | "widget_class_name": "TextField", 40 | "properties": {} 41 | } 42 | for p in self.args: 43 | self.template["properties"][p] = self.args[p]["default_value"] 44 | 45 | self.update() 46 | 47 | def update(self, new_props: dict = None): 48 | tf = self.self_object 49 | props = self.template["properties"] 50 | 51 | if new_props is not None: 52 | for i in new_props: 53 | self.template["properties"][i] = new_props[i] 54 | 55 | tf.value = props["text"] 56 | tf.label = props["label"] 57 | tf.hint_text = props["hint_text"] 58 | tf.password = props["password"] 59 | tf.can_reveal_password = props["can_reveal_password"] 60 | tf.width = props["width"] 61 | tf.height = props["height"] 62 | tf.bgcolor = props["bgcolor"] 63 | tf.color = props["color"] 64 | tf.border_radius = props["border_radius"] 65 | 66 | if self.self_object.page is not None: 67 | self.self_object.update() 68 | 69 | def on_start_type(self, event): 70 | if self.main_class.development_mode: 71 | return 72 | else: 73 | props = self.template["properties"] 74 | if props["on start"] == "": 75 | return 76 | 77 | if props["on start"] in self.main_class.storyboard_class.functions: 78 | self.main_class.storyboard_class.functions[props["on start"]]() 79 | else: 80 | fn = props["on start"] 81 | print(f"Pass error: There is not function found called {fn}") 82 | 83 | def on_change_text(self, event): 84 | if self.main_class.development_mode: 85 | return 86 | else: 87 | props = self.template["properties"] 88 | if props["point name"] != "": 89 | self.main_class.storyboard_class.points[props["point name"]] = str(self.self_object.value) 90 | if props["on change"] == "": 91 | return 92 | 93 | if props["on change"] in self.main_class.storyboard_class.functions: 94 | self.main_class.storyboard_class.functions[props["on change"]](self.self_object.value) 95 | else: 96 | fn = props["on change"] 97 | print(f"Pass error: There is not function found called {fn}") 98 | 99 | def on_end_type(self, event): 100 | if self.main_class.development_mode: 101 | return 102 | else: 103 | props = self.template["properties"] 104 | if props["point name"] != "": 105 | self.main_class.storyboard_class.points[props["point name"]] = str(self.self_object.value) 106 | if props["on end"] == "": return 107 | 108 | if props["on end"] in self.main_class.storyboard_class.functions: 109 | self.main_class.storyboard_class.functions[props["on end"]](self.self_object.value) 110 | else: 111 | fn = props["on end"] 112 | print(f"Pass error: There is not function found called {fn}") 113 | 114 | def return_widget(self): 115 | if self.main_class.development_mode: 116 | self.self_object.disabled = True 117 | props = self.template["properties"] 118 | if props["alignment"] == "left": 119 | return flet.Row([flet.Text(" "), self.self_object]) 120 | elif props["alignment"] == "center": 121 | return flet.Row([self.self_object], alignment=flet.MainAxisAlignment.CENTER) 122 | else: 123 | return flet.Row([self.self_object, flet.Text(" ")], alignment=flet.alignment.center_right) 124 | -------------------------------------------------------------------------------- /fletsb/widgets/widgets/title.py: -------------------------------------------------------------------------------- 1 | import flet 2 | from ...tools.color_picker import ColorPicker 3 | 4 | 5 | class Title(object): 6 | def __init__(self, main_class, parent, *args, **kwargs) -> None: 7 | self.parent = parent 8 | self.main_class = main_class 9 | self.self_object = flet.Text("") 10 | 11 | # all args 12 | self.args = { 13 | "title": {"type": str, "default_value": "myTitle"}, 14 | "title_color": {"type": ColorPicker, "default_value": "white"}, 15 | "size": {"type": int, "default_value": 23}, 16 | "width": {"type": int, "default_value": 350}, 17 | "italic": {"type": bool, "default_value": False}, 18 | "bold": {"type": bool, "default_value": True}, 19 | "hide": {"type": bool, "default_value": False}, 20 | "expand": {"type": bool, "default_value": False}, 21 | "alignment": {"type": list, "options": ["left", "center", "right"], "default_value": "center"}, 22 | "text_align": {"type": list, "options": ["left", "center", "right"], "default_value": "left"} 23 | } 24 | 25 | # Template dict 26 | # This is where the widget data will be stored. 27 | self.template = { 28 | "widget_class_name": "Title", 29 | "properties": {} 30 | } 31 | for p in self.args: 32 | self.template["properties"][p] = self.args[p]["default_value"] 33 | 34 | self.update() 35 | 36 | def update(self, new_props: dict = None): 37 | t = self.self_object 38 | props = self.template["properties"] 39 | 40 | if new_props is not None: 41 | for i in new_props: 42 | self.template["properties"][i] = new_props[i] 43 | 44 | t.value = props["title"] 45 | t.size = props["size"] 46 | t.color = props["title_color"] 47 | t.width = props["width"] 48 | t.expand = props["expand"] 49 | t.italic = props["italic"] 50 | t.visible = props["hide"] == False 51 | if str(props["text_align"]).lower() == "left": 52 | t.text_align = flet.TextAlign.LEFT 53 | elif str(props["text_align"]).lower() == "center": 54 | t.text_align = flet.TextAlign.CENTER 55 | elif str(props["text_align"]).lower() == "right": 56 | t.text_align = flet.TextAlign.RIGHT 57 | 58 | if props["bold"]: 59 | t.weight = "bold" 60 | else: 61 | t.weight = "normal" 62 | 63 | if self.self_object.page is not None: 64 | self.self_object.update() 65 | 66 | def return_widget(self): 67 | props = self.template["properties"] 68 | if props["alignment"] == "left": 69 | return flet.Row([flet.Text(" "), self.self_object]) 70 | elif props["alignment"] == "center": 71 | return flet.Row([self.self_object], alignment=flet.MainAxisAlignment.CENTER) 72 | else: 73 | return flet.Row([self.self_object, flet.Text(" ")], alignment=flet.alignment.center_right) 74 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ 3 | "setuptools>=54", 4 | "wheel" 5 | ] 6 | build-backend = "setuptools.build_meta" -------------------------------------------------------------------------------- /rules/about_me.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules" : [ 3 | { 4 | "case" : {}, 5 | "sugs" : [ 6 | { 7 | "class" : "Title", 8 | "about" : "Add a short title to make your page better.", 9 | "props" : { 10 | "title" : "hey 👋!", 11 | "size" : 26 12 | } 13 | } 14 | ] 15 | }, 16 | { 17 | "case" : {"Title":1}, 18 | "sugs" : [ 19 | { 20 | "class" : "Image", 21 | "about" : "Add an image to make the page look better.", 22 | "props" : { 23 | "src" : "https://images.pexels.com/photos/5220075/pexels-photo-5220075.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2", 24 | "width" : 150, 25 | "height" : 150, 26 | "border_radius" : 35 27 | } 28 | } 29 | ] 30 | }, 31 | { 32 | "case" : {"Title":1, "Image":1}, 33 | "sugs" : [ 34 | { 35 | "class" : "Title", 36 | "about" : "Add a small text under the image to make it knowable by users.", 37 | "props" : { 38 | "title" : "Thats me :)", 39 | "size" : 11, 40 | "width" : 130, 41 | "bold" : false 42 | } 43 | }, 44 | { 45 | "class" : "Paragraph", 46 | "about" : "Add a paragraph that talks about you.", 47 | "props" : { 48 | "text" : "hello !,\nmy name is Dave, and I'm just a\nfictional legend. And also I am a content creator!", 49 | "size" : 16, 50 | "bold" : true 51 | } 52 | } 53 | ] 54 | }, 55 | { 56 | "case" : {"Title":2, "Image":1}, 57 | "sugs" : [ 58 | { 59 | "class" : "Paragraph", 60 | "about" : "Add a paragraph that talks about you.", 61 | "props" : { 62 | "text" : "hello !,\nmy name is Dave, and I'm just a\nfictional legend. And also I am a content creator!", 63 | "size" : 16, 64 | "bold" : true 65 | } 66 | } 67 | ] 68 | }, 69 | { 70 | "case" : {"Title":2, "Image":1, "Paragraph":1}, 71 | "sugs" : [ 72 | { 73 | "class" : "Padding", 74 | "about" : "Add padding to make space between widgets.", 75 | "props" : { 76 | "height" : 60 77 | } 78 | }, 79 | { 80 | "class" : "Open Url", 81 | "about" : "Add a link to one of your accounts or to email.", 82 | "props" : { 83 | "text" : "TikTok - 20k", 84 | "link icon" : "TIKTOK_ROUNDED", 85 | "text_color" : "black", 86 | "bgcolor" : "white", 87 | "icon_color" : "black", 88 | "width" : 150, 89 | "height" : 40, 90 | "text_size" : 15, 91 | "icon_size" : 15 92 | } 93 | } 94 | ] 95 | }, 96 | { 97 | "case" : {"Title":2, "Image":1, "Paragraph":1, "Padding":1}, 98 | "sugs" : [ 99 | { 100 | "class" : "Open Url", 101 | "about" : "Add a link to one of your accounts or to email.", 102 | "props" : { 103 | "text" : "TikTok - 20k", 104 | "link icon" : "TIKTOK_ROUNDED", 105 | "text_color" : "black", 106 | "bgcolor" : "white", 107 | "icon_color" : "black", 108 | "width" : 150, 109 | "height" : 40, 110 | "text_size" : 15, 111 | "icon_size" : 15 112 | } 113 | } 114 | ] 115 | }, 116 | { 117 | "case" : {"Title":1, "Image":1, "Paragraph":1}, 118 | "sugs" : [ 119 | { 120 | "class" : "Padding", 121 | "about" : "Add padding to make space between widgets.", 122 | "props" : { 123 | "height" : 60 124 | } 125 | }, 126 | { 127 | "class" : "Open Url", 128 | "about" : "Add a link to one of your accounts or to email.", 129 | "props" : { 130 | "text" : "TikTok - 20k", 131 | "link icon" : "TIKTOK_ROUNDED", 132 | "text_color" : "black", 133 | "bgcolor" : "white", 134 | "icon_color" : "black", 135 | "width" : 150, 136 | "height" : 40, 137 | "text_size" : 15, 138 | "icon_size" : 15 139 | } 140 | } 141 | ] 142 | }, 143 | { 144 | "case" : {"Title":1, "Image":1, "Paragraph":1, "Padding":1}, 145 | "sugs" : [ 146 | { 147 | "class" : "Open Url", 148 | "about" : "Add a link to one of your accounts or to email.", 149 | "props" : { 150 | "text" : "TikTok - 20k", 151 | "link icon" : "TIKTOK_ROUNDED", 152 | "text_color" : "black", 153 | "bgcolor" : "white", 154 | "icon_color" : "black", 155 | "width" : 150, 156 | "height" : 40, 157 | "text_size" : 15, 158 | "icon_size" : 15 159 | } 160 | } 161 | ] 162 | } 163 | 164 | ] 165 | } 166 | -------------------------------------------------------------------------------- /rules/all.json: -------------------------------------------------------------------------------- 1 | { 2 | "all_rules" : { 3 | "sign_in page" : "https://raw.githubusercontent.com/SKbarbon/Flet_StoryBoard/main/rules/signin_rules.json", 4 | "about_me page" : "https://raw.githubusercontent.com/SKbarbon/Flet_StoryBoard/main/rules/about_me.json" 5 | } 6 | } -------------------------------------------------------------------------------- /rules/signin_rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules" : [ 3 | { 4 | "case" : {}, 5 | "sugs" : [ 6 | { 7 | "class" : "Title", 8 | "about" : "Add a 'sign in' title so users know about this page.", 9 | "props" : { 10 | "title" : "sign in", 11 | "size" : 26 12 | } 13 | } 14 | ] 15 | }, 16 | { 17 | "case" : {"Title":1}, 18 | "sugs" : [ 19 | { 20 | "class" : "Paragraph", 21 | "about" : "Add a paragraph describing the current page, in a little more detail.", 22 | "props" : { 23 | "text" : "You look like you did not sign in.\nPlease sign in to start using the app 😃." 24 | } 25 | }, 26 | { 27 | "class" : "TextField", 28 | "about" : "Add a username TextField so users can enter their names.", 29 | "props" : { 30 | "label" : "username", 31 | "hint_text" : "username" 32 | } 33 | } 34 | ] 35 | }, 36 | { 37 | "case" : {"Title":1, "Paragraph":1}, 38 | "sugs" : [ 39 | { 40 | "class" : "TextField", 41 | "about" : "Add a username TextField so users can enter their names.", 42 | "props" : { 43 | "label" : "username", 44 | "hint_text" : "username", 45 | "width" : 250, 46 | "height" : 50 47 | } 48 | } 49 | ] 50 | }, 51 | { 52 | "case" : {"Title":1, "Paragraph":1, "TextField":1}, 53 | "sugs" : [ 54 | { 55 | "class" : "TextField", 56 | "about" : "Add a password TextField so users can enter their passwords.", 57 | "props" : { 58 | "label" : "password", 59 | "hint_text" : "password", 60 | "password" : true, 61 | "width" : 250, 62 | "height" : 50 63 | } 64 | } 65 | ] 66 | }, 67 | { 68 | "case" : {"Title":1, "Paragraph":1, "TextField":2}, 69 | "sugs" : [ 70 | { 71 | "class" : "Button", 72 | "about" : "Add a button to submit the sign-in.", 73 | "props" : { 74 | "text" : "Done!", 75 | "text_color" : "white", 76 | "bgcolor" : "blue", 77 | "width" : 100, 78 | "height" : 40 79 | } 80 | } 81 | ] 82 | }, 83 | { 84 | "case" : {"Title":1, "TextField":1}, 85 | "sugs" : [ 86 | { 87 | "class" : "TextField", 88 | "about" : "Add a password TextField so users can enter their passwords.", 89 | "props" : { 90 | "label" : "password", 91 | "hint_text" : "password", 92 | "password" : true, 93 | "width" : 250, 94 | "height" : 50 95 | } 96 | } 97 | ] 98 | }, 99 | { 100 | "case" : {"Title":1, "TextField":2}, 101 | "sugs" : [ 102 | { 103 | "class" : "Button", 104 | "about" : "Add a button to submit the sign-in.", 105 | "props" : { 106 | "text" : "Done!", 107 | "text_color" : "white", 108 | "bgcolor" : "blue", 109 | "width" : 100, 110 | "height" : 40 111 | } 112 | } 113 | ] 114 | }, 115 | { 116 | "case" : {"Paragraph":1}, 117 | "sugs" : [ 118 | { 119 | "class" : "TextField", 120 | "about" : "Add a username TextField so users can enter their names.", 121 | "props" : { 122 | "label" : "username", 123 | "hint_text" : "username", 124 | "width" : 250, 125 | "height" : 50 126 | } 127 | } 128 | ] 129 | }, 130 | { 131 | "case" : {"Paragraph":1, "TextField":1}, 132 | "sugs" : [ 133 | { 134 | "class" : "TextField", 135 | "about" : "Add a password TextField so users can enter their passwords.", 136 | "props" : { 137 | "label" : "password", 138 | "hint_text" : "password", 139 | "password" : true, 140 | "width" : 250, 141 | "height" : 50 142 | } 143 | } 144 | ] 145 | }, 146 | { 147 | "case" : {"Paragraph":1, "TextField":2}, 148 | "sugs" : [ 149 | { 150 | "class" : "Button", 151 | "about" : "Add a button to submit the sign-in.", 152 | "props" : { 153 | "text" : "Done!", 154 | "text_color" : "white", 155 | "bgcolor" : "blue", 156 | "width" : 100, 157 | "height" : 40 158 | } 159 | } 160 | ] 161 | }, 162 | { 163 | "case" : {"Title":1, "Paragraph":1, "TextField":2, "Label":1}, 164 | "sugs" : [ 165 | { 166 | "class" : "Button", 167 | "about" : "Add a button to submit the sign-in.", 168 | "props" : { 169 | "text" : "Done!", 170 | "text_color" : "white", 171 | "bgcolor" : "blue", 172 | "width" : 100, 173 | "height" : 40 174 | } 175 | } 176 | ] 177 | } 178 | ] 179 | } -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | with open("README.md", encoding="utf-8") as f: 4 | long_des = str(f.read()) 5 | 6 | setup( 7 | name='Flet StoryBoard', 8 | version='1.5', 9 | author='SKbarbon', 10 | description='A UI-Builder that helps programmers build the front-end without codding it.', 11 | long_description=long_des, 12 | long_description_content_type='text/markdown', 13 | url='https://github.com/SKbarbon/Flet-StoryBoard', 14 | install_requires=["flet==0.5.2", "requests", "bardapi"], 15 | packages=find_packages(), 16 | classifiers=[ 17 | "Programming Language :: Python :: 3", 18 | "Operating System :: MacOS :: MacOS X", 19 | "Operating System :: Microsoft :: Windows" 20 | ], 21 | ) --------------------------------------------------------------------------------