class MyGrid(GridLayout): def __init__(self, **kwargs): super(MyGrid, self).__init__(**kwargs) self.rows=2 self.cols=1 Window.clearcolor = (0.502, 0.8196, 1, 0.98) self.cbot = chat.chatBot() self.layout = GridLayout(cols=1, spacing=10, size_hint_y=None) self.bottom = GridLayout(cols=2, spacing=3, size_hint=(1,0.15)) self.root = ScrollView(size_hint=(1, 0.85)) self.layout.bind(minimum_height=self.layout.setter('height')) l = WrappedLabel(text='Hello! How are you doing? (type bye anytime to stop)', size_hint=(1, None), padding=(5, 5), color=[0,0,0,1]) self.layout.add_widget(l) self.root.add_widget(self.layout) self.textbox = TextInput(text='type here...', size_hint=(0.8, None)) self.btn = Button(text='send', size_hint_x=None, width=75) self.btn.bind(on_press=self.pressed) self.bottom.add_widget(self.textbox) self.bottom.add_widget(self.btn) self.add_widget(self.root) self.add_widget(self.bottom) def pressed(self, instance): t = '| ' + self.textbox.text nlabel = WrappedLabel(text = t, size_hint=(1, None), padding=(5, 5), color=[1,1,1,1]) self.layout.add_widget(nlabel) self.root.scroll_to(nlabel) out = self.cbot.chat(t) nlabel2 = WrappedLabel(text=out, size_hint=(1, None), padding=(5, 5), color=[0,0,0,1]) self.layout.add_widget(nlabel2) self.root.scroll_to(nlabel2) self.textbox.text = ""
class Screen4u(MDScreen, Image): def __init__(self, **kwargs): super(MDRaisedButton).__init__(**kwargs) super().__init__(**kwargs) self.i = Image() self.incoming = MDFillRoundFlatButton() self.msg = MDFillRoundFlatButton() self.incoming_text = MDLabel() self.text_msg = MDLabel() self.Box = MDBoxLayout() self.count = 0 self.count_the_length = 0 self.screen = MDGridLayout( cols=1, rows=2, md_bg_color=hex8("#00ffff"), size_hint=[1, 1]) self.size = [1, 1] self.Scroll = ScrollView() self.Scroll.scroll_type = ["content", "bars"] self.Scroll.bar_color = hex8("#000000") self.Scroll.bar_width = "5dp" self.text = TextInput( font_name="Default.ttf", size_hint=[1, 1], font_size=23, multiline=False) self.button = MDRaisedButton( size_hint=[0.124, 0.124], font_name="Arial", on_press=lambda message:self.send_it(self.text.text)) self.button.md_bg_color = hex8("#ff00ff") self.button.text = "send" self.button.text_color = hex8("#000000") self.Top = MDGridLayout( cols=2, rows=1, md_bg_color=hex8("#00ffff"), size_hint_x=1, size_hint_y=1, minimum_height=20) self.Container = MDBoxLayout( md_bg_color=hex8("#00ffff"), orientation="vertical", width=self.screen.width, height=self.screen.height) self.Bot = MDBoxLayout( md_bg_color=hex8("##00ffff"), orientation="vertical", width=self.screen.width, height=self.screen.height) self.bottom = MDGridLayout( cols=2, rows=1, md_bg_color=hex8("#00ffff"), width=200, height=200, size_hint=[.07, .07]) self.bottom.add_widget(self.text) self.bottom.add_widget(self.button) self.Top.add_widget(self.Container) self.Top.add_widget(self.Bot) self.Scroll.size = [self.screen.width, self.screen.height] self.Scroll.add_widget(self.Top) self.screen.add_widget(self.Scroll) self.screen.add_widget(self.bottom) self.add_widget(self.screen) def send_it(self, message): self.count += 1 br = Bot_Response() text = f"{self.text.text}" abc = br.respond(text) self.text_msg.color = hex8("#000000") self.text_msg.text = message self.text_msg.pos_hint = [0.5, 0.5] self.text_msg.halign = "center" self.text_msg.valign = "middle" self.text_msg.font_size = "17dp" if len(self.text.text) < 70 else '10dp' self.text_msg.texture_update() self.text_msg.text_size = self.width, None self.texture = self.text_msg.texture self.msg.md_bg_color = hex8("#ffff00") self.msg.size_hint_x = 1 self.msg.height = 243 self.msg.padding = "3dp" self.msg.add_widget(self.text_msg) emp = Widget() emp.size_hint_x = 1 emp.height = 0.5 sound.play() if self.count >= 1: print(self.count) self.Container.add_widget(self.msg) self.Container.add_widget(emp) self.response(abc) return self.count def response(self, query): self.incoming_text.color = hex8("#000000") self.incoming_text.text = query self. incoming_text.halign = "center" self.incoming_text.valign = "middle" self.incoming_text.pos_hint = [0.5, 0.5] self.incoming_text.font_size = "17dp" if len(self.text.text) < 70 else '10dp' self.incoming_text.texture_update() self.incoming_text.text_size = self.width, None self.texture = self.incoming_text.texture self.incoming.md_bg_color = hex8("#ffff00") self.incoming.size_hint_x = 1 self.incoming.height = 243 self.incoming.padding = "3dp" self.incoming.add_widget(self.incoming_text) emp2 = Widget() emp2.size_hint_x = 1 emp2.height = 0.5 self.Top.size_hint_y = len(range(self.count)) self.Bot.add_widget(emp2) self.Bot.add_widget(self.incoming) self.Container.height = self.text_msg.size_hint_y self.Bot.width = self.incoming_text.size_hint_y self.Scroll.scroll_to(self.incoming) sound.play()
def filesync(self): """Callback when the user presses the Sync button. This relies on keyless ssh working, and does most of the work in shell scripts.""" Logger.info('Config: filesync') # set up a popup containing a scrollview to contain stdout output layout = GridLayout(cols=1, spacing=1, padding=1, size_hint_y=None) layout.bind(minimum_height=layout.setter('height')) popup = Popup(title='Sync', size_hint=(0.8, 1)) sv = ScrollView(size_hint=(1, 1)) sv.add_widget(layout) popup = Popup(title='Sync', content=sv, size_hint=(0.8, 1)) popup.open() # temp file for the rsync, probably a better way to do this # this file describes exactly what songs should exist on the host, no more, no less tpath = os.path.join(self.config.get('paths', 'tmppath'), "rsync.inc") # look in the ini file for all the relevant paths synchost = self.config.get('sync', 'synchost') syncbasepath = self.config.get('sync', 'syncmusicpath') syncfanartpath = self.config.get('sync', 'syncfanartpath') basepath = self.config.get('paths', 'musicpath') fanartpath = self.config.get('paths', 'fanartpath') Logger.info('Filesync: Copying rsync file to carpi') # TODO: figure out why this doesn't show up on the screen until after the os.walk has completed l = OutlineLabel(text='Copying rsync file to carpi', size_hint=(None, None), font_size='12sp', halign='left') l.bind(texture_size=l.setter('size')) layout.add_widget(l) sv.scroll_to(l) # copy the rsync file from the synchost # TODO: implement this using python instead of call call(["scp", synchost + ":rsync.inc", tpath]) filelist = {} # use codecs.open to ensure the file is read as utf8, otherwise special chars can be mangled with codecs.open(tpath, 'r', 'utf-8') as f: for line in f: # add each filename to a dict for easy searching later filelist[Helpers.decodeFileName(line.rstrip())] = True Logger.info('Filesync: Removing old files from carpi') # TODO: figure out why this doesn't show up on the screen until after the os.walk has completed l = OutlineLabel(text='Removing old files from carpi', size_hint=(None, None), font_size='12sp', halign='left') l.bind(texture_size=l.setter('size')) layout.add_widget(l) sv.scroll_to(l) # this whole block walks the filesystem and deletes any file that is not in the rsync file # the sync operation is split up into a delete and a copy because that was the only way I could get # rsync to work correctly, it was always copying/deleting the wrong things otherwise for dirpath, dirnames, filenames in os.walk( Helpers.decodeFileName(basepath)): if len(filenames) > 0: rpath = dirpath[len(basepath + os.sep):] for filename in filenames: fpath = os.path.join(Helpers.decodeFileName(rpath), Helpers.decodeFileName(filename)) apath = os.path.join(Helpers.decodeFileName(dirpath), Helpers.decodeFileName(filename)) if fpath not in filelist: Logger.debug("Filesync: Deleting " + apath) os.remove(Helpers.decodeFileName(apath)) # TODO: somehow do this all in python instead of shell script, it's ugly # also, if the host somehow has tmppath mounted with the no-execute bit set, this will fail with open(os.path.join(self.config.get('paths', 'tmppath'), 'sync.sh'), 'w') as sfile: sfile.write("#!/bin/bash\n") # delete all empty directories sfile.write('find "' + basepath + '" -type d -empty -delete 2>/dev/null\n') # copy/update only the files that exist in the rsync file sfile.write('rsync -vruxhm --files-from="' + tpath + '" ' + synchost + ':"' + syncbasepath + '"/ "' + basepath + '"\n') # copy the car sticker database to the synchost sfile.write('scp /var/lib/mpd/sticker.sql ' + synchost + ':' + self.config.get('sync', 'synctmppath') + '\n') # build a secondary shell script to perform the sticker update on the synchost with open( os.path.join(self.config.get('paths', 'tmppath'), 'scmd'), 'w') as f: # attach the copied database and merge sticker data from it to update ratings user has added in the car # not using os.path.join here since who knows what os the synchost uses...use linux f.write("attach database \"" + self.config.get('sync', 'synctmppath') + "/sticker.sql\" as carpi;\n") f.write("replace into sticker select * from carpi.sticker;\n") f.write( "replace into carpi.sticker select * from sticker where name='rating';\n" ) f.write(".quit\n") # copy secondary script to synchost and run it sfile.write( 'scp ' + os.path.join(self.config.get('paths', 'tmppath'), 'scmd') + ' ' + synchost + ':' + self.config.get('sync', 'synctmppath') + '\n') # not using os.path.join here since who knows what os the synchost uses...use linux sfile.write('ssh -t ' + synchost + ' sudo sqlite3 /var/lib/mpd/sticker.sql < ' + self.config.get('sync', 'synctmppath') + '/scmd\n') # copy the now updated sticker database back from the synchost # not using os.path.join here since who knows what os the synchost uses...use linux sfile.write('scp ' + synchost + ':' + self.config.get('sync', 'synctmppath') + '/sticker.sql ' + self.config.get('paths', 'tmppath') + '\n') # build a secondary shell script to perform the sticker update on the host with open( os.path.join(self.config.get('paths', 'tmppath'), 'scmd'), 'w') as f: # attach the copied database and merge sticker data from it to update ratings user has added at home f.write("attach database \"" + os.path.join( self.config.get('paths', 'tmppath'), "sticker.sql") + "\" as carpi;\n") f.write("replace into sticker select * from carpi.sticker;\n") f.write(".quit\n") # run the secondary script sfile.write( 'cat ' + os.path.join(self.config.get('paths', 'tmppath'), 'scmd') + ' | sudo sqlite3 /var/lib/mpd/sticker.sql\n') # rsync over all the fanart sfile.write('rsync -vruxhm ' + synchost + ':"' + syncfanartpath + '"/ "' + fanartpath + '"\n') # tell mpd about any changes sfile.write("mpc update\n") # make the shell script executable os.chmod( os.path.join(self.config.get('paths', 'tmppath'), 'sync.sh'), os.stat( os.path.join(self.config.get('paths', 'tmppath'), 'sync.sh')).st_mode | 0111) # queue for holding stdout q = Queue() # create a subprocess for the shell script and capture stdout p = Popen( [os.path.join(self.config.get('paths', 'tmppath'), 'sync.sh')], stdout=PIPE, bufsize=1, close_fds=True) # check the stdout queue every .1 seconds and write lines to the scrollview if there is output event = Clock.schedule_interval( partial(self.write_queue_line, q, layout, sv), 0.1) # run all this crap in a separate thread to be non-blocking t = Thread(target=self.enqueue_output, args=(p.stdout, q, event, popup, tpath, synchost, layout, sv)) t.daemon = True t.start()
def scroll_to(self, widget): for i in range(0, len(self.children)): object_name = re.search('(?<=\.)[A-z0-9]+(?= )', str(self.children[i])).group(0) if object_name == 'PasswordsList': ScrollView.scroll_to(self.children[i].ids.scroll, widget)