Advertisement
Guest User

main.py

a guest
Feb 19th, 2023
28
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.14 KB | None | 0 0
  1. from kivy.lang import Builder
  2. from kivy.metrics import dp
  3. from kivy.core.text import LabelBase
  4. from kivymd.app import MDApp
  5. from kivymd.uix.widget import MDWidget
  6. from kivymd.uix.dialog import MDDialog
  7. from kivymd.uix.button import MDFlatButton
  8. from kivymd.uix.menu import MDDropdownMenu
  9. from kivymd.uix.transition import MDSlideTransition
  10. from kivymd.toast import toast
  11. from json import dump,load
  12. from pylatexenc.latex2text import LatexNodes2Text as LT
  13. import re
  14.  
  15. # importing font for math expressions
  16. LabelBase.register(
  17.     name="DejaVu",
  18.     fn_regular="DejaVuSansCondensed.ttf"
  19. )
  20.  
  21. # Main Class
  22. class MainBaseApp(MDApp):
  23.     # method to make dropdown menus
  24.     def make_dropdown(self,names,funcs,caller):
  25.         items = [{"viewclass":"OneLineListItem","text": i,"halign": "center","height": dp(54),"on_release": j}for i,j in zip(names,funcs)]
  26.         menu = MDDropdownMenu(
  27.             caller=caller,
  28.             items=items,
  29.             width_mult=2.5
  30.         )
  31.         return menu
  32.     # method to switch themes
  33. ## TODO: add this (full) to settings screen
  34.     def decide_colors(self,style):
  35.         if style == "Dark":
  36.             res = ["Dark","DeepOrange","#070707","#bcbcbc","#a3a3a380","#f0f0f080"]
  37.         else:
  38.             res = ["Light","Green","#e8e8e8","#303030","#363636","#07070780"]
  39.         return res
  40.     # method to reset converter screens
  41.     # (is needed)
  42.     # this may go on settings as :
  43.     #Switch: Keep result from different conversions
  44.     def init_convers(self,which):
  45.         self.current = self.convs[which]
  46.         a = [i for i in self.current.keys()]
  47.         self.screen.ids.first.text = a[0]
  48.         self.screen.ids.second.text = a[0]
  49.         self.screen.ids.input_label.text = "0"
  50.         self.screen.ids.output_label.text = "0"
  51.        
  52.         self.first_menu = self.make_dropdown(
  53.             self.current.keys(),
  54.             [lambda x=i:self.change_label(x,1)for i in self.current],
  55.             self.screen.ids.first
  56.         )
  57.         self.second_menu = self.make_dropdown(
  58.             self.current.keys(),
  59.             [lambda x=i:self.change_label(x,0)for i in self.current],
  60.             self.screen.ids.second
  61.         )
  62.     # initializing the class
  63.     def __init__(self, **kwargs):
  64.         # check the main buttons layout
  65.         self.main_switched = False
  66.         # latex engine
  67.         self.lt = LT()
  68.         # setting up parent class (is needed)
  69.         super().__init__(**kwargs)
  70.         # default theme (the only point responsible for theming)
  71.         self.colors = self.decide_colors("Darky")
  72.         # loading the file responsible for the hierarchy of widgets
  73.         self.screen = Builder.load_file("main.kv")
  74.         self.theme_cls.theme_style = self.colors[0]
  75.         self.theme_cls.primary_palette = self.colors[1]
  76.         # loading conversion coefficients
  77.         with open('conversions.json','r') as f:
  78.             self.convs = load(f)
  79.         self.exit_dialog = None
  80.         # default screen (changable)
  81.         self.curr_main = "main_scr"
  82.         self.exit_menu = self.make_dropdown(
  83.             ["Cilësimet","Rreth","Dil"],
  84.             [
  85.                 lambda x="Settings":self.menu_callback(x),
  86.                 lambda x="About":self.menu_callback(x),
  87.                 lambda x="Quit":self.menu_callback(x)
  88.             ],
  89.             self.screen.ids.menu_caller)
  90.  
  91.     # this is needed (builds up the whole program)
  92.     def build(self):
  93.         return self.screen
  94.     # method to response `exit_menu` events
  95.     def menu_callback(self,call):
  96.         if call=="Settings":
  97.             self.root.ids.my_toolbar.opacity = 0
  98.             self.root.ids.my_toolbar.disabled = True
  99.             self.change_screen("settings_scr")
  100.         if call=="About":
  101.             self.root.ids.my_toolbar.opacity = 0
  102.             self.root.ids.my_toolbar.disabled = True
  103.             self.change_screen("about_scr")
  104.         if call=="Quit":
  105.             self.dialog()
  106.         self.exit_menu.dismiss()
  107.     # method to change screens (prime ones)
  108.     # also applying effects
  109.     def change_screen(self,screen):
  110.         color = self.colors[4]
  111.         current = self.root.ids.manager.current
  112.         if screen == "main_scr":
  113.             self.root.ids.main_btn.icon_color = self.theme_cls.primary_color
  114.             self.root.ids.conv_btn.icon_color = color
  115.             self.root.ids.curr_btn.icon_color = color
  116.             if current=="about_scr":
  117.                 self.root.ids.my_toolbar.opacity = 1
  118.                 self.root.ids.my_toolbar.disabled = False
  119.             if current=="settings_scr":
  120.                 self.root.ids.my_toolbar.opacity = 1
  121.                 self.root.ids.my_toolbar.disabled = False
  122.         elif screen == "converter_scr":
  123.             self.root.ids.main_btn.icon_color = color
  124.             self.root.ids.conv_btn.icon_color = self.theme_cls.primary_color
  125.             self.root.ids.curr_btn.icon_color = color
  126.         elif screen == "currency_scr":
  127.             self.root.ids.main_btn.icon_color = color
  128.             self.root.ids.conv_btn.icon_color = color
  129.             self.root.ids.curr_btn.icon_color = self.theme_cls.primary_color
  130.         self.root.ids.manager.current = screen
  131.     # this also changes screens, but is used only for converters
  132.     # TODO: add statements to change on unpure conversions
  133.     def change_screen1(self,t):
  134.         if t=="bases":
  135.             self.root.ids.manager.current = "bases-convy"
  136.             self.screen.ids.bases_first.text = "dec"
  137.             self.screen.ids.bases_second.text = "dec"
  138.             self.bases_first_menu = self.make_dropdown(
  139.             ["Binar","Oktal","Decimal","Hexadecimal"],
  140.             [lambda x=i:self.change_label(x,1)for i in ["bin","oct","dec","hex"]],
  141.             self.screen.ids.bases_first
  142.         )
  143.             self.bases_second_menu = self.make_dropdown(
  144.             ["Binar","Oktal","Decimal","Hexadecimal"],
  145.             [lambda x=i:self.change_label(x,0)for i in ["bin","oct","dec","hex"]],
  146.             self.screen.ids.bases_second
  147.         )
  148.         else:
  149.             self.init_convers(t)
  150.             self.root.ids.manager.current = "convy"
  151.     # this shows a toast
  152.     # TODO: fond a use for it
  153.     def show_toast(self,text):
  154.         toast(text)
  155.     # inserting values from buttons to input labels
  156.     def insert_value(self,val):
  157.         d = self.screen.ids.manager.current
  158.         print(d,val)
  159.         if d=="main_scr":
  160.             c = self.root.ids.the_input.text
  161.             if c=='0' and val!='.':
  162.                 self.root.ids.the_input.text = val
  163.             else:
  164.                 z = ([1,0][len(i)>2]for i in (i.split('.')for i in re.split('[^0-9.-]',c)))
  165.                 if not all(z):
  166.                     return
  167.                 self.root.ids.the_input.text = c+val
  168.         elif d=="convy":
  169.             c = self.root.ids.input_label.text
  170.             if c=='0' and val!='.':
  171.                 self.root.ids.input_label.text = val
  172.             else:
  173.                 z = ([1,0][len(i)>2]for i in (i.split('.')for i in re.split('[^0-9.-]',c)))
  174.                 if not all(z):
  175.                     return
  176.                 self.root.ids.input_label.text = c+val
  177.         elif d=="bases-convy":
  178.             c = self.root.ids.bases_input_label.text
  179.             if c == "0":
  180.                 self.root.ids.bases_input_label.text = val
  181.             else:
  182.                 self.root.ids.bases_input_label.text = c+val
  183.     # the `C` button functionality
  184.     def clear_input(self):
  185.         c = self.root.ids.manager.current
  186.         if c == "main_scr":
  187.             self.root.ids.the_input.text = "0"
  188.         elif c == "convy":
  189.             self.root.ids.input_label.text = "0"
  190.             self.root.ids.output_label.text = "0"
  191.         elif c == "bases-convy":
  192.             self.root.ids.bases_input_label.text = "0"
  193.             self.root.ids.bases_output_label.text = "0"
  194.     # this pops one char from inputs
  195.     def backspace(self):
  196.         c = self.root.ids.manager.current
  197.         if c == "main_scr":
  198.             d = self.root.ids.the_input.text
  199.             self.root.ids.the_input.text = d[:-1] if len(d)>1 else "0"
  200.         elif c == "convy":
  201.             d = self.root.ids.input_label.text
  202.             self.root.ids.input_label.text = d[:-1] if len(d)>1 else "0"
  203.         elif c == "bases-convy":
  204.             d = self.root.ids.bases_input_label.text
  205.             self.root.ids.bases_input_label.text = d[:-1] if len(d)>1 else "0"
  206.  
  207.     # here I am using `eval` because there cannot be vulnerabilities using numbers only
  208.     # P.S. I may be wrong
  209.     def evaluate(self):
  210.         c = self.root.ids.the_input.text
  211.         try:
  212.             r = eval(c)
  213.             self.root.ids.the_input.text = f'{r:,}'
  214.         except:
  215.             pass
  216.     # this is the `exit_dialog` formation
  217.     def dialog(self):
  218.         def dfunc(n):
  219.             if n:
  220.                 exit()
  221.             else:
  222.                 self.exit_dialog.dismiss(force=True)
  223.             self.exit_dialog = None
  224.         if not self.exit_dialog:
  225.             self.exit_dialog = MDDialog(text="Të dal tani ?",buttons=[MDFlatButton(text="ANULLO",theme_text_color="Custom",text_color=self.theme_cls.primary_color,on_release=lambda x:dfunc(0)),MDFlatButton(text="PO",theme_text_color="Custom",text_color=self.theme_cls.primary_color,on_release=lambda x:dfunc(1))],radius=[20,20,20,20])
  226.             self.exit_dialog.open()
  227.     # converting pure units (convert screen only)
  228.     def convert(self):
  229.         fromUnit = self.screen.ids.first.text
  230.         toUnit = self.screen.ids.second.text
  231.         f = self.current[fromUnit]
  232.         t = self.current[toUnit]
  233.         # here I do two operations without considering the types of units
  234.         # so they can be the same, one-way or impossibe conversions
  235.         r = str((float(self.screen.ids.input_label.text)/f)*t)
  236.         self.screen.ids.output_label.text = r
  237.    
  238.     # this is used to convert a number from given base to another
  239.     def conv_bases(self):
  240.         n = self.screen.ids.bases_input_label.text
  241.         f = self.screen.ids.bases_first.text
  242.         t = self.screen.ids.bases_second.text
  243.         a={"bin":2,"oct":8,"dec":10,"hex":16}.get(f,10)
  244.         b={"bin":bin,"oct":oct,"dec":int,"hex":hex}.get(t,int)
  245.         try:
  246.             to_dec = int(n,a)
  247.             to_other = str((lambda x:x(to_dec))(b))
  248.         except Exception as e:
  249.             self.show_toast(e)
  250.             return
  251.         if any(to_other.count(i)for i in'box'):
  252.             to_other = to_other[2:]
  253.         self.screen.ids.bases_output_label.text = to_other
  254.     # used to adapt menus' texts upon unit choosing
  255.     def change_label(self,unit,w):
  256.         if self.root.ids.manager.current!="bases-convy":
  257.             if w:
  258.                 self.screen.ids.first.text = unit
  259.                 self.first_menu.dismiss()
  260.             else:
  261.                 self.screen.ids.second.text = unit
  262.                 self.second_menu.dismiss()
  263.         else:
  264.             if w:
  265.                 self.screen.ids.bases_first.text = unit
  266.                 self.bases_first_menu.dismiss()
  267.             else:
  268.                 self.screen.ids.bases_second.text = unit
  269.                 self.bases_second_menu.dismiss()
  270.  
  271. if __name__ in ["__main__","__android__"]:
  272.     MainBaseApp().run()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement