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 PasswordScreen(Gtk.Box): def __init__( self, win, wiface, network_name, encryption, wrong_password=False ): ''' Show the screen with the option of adding a password and connecting to a network ''' Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL) self._win = win self._win.set_main_widget(self) self._win.top_bar.enable_prev() self._wiface = wiface self._network_name = network_name self._encryption = encryption # Keep track if the user has already entered the wrong password before # so that we only pack the "password incorrect" label once self._wrong_password_used_before = False self._heading = Heading( "Connect to the network", self._network_name, self._win.is_plug(), True ) self._heading.set_prev_callback(self._refresh_networks) self._heading.container.set_margin_right(20) self._heading.container.set_margin_left(20) if wrong_password: image_path = os.path.join(img_dir, "password-fail.png") wrong_password = self._create_wrong_password_label() self._heading.container.pack_start(wrong_password, True, True, 0) else: image_path = os.path.join(img_dir, "password.png") self._padlock_image = Gtk.Image.new_from_file(image_path) self._password_entry = Gtk.Entry() self._password_entry.set_placeholder_text("Password") self._password_entry.set_visibility(False) self._password_entry.get_style_context().add_class("password_entry") self._password_entry.set_margin_left(60) self._password_entry.set_margin_right(60) self._password_entry.connect("key-release-event", self._set_button_sensitive) # If Enter key is pressed on the password entry, we want to act as # though the connect_btn was clicked self._password_entry.connect( "key-release-event", self._on_connect_key_wrapper ) self._connect_btn = KanoButton("CONNECT") self._connect_btn.connect('clicked', self._on_connect) self._connect_btn.set_sensitive(False) self._connect_btn.set_margin_right(100) self._connect_btn.set_margin_left(100) self._connect_btn.pack_and_align() self._show_password = Gtk.CheckButton.new_with_label("Show password") self._show_password.get_style_context().add_class("show_password") self._show_password.connect("toggled", self._change_password_entry_visiblity) self._show_password.set_active(True) self._show_password.set_margin_left(100) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.add(vbox) vbox.pack_start(self._heading.container, False, False, 10) vbox.pack_start(self._padlock_image, False, False, 10) vbox.pack_start(self._password_entry, False, False, 10) vbox.pack_start(self._show_password, False, False, 10) vbox.pack_end(self._connect_btn.align, False, False, 40) # Entry should have the keyboard focus self._password_entry.grab_focus() self.show_all() def _create_wrong_password_label(self): label = Gtk.Label("Password incorrect") label.get_style_context().add_class("wrong_password_label") return label def _change_password_entry_visiblity(self, widget): ''' Depending on the checkbox, change the writing in the password entry to be readable. ''' visibility = self._show_password.get_active() self._password_entry.set_visibility(visibility) def _refresh_networks(self, widget=None): from kano_wifi_gui.RefreshNetworks import RefreshNetworks RefreshNetworks(self._win) def _on_connect_key_wrapper(self, widget, event): if event.keyval == Gdk.KEY_Return: self._on_connect() def _on_connect(self, widget=None): passphrase = self._password_entry.get_text() ConnectToNetwork( self._win, self._network_name, passphrase, self._encryption ) def _set_button_sensitive(self, widget, event): self._connect_btn.set_sensitive(True) def _thread_finish(self, success): if success: self._success_screen() else: self._wrong_password_screen() def _success_screen(self): self._win.remove_main_widget() title = "Success!" description = "You're connected" buttons = [ { "label": "OK", "color": "green", "type": "KanoButton", "callback": Gtk.main_quit } ] img_path = os.path.join(img_dir, "internet.png") self._win.set_main_widget( Template( title, description, buttons, self._win.is_plug(), img_path ) ) def _disable_widgets_start_spinner(self): self._connect_btn.start_spinner() self._connect_btn.set_sensitive(False) self._win.top_bar.prev_button.set_sensitive(False) self._password_entry.set_sensitive(False) self._show_password.set_sensitive(False) def _enable_widgets_stop_spinner(self): self._connect_btn.stop_spinner() self._connect_btn.set_sensitive(True) self._win.top_bar.prev_button.set_sensitive(True) self._password_entry.set_sensitive(True) self._show_password.set_sensitive(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 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()
class PasswordScreen(Gtk.Box): def __init__(self, win, wiface, network_name, encryption, wrong_password=False): ''' Show the screen with the option of adding a password and connecting to a network ''' Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL) self._win = win self._win.set_main_widget(self) self._win.top_bar.enable_prev() self._wiface = wiface self._network_name = network_name self._encryption = encryption # Keep track if the user has already entered the wrong password before # so that we only pack the "password incorrect" label once self._wrong_password_used_before = False self._heading = Heading(_("Connect to the network"), self._network_name, self._win.is_plug(), True) self._heading.set_prev_callback(self._refresh_networks) self._heading.container.set_margin_right(20) self._heading.container.set_margin_left(20) if wrong_password: image_path = os.path.join(img_dir, "password-fail.png") wrong_password = self._create_wrong_password_label() self._heading.container.pack_start(wrong_password, True, True, 0) else: image_path = os.path.join(img_dir, "password.png") self._padlock_image = Gtk.Image.new_from_file(image_path) self._password_entry = Gtk.Entry() self._password_entry.set_placeholder_text(_("Password")) self._password_entry.set_visibility(False) self._password_entry.get_style_context().add_class('password_entry') self._password_entry.set_margin_left(60) self._password_entry.set_margin_right(60) self._password_entry.connect('key-release-event', self._set_button_sensitive) # If Enter key is pressed on the password entry, we want to act as # though the connect_btn was clicked self._password_entry.connect('key-release-event', self._on_connect_key_wrapper) self._connect_btn = KanoButton(_("CONNECT")) self._connect_btn.connect('clicked', self._on_connect) self._connect_btn.set_sensitive(False) self._connect_btn.set_margin_right(100) self._connect_btn.set_margin_left(100) self._connect_btn.pack_and_align() self._show_password = Gtk.CheckButton.new_with_label( _("Show password")) self._show_password.get_style_context().add_class('show_password') self._show_password.connect('toggled', self._change_password_entry_visiblity) self._show_password.set_active(True) self._show_password.set_margin_left(100) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.add(vbox) vbox.pack_start(self._heading.container, False, False, 10) vbox.pack_start(self._padlock_image, False, False, 10) vbox.pack_start(self._password_entry, False, False, 10) vbox.pack_start(self._show_password, False, False, 10) vbox.pack_end(self._connect_btn.align, False, False, 40) # Entry should have the keyboard focus self._password_entry.grab_focus() self.show_all() def _create_wrong_password_label(self): label = Gtk.Label(_("Password incorrect")) label.get_style_context().add_class('wrong_password_label') return label def _change_password_entry_visiblity(self, widget): ''' Depending on the checkbox, change the writing in the password entry to be readable. ''' visibility = self._show_password.get_active() self._password_entry.set_visibility(visibility) def _refresh_networks(self, widget=None): from kano_wifi_gui.RefreshNetworks import RefreshNetworks RefreshNetworks(self._win) def _on_connect_key_wrapper(self, widget, event): if event.keyval == Gdk.KEY_Return: self._on_connect() def _on_connect(self, widget=None): passphrase = self._password_entry.get_text() ConnectToNetwork(self._win, self._network_name, passphrase, self._encryption) def _set_button_sensitive(self, widget, event): ''' Enable the Connect button only if the passphrase is non empty ''' self._connect_btn.set_sensitive(widget.get_text_length() > 0) def _thread_finish(self, success): if success: self._success_screen() else: self._wrong_password_screen() def _success_screen(self): self._win.remove_main_widget() title = _("Success!") description = _("You're connected") buttons = [{ 'label': _("OK"), 'color': 'green', 'type': 'KanoButton', 'callback': Gtk.main_quit }] img_path = os.path.join(img_dir, "internet.png") # Track that user connected online track_action('internet-connection-established') self._win.set_main_widget( Template(title, description, buttons, self._win.is_plug(), img_path)) def _disable_widgets_start_spinner(self): self._connect_btn.start_spinner() self._connect_btn.set_sensitive(False) self._win.top_bar.prev_button.set_sensitive(False) self._password_entry.set_sensitive(False) self._show_password.set_sensitive(False) def _enable_widgets_stop_spinner(self): self._connect_btn.stop_spinner() self._connect_btn.set_sensitive(True) self._win.top_bar.prev_button.set_sensitive(True) self._password_entry.set_sensitive(True) self._show_password.set_sensitive(True)