def second_scroll(self): self._clear() ticks = Gtk.Image.new_from_file(self._stage.media_path('ticks.png')) copy = ["Complete all of the ticks in a", "quest to unlock rewards."] text_widgets = self._get_text_widgets(copy) chest = Gtk.Image.new_from_file( self._stage.media_path('chest-open.png')) button = KanoButton('NEXT', color='orange') button.connect('clicked', cb_wrapper, self.third_scroll) ticks.set_margin_top(20) self._vbox.pack_start(ticks, False, False, 0) text_widgets[0].set_margin_top(40) for w in text_widgets: self._vbox.pack_start(w, False, False, 0) chest.set_margin_top(35) self._vbox.pack_start(chest, False, False, 0) button.set_margin_top(40) button.set_margin_left(80) button.set_margin_right(80) self._vbox.pack_start(button, False, False, 0) self.show_all()
def third_scroll(self): self._clear() heading = Gtk.Label('New quest') add_class(heading, 'scroll-heading') world = Gtk.Image.new_from_file(self._stage.media_path('world.png')) copy = [ "Journey to Kano World", ] text_widgets = self._get_text_widgets(copy) button = KanoButton('OK', color='orange') button.connect('clicked', cb_wrapper, self._stage._ctl.next_stage) heading.set_margin_top(35) self._vbox.pack_start(heading, False, False, 0) world.set_margin_top(35) self._vbox.pack_start(world, False, False, 0) text_widgets[0].set_margin_top(40) for w in text_widgets: self._vbox.pack_start(w, False, False, 0) button.set_margin_top(40) button.set_margin_left(80) button.set_margin_right(80) self._vbox.pack_start(button, False, False, 0) self.show_all()
def first_scroll(self): self._clear() copy = [ "Quests are a series of tasks that you", "can complete on your Kano to get", "great rewards." ] text_widgets = self._get_text_widgets(copy) img_path = self._stage.media_path('chest-closed.png') chest = Gtk.Image.new_from_file(img_path) button = KanoButton('NEXT', color='orange') button.connect('clicked', cb_wrapper, self.second_scroll) text_widgets[0].set_margin_top(30) for w in text_widgets: self._vbox.pack_start(w, False, False, 0) chest.set_margin_top(60) self._vbox.pack_start(chest, False, False, 0) button.set_margin_top(70) button.set_margin_left(80) button.set_margin_right(80) self._vbox.pack_start(button, False, False, 0) self.show_all()
def second_scroll(self): self._clear() ticks = Gtk.Image.new_from_file(self._stage.media_path('ticks.png')) copy = [ "Complete all of the ticks in a", "quest to unlock rewards." ] text_widgets = self._get_text_widgets(copy) chest = Gtk.Image.new_from_file(self._stage.media_path('chest-open.png')) button = KanoButton('NEXT', color='orange') button.connect('clicked', cb_wrapper, self.third_scroll) ticks.set_margin_top(20) self._vbox.pack_start(ticks, False, False, 0) text_widgets[0].set_margin_top(40) for w in text_widgets: self._vbox.pack_start(w, False, False, 0) chest.set_margin_top(35) self._vbox.pack_start(chest, False, False, 0) button.set_margin_top(40) button.set_margin_left(80) button.set_margin_right(80) self._vbox.pack_start(button, False, False, 0) self.show_all()
class AudioTemplate(Gtk.Box): """ Template for audio screens """ def __init__(self, img_path, title, description): Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL) if img_path: self.image = Gtk.Image.new_from_file(img_path) self.pack_start(self.image, False, False, 0) self.heading = Heading(title, description) icon_path = os.path.join(MEDIA_DIR, "play-sound.png") self.kano_button = KanoButton(text="PLAY SOUND", color="blue", icon_filename=icon_path) self.kano_button.pack_and_align() self.kano_button.set_margin_top(10) self.pack_start(self.heading.container, False, False, 0) self.pack_start(self.kano_button.align, False, False, 0) button_box = Gtk.ButtonBox(spacing=15) button_box.set_layout(Gtk.ButtonBoxStyle.CENTER) self.yes_button = KanoButton("YES") self.yes_button.set_sensitive(False) self.no_button = KanoButton("NO", color="red") self.no_button.set_sensitive(False) button_box.pack_start(self.yes_button, False, False, 0) button_box.pack_start(self.no_button, False, False, 0) button_box.set_margin_bottom(5) self.pack_start(button_box, False, False, 15)
class AudioHintTemplate(TopImageTemplate): """ Template for hints for audio setup """ def __init__(self, img_path, title, description, kano_button_text, hint_text=""): TopImageTemplate.__init__(self, img_path) self.heading = HintHeading(title, description, hint_text) self.pack_start(self.heading.container, False, False, 0) self.heading.description.set_margin_bottom(0) self.heading.container.set_margin_bottom(0) self.heading.container.set_size_request(590, -1) self.heading.container.set_spacing(0) self.kano_button = KanoButton(kano_button_text) self.kano_button.set_margin_top(30) self.kano_button.set_margin_bottom(30) self.kano_button.pack_and_align() self.pack_start(self.kano_button.align, False, False, 0)
class RegistrationScreen(Gtk.Box): """ """ def __init__(self, win): Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL) self.win = win self.win.set_main_widget(self) self.win.set_decorated(True) title = Heading(_("Kano World"), _("Choose a cool name and secure password")) self.pack_start(title.container, False, False, 0) self.data_screen = GetData() # TODO: refactor this self.data_screen.connect('widgets-filled', self._enable_register_button) self.data_screen.connect('widgets-empty', self._disable_register_button) self.add(self.data_screen) self.register_button = KanoButton(_("JOIN KANO WORLD")) self.register_button.set_sensitive(False) self.register_button.set_margin_top(10) self.register_button.set_margin_left(30) self.register_button.set_margin_right(30) self.register_button.set_margin_bottom(30) self.register_button.connect('clicked', self._on_register_button) self.pack_end(self.register_button, False, False, 0) self.win.show_all() def _enable_register_button(self, widget=None): """ """ self.register_button.set_sensitive(True) def _disable_register_button(self, widget=None): """ """ self.register_button.set_sensitive(False) def _on_register_button(self, widget=None): # TODO: refactor this """ """ if not is_internet(): self._show_not_internet_dialog() return # Get the username, password and birthday data = self.data_screen.get_widget_data() email = data['email'] username = data['username'] # Validate that the email address format is correct email_error = validate_email(email) if email_error: self._show_error_dialog(_("Incorrect Email address"), email_error) return if not self._is_username_available(username): self._show_username_taken_dialog(username) return # We can save the username to kano-profile # Don't save password as this is private self.data_screen.save_username_and_birthday() # TODO: rename this self.data_screen.cache_emails() data = self.data_screen.get_widget_data() # This means no threads are needed. while Gtk.events_pending(): # TODO: why is this needed? Gtk.main_iteration() # Try and register the account on the server password = data['password'] success, text = register_(email, username, password, marketing_enabled=True) # This should no longer be needed, since this is checked in the first # screen. However there is a small chance someone could take the # username while the user is in the process of registering if not success: if text.strip() == _("Cannot register, problem: " "Username already registered"): self._show_username_taken_dialog(username) else: logger.info("problem with registration: {}".format(text)) return_value = 'FAIL' self._create_dialog(title=_("Houston, we have a problem"), description=str(text)) track_data('world-registration-failed', {'reason': text}) else: logger.info("registration successful") # saving hardware info and initial Kano version save_hardware_info() save_kano_version() # running kano-sync after registration logger.info("running kano-sync after successful registration") cmd = '{bin_dir}/kano-sync --sync -s'.format(bin_dir=bin_dir) run_bg(cmd) return_value = 'SUCCEED' self._create_dialog( title=_("Profile activated!"), description=_("Now you can share stuff, build your character, " "and connect with friends.")) self.win.get_window().set_cursor(None) # Close the app if it was successful if return_value == 'SUCCEED': Gtk.main_quit() def _is_username_available(self, name): """ Returns True if username is available, and False otherwise """ # Use the endpoint api.kano.me/users/username/:name success, text, data = request_wrapper( 'get', '/users/username/{}'.format(name), headers=content_type_json) if not success and text.strip() == "User not found": return True elif success: # Username is definitely taken return False else: # Maybe let the user know something went wrong? e.g. if there's no # internet, launch a dialog at this point return False def _create_dialog(self, title, description): # TODO: refactor this kdialog = KanoDialog(title, description, parent_window=self.win) rv = kdialog.run() return rv def _show_error_dialog(self, title, description): # TODO: refactor this kdialog = KanoDialog(title, description, parent_window=self.win) kdialog.run() def _show_username_taken_dialog(self, username): # TODO: refactor this track_data('world-registration-username-taken', {'username': username}) kd = KanoDialog(_("This username is taken!"), _("Try another one"), parent_window=self.win) kd.run() self.data_screen.username.set_text("") self.data_screen.validate_username() self._disable_register_button() self.data_screen.username.grab_focus() def _show_not_internet_dialog(self): # TODO: refactor this kd = KanoDialog(_("You don't have internet"), _("Do you want to connect to WiFi?"), [{ 'label': _("YES"), 'color': 'green', 'return_value': 0 }, { 'label': _("NO"), 'color': 'red', 'return_value': 1 }], parent_window=self.win) response = kd.run() # Close the dialog while Gtk.events_pending(): # TODO: why is this needed? Gtk.main_iteration() if response == 0: subprocess.Popen("sudo kano-wifi-gui", shell=True)
class RegistrationScreen(Gtk.Box): """ """ def __init__(self, win): Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL) self.win = win self.win.set_main_widget(self) self.win.set_decorated(True) title = Heading( _("Kano World"), _("Choose a cool name and secure password") ) self.pack_start(title.container, False, False, 0) self.data_screen = GetData() # TODO: refactor this self.data_screen.connect('widgets-filled', self._enable_register_button) self.data_screen.connect('widgets-empty', self._disable_register_button) self.add(self.data_screen) self.register_button = KanoButton(_("JOIN KANO WORLD")) self.register_button.set_sensitive(False) self.register_button.set_margin_top(10) self.register_button.set_margin_left(30) self.register_button.set_margin_right(30) self.register_button.set_margin_bottom(30) self.register_button.connect('clicked', self._on_register_button) self.pack_end(self.register_button, False, False, 0) self.win.show_all() def _enable_register_button(self, widget=None): """ """ self.register_button.set_sensitive(True) def _disable_register_button(self, widget=None): """ """ self.register_button.set_sensitive(False) def _on_register_button(self, widget=None): # TODO: refactor this """ """ if not is_internet(): self._show_not_internet_dialog() return # Get the username, password and birthday data = self.data_screen.get_widget_data() email = data['email'] username = data['username'] # Validate that the email address format is correct email_error = validate_email(email) if email_error: self._show_error_dialog(_("Incorrect Email address"), email_error) return if not self._is_username_available(username): self._show_username_taken_dialog(username) return # We can save the username to kano-profile # Don't save password as this is private self.data_screen.save_username_and_birthday() # TODO: rename this self.data_screen.cache_emails() data = self.data_screen.get_widget_data() # This means no threads are needed. while Gtk.events_pending(): # TODO: why is this needed? Gtk.main_iteration() # Try and register the account on the server password = data['password'] success, text = register_(email, username, password, marketing_enabled=True) # This should no longer be needed, since this is checked in the first # screen. However there is a small chance someone could take the # username while the user is in the process of registering if not success: if text.strip() == _("Cannot register, problem: " "Username already registered"): self._show_username_taken_dialog(username) else: logger.info("problem with registration: {}".format(text)) return_value = 'FAIL' self._create_dialog( title=_("Houston, we have a problem"), description=str(text) ) track_data('world-registration-failed', {'reason': text}) else: logger.info("registration successful") # saving hardware info and initial Kano version save_hardware_info() save_kano_version() # running kano-sync after registration logger.info("running kano-sync after successful registration") cmd = '{bin_dir}/kano-sync --sync -s'.format(bin_dir=bin_dir) run_bg(cmd) return_value = 'SUCCEED' self._create_dialog( title=_("Profile activated!"), description=_("Now you can share stuff, build your character, " "and connect with friends.") ) self.win.get_window().set_cursor(None) # Close the app if it was successful if return_value == 'SUCCEED': Gtk.main_quit() def _is_username_available(self, name): """ Returns True if username is available, and False otherwise """ # Use the endpoint api.kano.me/users/username/:name success, text, data = request_wrapper( 'get', '/users/username/{}'.format(name), headers=content_type_json ) if not success and text.strip() == "User not found": return True elif success: # Username is definitely taken return False else: # Maybe let the user know something went wrong? e.g. if there's no # internet, launch a dialog at this point return False def _create_dialog(self, title, description): # TODO: refactor this kdialog = KanoDialog( title, description, parent_window=self.win ) rv = kdialog.run() return rv def _show_error_dialog(self, title, description): # TODO: refactor this kdialog = KanoDialog( title, description, parent_window=self.win ) kdialog.run() def _show_username_taken_dialog(self, username): # TODO: refactor this track_data('world-registration-username-taken', {'username': username}) kd = KanoDialog( _("This username is taken!"), _("Try another one"), parent_window=self.win ) kd.run() self.data_screen.username.set_text("") self.data_screen.validate_username() self._disable_register_button() self.data_screen.username.grab_focus() def _show_not_internet_dialog(self): # TODO: refactor this kd = KanoDialog( _("You don't have internet"), _("Do you want to connect to WiFi?"), [ { 'label': _("YES"), 'color': 'green', 'return_value': 0 }, { 'label': _("NO"), 'color': 'red', 'return_value': 1 } ], parent_window=self.win ) response = kd.run() # Close the dialog while Gtk.events_pending(): # TODO: why is this needed? Gtk.main_iteration() if response == 0: subprocess.Popen("sudo kano-wifi-gui", shell=True)
class BluetoothDeviceItem(Gtk.Box): __gsignals__ = { 'pairing': (GObject.SIGNAL_RUN_FIRST, GObject.TYPE_NONE, ()), 'done-pairing': (GObject.SIGNAL_RUN_FIRST, GObject.TYPE_NONE, ()), } def __init__(self, device): Gtk.Box.__init__(self, hexpand=True) self.device = device device_name = device.name dev_label = Gtk.Label(device_name, hexpand=True) dev_label.get_style_context().add_class('normal_label') self.pack_start(dev_label, False, False, 0) self._pair_button = KanoButton() self._set_paired_button_state() self._pair_button.set_margin_top(10) self._pair_button.set_margin_bottom(10) self._pair_button.set_margin_left(10) self._pair_button.set_margin_right(10) self._pair_button.connect('clicked', self.pair) self.pack_start(self._pair_button, False, False, 0) def _set_paired_button_state(self, *dummy_args, **dummy_kwargs): if not self.device.connected: label = _("PAIR") colour = 'green' else: label = _("UNPAIR") colour = 'red' self._pair_button.set_label(label) self._pair_button.set_color(colour) def error(self, err_msg): KanoDialog(err_msg).run() def pair(self, *dummy_args, **dummy_kwargs): def done_pairing(): self._set_paired_button_state() self.emit('done-pairing') @queue_cb(callback=done_pairing, gtk=True) def do_pair(): if not self.device.fuse(): GObject.idle_add(self.error, _("Pairing failed")) @queue_cb(callback=done_pairing, gtk=True) def do_unpair(): if not self.device.unfuse(): GObject.idle_add(self.error, _("Unpairing failed")) self.emit('pairing') if self.device.connected: pair_fn = do_unpair logger.info("Unpairing {}".format(self.device)) else: pair_fn = do_pair logger.info("Pairing {}".format(self.device)) pair_thr = threading.Thread(target=pair_fn) pair_thr.start()
def __init__(self, stage, next_cb): super(Notebook, self).__init__() self.add(Gtk.Image.new_from_file(stage.media_path('notebook.png'))) fixed = Gtk.Fixed() self.add_overlay(fixed) self._eb = Gtk.EventBox() add_class(self._eb, 'notebook-content-area') self._eb.set_size_request(425, 570) fixed.put(self._eb, 200, 90) vbox = Gtk.VBox(False, 0) vbox.set_vexpand(True) vbox.set_hexpand(True) vbox.set_margin_left(10) vbox.set_margin_right(10) heading = Gtk.Label('Screen machine') add_class(heading, 'heading') add_class(heading, 'notebook-heading') body_lines = [ "Use the up and down arrows on the", "keyboard to adjust the picture until the", "screen pushing machine lines up with the", "edges of your TV." ] body_widgets = [] for line in body_lines: body = Gtk.Label(line) body.set_line_wrap(False) body.set_justify(Gtk.Justification.LEFT) add_class(body, 'notebook-text') body.set_halign(Gtk.Align.START) body_widgets.append(body) # TODO: info legend_data = [ {'icon': 'up-icon.png', 'desc': 'on your keyboard to increase'}, {'icon': 'down-icon.png', 'desc': 'on your keyboard to decrease'}, {'icon': 'ok-icon.png', 'desc': 'click the button to confirm'} ] legend_widgets = [] for l in legend_data: legend = Gtk.HBox(False, 0) icon = Gtk.Image.new_from_file(stage.media_path(l['icon'])) desc = Gtk.Label(l['desc']) add_class(desc, 'notebook-text') legend.pack_start(icon, False, False, 0) legend.pack_start(desc, False, False, 10) legend_widgets.append(legend) button = KanoButton('GO') button.connect('clicked', cb_wrapper, next_cb) # Pack heading vbox.pack_start(heading, False, False, 10) heading.set_margin_bottom(20) for w in body_widgets: vbox.pack_start(w, False, False, 8) legend_widgets[0].set_margin_top(30) for w in legend_widgets: vbox.pack_start(w, False, False, 10) button.set_margin_top(30) vbox.pack_start(button, False, False, 0) self._eb.add(vbox)