Package: fast-flet
🔥Fast-FletFast-Fletis a package built as a complement toFlet, designed for newbies which facilitates the handling of flet events, designed to work with numerous pages of your created application. It also provides a better MVC construction of your code, which can be scalable and easy to read. But it not only limits the MVC model but you canadapt it according to your preferences.📌Flet events it handleson_route_change:  Dynamic routing (automatic and manual)on_view_popon_keyboard_eventon_resizeon_error📌It also contains extra options:Responsive of the page in terms of its height.viewLogin control of assigned pages.viewAsync compatible.viewAutomatic dynamic routing.viewManual dynamic routing.viewCompatible withFlet_Fastapi.viewHow to useFast-Flet?viewclass ofFast-FletUsingViewPageclass.viewUsingMyControllerclass.viewUsing ofon_resize.viewUsing ofon_keyboard_event.view💻Installation:It is installed automatically:fletflet_fastapiuvicornpip install fast-flet💻Update:pip install fast-flet --upgrade⌨️Fast-FletCliContains new quickstart commands that you can use in the terminal. They will allow you to start developing immediately and without any effort.Create the MVC based projectfast-flet init mvcCreate the MVC based project (async)fast-flet init mvc --asyncCreate a custom project, only theviewsfolder and theapp.pyfile will be created.fast-flet init appCreate a custom project, only theviewsfolder and theapp.pyfile will be created. (async)fast-flet init app --asyncCheck the versionfast-flet version🚀 HOW TO USE FAST-FLET?Fast-Fletpresents a main structure based on MVC and the other is according to how the user wants to adapt it.Suggested MVCAdaptive according to the user.In this case it only requires theapp.pyfile and theviewsfolder, the rest is already customizable in terms of more folders or files.Fast-Flet app example:We create the main fileapp.pyin the root path of the project, which is whereFletwill be initialized.importfletasftfromfast_fletimportRoutePage,ConfViewdefmain(page:ft.Page):# CONFIGURACION GENERALtheme=ft.Theme()platforms=["android","ios","macos","linux","windows"]forplatforminplatforms:# Removing animation on route change.setattr(theme.page_transitions,platform,ft.PageTransitionTheme.NONE)page.theme=theme# View flet configuration in all viewsview=ConfView(appbar=lambda:ft.AppBar(title=ft.Text("fast-flet"),center_title=False,bgcolor=ft.colors.SURFACE_VARIANT,actions=[ft.IconButton(ft.icons.WB_SUNNY_OUTLINED),ft.IconButton(ft.icons.FILTER_3),ft.PopupMenuButton(items=[ft.PopupMenuItem(text="Item 1"),ft.PopupMenuItem(text="Checked item",checked=False),]),],))# ROUTING AND HANDLING VIEWS IN AUTOMATICOfast_flet=RoutePage(page=page,route="/index",route_login='/login',route_404="/404-fast-flet",view=view,)# WE RUN THE ROUTING OF THE VIEWSfast_flet.run()ft.app(main,port=8000,view=ft.AppView.WEB_BROWSER,web_renderer=ft.WebRenderer.AUTO,route_url_strategy='hash')Class usageRoutePage:By default thisFast-Fletclass performs automatic routing. It has the following attributes.page:'page' parameter of the main function of the app or website (mandatory).route:Path where the app or website will be initialized (mandatory).route_login:Login route, where it will be redirected.route_404:Custom page path not found.view:General configuration of all the'View'of the page'(page.views)'manual_routing:Use manual routing of'views'Class usageConfView:Contains allViewFlet properties to assign to all pages.Note: if the parameter receives a flet class,lambdais used. (Not in async)Example:controls:list=Noneappbar:AppBar=None# use lambdafloating_action_button:FloatingActionButton=None# use lambdanavigation_bar:NavigationBar=None# use lambdavertical_alignment:MainAxisAlignment=None# use lambdahorizontal_alignment:CrossAxisAlignment=None# use lambdaspacing:int=Nonepadding:int=None# use lambdabgcolor:str=None# use lambda# ScrollableControl specificscroll:ScrollMode=None# use lambdaauto_scroll:bool=Nonefullscreen_dialog:bool=Noneon_scroll_interval:OptionalNumber=None# use lambdaon_scroll=NoneManual dynamic routing.To perform manual routing, it is required to use theadd_routes()method fromRoutePageand importadd_view()fromFast-Flet.🔎Note:To use it you must first activate it in theRoutePageclass with its attributemanual_routing= True(by default it is False).Example:importfletasftfromfast_fletimportRoutePage,add_view# Import the View classes from the views folder to use in add_routesfromviews.indeximportViewfromviews.taskimportViewasTaskviewfromviews.contadorimportViewasContadorViewfromviews.loginimportViewasLoginViewfromviews.resizeimportViewasResizeViewfromviews.page_404importViewasPage_404Viewdefmain(page:ft.Page):# CONFIGURACION GENERALtheme=ft.Theme()platforms=["android","ios","macos","linux","windows"]forplatforminplatforms:# Removing animation on route change.setattr(theme.page_transitions,platform,ft.PageTransitionTheme.NONE)page.theme=themefast_flet=RoutePage(page=page,route="/index",route_login='/login',route_404="/404-fast-flet",manual_routing=True)# ROUTING AND MANAGEMENT VIEWS IN MANUAL'fast_flet.add_routes([add_view(url='/index',view=View()),add_view(url='/task',view=Taskview(),clear=False),add_view(url='/counter/:id/:name',view=ContadorView(),clear=False),add_view(url='/login',view=LoginView()),add_view(url='/resize',view=ResizeView(),clear=False),add_view(url='/404-fast-flet',view=Page_404View(),clear=False),])# WE RUN THE ROUTING OF THE VIEWSfast_flet.run()ft.app(main,port=8000,view=ft.AppView.WEB_BROWSER,web_renderer=ft.WebRenderer.AUTO,route_url_strategy='hash')Using theadd_view()functionThe parameters that this function has are:urlWe set the url.viewWe use the class imported from the views folder.clearAll views stored inpage.viewsare removed (default is true).⚡RoutePagerun()methodrun()Initialize Fast-Flet🔀Async apps with Fast-FletTo use Flet in async mode, it is initialized with therun_async()method of theRoutePageclass🗂️In theviewsfolder a file is created for exampleindex.py🔎Note: When using automatic routing the class must be calledViewand inheritViewPagefromFast-Flet.importfletasftfromfast_fletimportViewPageclassView(ViewPage):def__init__(self)->None:super().__init__()self.call.route='/index'# remove icon return to previous view of 'appbar', if it is activatedself.call.page_clear=True# clean the list of views added to the page (default is false)# View general configurationdefbuild(self):# we assign a urlself.route='/index'page=self.call.pagepage.title='Index'# modify View properties : https://flet.dev/docs/controls/viewself.appbar.title=ft.Text('Home')self.controls=[ft.Column([ft.Container(content=ft.Column([ft.FilledButton('go Counter',on_click=lambdae:e.page.go('/counter/100/fast-flet')),ft.FilledButton('go Task',on_click=lambdae:e.page.go('/task')),ft.FilledButton('go Resize',on_click=lambdae:e.page.go('/resize')),],alignment=ft.MainAxisAlignment.CENTER,horizontal_alignment=ft.CrossAxisAlignment.CENTER),width=450,height=450,bgcolor='blue800',alignment=ft.alignment.center,border_radius=20),])]self.horizontal_alignment=ft.CrossAxisAlignment.CENTERself.vertical_alignment=ft.MainAxisAlignment.CENTERself.bgcolor=ft.colors.BLACKTheViewclass inherits:self.callself.call.page: PageReceives the page from the main function.self.call.route: str = '/'Establish a route (Automatic Routing).self.call.page_clear:bool = FalseSet removal of listpage.viewsstored by flet (Automatic Routing).self.call.url_params: list = NoneReceives the parameters sent through the url.self.call.is_login: bool = FalseEstablish if the page requires login.self.call.on_keyboard_event: MykeyboardReceive information about the event:'on_keyboard_event'.self.call.on_resize: MyPageResizeReceive information about the event:on_resize.Configure flet View propertiesflet.View, It is used in thebuild()method.In thebuild()method that inherits from theViewPageclass, you can add new controllers and assign value of the page properties.self.controls: list = Noneself.appbar: AppBar = Noneself.floating_action_button: FloatingActionButton = Noneself.navigation_bar: NavigationBar = Noneself.vertical_alignment: MainAxisAlignment = Noneself.horizontal_alignment: CrossAxisAlignment = Noneself.spacing: int = Noneself.padding: int = Noneself.bgcolor: str = NoneScrollableControl specificself.scroll: ScrollMode = Noneself.auto_scroll: bool = Noneself.fullscreen_dialog: bool = Noneself.on_scroll_interval: int = Noneself.on_scroll = None🔐How to configure page access protection? (login)To do this we use thelogin_required()method that inherits from the ViewPage class, the configuration will only be done once.We useself.call.is_login = TrueRequires login to access the page (previously configured)classView(ViewPage):def__init__(self)->None:super().__init__()self.call.route='/login'# we assign a urlself.call.is_login=True# requires login to access the page (previously configured)# required login configurationdeflogin_required(self)->bool:super().login_required()class_login=Login()# import the login controller classadd_login_required=lambda:class_login.login()#We use the method of the class where the login configuration has been madereturnadd_login_required()# Returns login validation.# View general configurationdefbuild(self):self.call.page.title='Login'...............⚙️Useself.call.on_keyboard_eventOnce theViewPageattributes are inherited we can use them.🔎self.call.on_keyboard_eventIt has the following methods:add_control('<controller method>')Adds a controller configuration (controller method), which is executed with theon_keyboard_eventevent.def key()Returns the value entered by keyboard.def shift()Returns the value entered by keyboard.def ctrl()Returns the value entered by keyboard.def alt()Returns the value entered by keyboard.def meta()Returns the value entered by keyboard.def test()Returns a message of all the values ​​entered by keyboard. (key, Shift, Control, Alt, Meta)⚙️ Useself.call.on_resize🔎self.call.on_resizeIt has the following methods:controlsStores the checklist to be responseve.add_control('<control>', '<height>', '<max_height>')Add a control that will be a response when executing the 'on_resize' event.add_controls = '<lambda>'Stores an anonymous function.response('<'controls>')Configure the response of all controls.add_def_control = <lambda>Add a function that will be executed with theon_resizeevent, the function must be from thecontrollersfolder.Example:🗂️ In theviewsfolder of thetask.pyfiledefbuild(self):# ------# We configure all the values ​​of the page.page=self.call.page# we get all the values ​​of the page.page.title='test'# --------on_resize=self.call.on_resize# on_resize values ​​are obtainedon_keyboard=self.call.on_keyboard_event# the values ​​of on_keyboard_event are obtainedtask=ContentTask(on_resize,on_keyboard)# flet custom control# modify View properties : https://flet.dev/docs/controls/viewself.appbar.title=ft.Text('Task')self.controls=[task]Fletcustom controlclassContentTask(ft.UserControl):def__init__(self,on_resize:MyPageResize,on_keyboard:Mykeyboard):super().__init__()# We create an object of the controller class of this class, to be able to use its methods.self.new_control=ContentTaskC(self,on_resize,on_keyboard)self.on_keyboard=on_keyboard# the values ​​of on_keyboard_event are obtained# add a function to on_keyboard, which will be executed according to what is established in the function, it will be executed with keyboard input.self.on_keyboard.add_control(self.new_control.add_on_keyboard)self.on_resize=on_resize# on_resize values ​​are obtainedself.new_control.user_control=Task# # We send the class that we are going to use in the controller of this classself.input=ft.TextField(col=8,label='Enter the task',multiline=True,autocorrect=True,helper_text="'Alt'+'L' -> to add task",on_focus=self.new_control.update_input,)self.colum_task=ft.Column(scroll=ft.ScrollMode.ADAPTIVE)self.response_page=ft.Container(col={'sm':5},bgcolor=ft.colors.BLACK26,height=self.on_resize.height-80,padding=10,border_radius=10)self.response_task=ft.Container(col={'sm':11},bgcolor=ft.colors.BLACK12,height=self.on_resize.height-244,padding=10,border_radius=10,)# We add the controllers that are height responsive, if it is not displayed the page has to be reloaded (possible flet error)self.on_resize.add_control(self.response_page,80,420)self.on_resize.add_control(self.response_task,244,383)self.on_resize.add_controls=lambda:self.new_control.response(self.on_resize.controls)# we add all the controlsdefbuild(self):self.response_task.content=self.colum_taskself.response_page.content=ft.ResponsiveRow(controls=[ft.Text('Task',size=25,text_align=ft.TextAlign.CENTER),ft.ResponsiveRow(controls=[self.input,ft.FilledButton('ADD',col=4,on_click=self.new_control.add_task)],vertical_alignment=ft.CrossAxisAlignment.CENTER),self.response_task],alignment=ft.MainAxisAlignment.CENTER)returnft.ResponsiveRow(controls=[self.response_page],alignment=ft.MainAxisAlignment.CENTER,)🗂️In thecontrollersfolder of the task.py fileThe Fast-Flet MyController class contains the following inheriting attributes.self.call.model = NoneIt is assigned the class of the file.py in the models folder.self.call.on_resize = on_resizeIt is assigned the self.call.on_resize of the View class from the file.py in the views folder.self.call.on_keyboard_event = on_keyboardIt is assigned the self.call.on_keyboard_event of the View class in the .py file in the views folder.self.x = _selfThe custom control object is stored.self._user_control = NoneThe class that will be used in the custom control is stored.# view's ContentTask class handlerclassContentTaskC(MyController):def__init__(self,_self:object,on_resize:MyPageResize=None,on_keyboard=None)->None:super().__init__(_self,on_resize,on_keyboard)def_add_task(self):ifself.x.input.value!='':input_task=self.x.input.valuetask=self.user_control(self.delete,input_task,self.call.on_keyboard_event)self.x.colum_task.controls.append(task)self.x.input.value=''self.x.input.label='Enter a task'else:self.x.input.label='Enter a task please'self.x.input.border_color=ft.colors.REDself.x.update()sleep(2)self.x.input.border_color=Noneself.x.update()defadd_task(self,e):self._add_task()defdelete(self,task):self.x.colum_task.controls.remove(task)self.x.update()defupdate_input(self,e):self.x.input.border_color=Noneself.x.update()# used with keyboard inputdefadd_on_keyboard(self):keyboard=self.call.on_keyboard_eventifkeyboard.key()=='L'andkeyboard.alt():self._add_task()🔗Responsive of the page in terms of its height.In the previous example you can see the responsible use of the page height.self.response_page=ft.Container(col={'sm':5},bgcolor=ft.colors.BLACK26,height=self.on_resize.height-80,padding=10,border_radius=10)self.response_task=ft.Container(col={'sm':11},bgcolor=ft.colors.BLACK12,height=self.on_resize.height-244,padding=10,border_radius=10,)# We add the controllers that are height responsive, if it is not displayed the page has to be reloaded (possible flet error)self.on_resize.add_control(self.response_page,80,420)self.on_resize.add_control(self.response_task,244,383)self.on_resize.add_controls=lambda:self.new_control.response(self.on_resize.controls)# we add all the controls🔗 Links🔋Sample applications with Fast-Fletthreading(defectFlet)Async(withflet_fastapi)watch onlineLicenseApache License 2.0