Publish Vulpes Preview 15 sources for desktop, Android and Tundra

Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View file

@ -0,0 +1,35 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import time
from marionette_driver import expected, By, Wait
from gaiatest.apps.base import Base
class CropView(Base):
_src = 'app://gallery.gaiamobile.org/index.html#pick'
_crop_done_button_locator = (By.ID, 'crop-done-button')
_edit_preview_canvas_locator = (By.ID, 'edit-preview-canvas')
def __init__(self, marionette):
Base.__init__(self, marionette)
Wait(self.marionette).until(expected.element_displayed(
Wait(self.marionette).until(expected.element_present(
*self._edit_preview_canvas_locator))))
# I have tried waiting for all the elements in the UI, but the crash
# still occurs so the only solution I found was the hardcoded sleep - Bug 1111981
time.sleep(3)
done = self.marionette.find_element(*self._crop_done_button_locator)
Wait(self.marionette).until(expected.element_enabled(done))
def tap_crop_done(self):
element = self.marionette.find_element(*self._crop_done_button_locator)
self.tap_element_from_system_app(element)
# Fall back to the app underneath
Wait(self.marionette).until(lambda m: self.apps.displayed_app.src != self._src)
self.apps.switch_to_displayed_app()

View file

@ -0,0 +1,73 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from marionette_driver import expected, By, Wait
from gaiatest.apps.base import Base
from gaiatest.apps.base import PageRegion
class EditPhoto(Base):
_canvas_locator = (By.ID, 'edit-preview-canvas')
_edit_effect_button_locator = (By.ID, 'edit-effect-button')
_effect_options_locator = (By.CSS_SELECTOR, '#edit-effect-options a')
_edit_save_locator = (By.ID, 'edit-save-button')
_edit_crop_button_locator = (By.ID, 'edit-crop-button')
_crop_portrait_locator = (By.ID, 'edit-crop-aspect-portrait')
_save_progress_bar_locator = (By.ID, 'save-progress')
_edit_tool_apply_button_locator = (By.ID, 'edit-tool-apply-button')
def __init__(self, marionette):
Base.__init__(self, marionette)
# <canvas> is dynamically inserted
Wait(self.marionette).until(expected.element_displayed(
Wait(self.marionette).until(expected.element_present(
*self._canvas_locator))))
def tap_edit_effects_button(self):
self.marionette.find_element(*self._edit_effect_button_locator).tap()
Wait(self.marionette).until(expected.element_displayed(
Wait(self.marionette).until(expected.element_present(
*self._effect_options_locator))))
def tap_edit_crop_button(self):
self.marionette.find_element(*self._edit_crop_button_locator).tap()
Wait(self.marionette).until(expected.element_displayed(
Wait(self.marionette).until(expected.element_present(
*self._crop_portrait_locator))))
def tap_edit_tool_apply_button(self):
element = Wait(self.marionette).until(
expected.element_present(*self._edit_tool_apply_button_locator))
Wait(self.marionette).until(expected.element_displayed(element))
element.tap()
def tap_edit_save_button(self):
element = Wait(self.marionette).until(
expected.element_present(*self._edit_save_locator))
Wait(self.marionette).until(expected.element_displayed(element))
element.tap()
progress = self.marionette.find_element(*self._save_progress_bar_locator)
Wait(self.marionette).until(expected.element_not_displayed(progress))
from gaiatest.apps.gallery.regions.fullscreen_image import FullscreenImage
return FullscreenImage(self.marionette)
def tap_portrait_crop(self):
element = Wait(self.marionette).until(
expected.element_present(*self._crop_portrait_locator))
Wait(self.marionette).until(expected.element_displayed(element))
element.tap()
Wait(self.marionette).until(lambda m: 'selected' in element.get_attribute('class'))
@property
def effects(self):
return [self.Effect(marionette=self.marionette, element=effect)
for effect in self.marionette.find_elements(*self._effect_options_locator)]
class Effect(PageRegion):
def tap(self):
self.root_element.tap()
Wait(self.marionette).until(lambda m: 'selected' in self.root_element.get_attribute('class'))

View file

@ -0,0 +1,120 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from marionette_driver import expected, By, Wait
from marionette_driver.marionette import Actions
from gaiatest.apps.base import Base
class FullscreenImage(Base):
'''
This is not the actual image file - it is a blob of the image file in storage
'''
_current_image_locator = (By.CSS_SELECTOR, '#frames .current > .image-view')
_current_frame_locator = (By.CSS_SELECTOR, '#frames .current')
_photos_toolbar_locator = (By.ID, 'fullscreen-toolbar')
_delete_image_locator = (By.ID, 'fullscreen-delete-button-tiny')
_confirm_delete_locator = (By.ID, 'confirm-ok')
_edit_photo_locator = (By.ID, 'fullscreen-edit-button-tiny')
_go_back_locator = (By.ID, 'fullscreen-back-button-tiny')
_camera_locator = (By.ID, 'fullscreen-camera-button-tiny')
_photo_toolbar_options_locator = (By.CSS_SELECTOR, '#fullscreen-toolbar > a')
# for camera app switch
_loading_screen_locator = (By.CSS_SELECTOR, '.loading-screen')
def __init__(self, marionette):
Base.__init__(self, marionette)
Wait(self.marionette).until(expected.element_displayed(
Wait(self.marionette).until(expected.element_present(
*self._current_image_locator))))
Wait(self.marionette).until(lambda m: self.marionette.find_element(*self._current_image_locator).get_attribute('src') != '')
@property
def is_photo_toolbar_displayed(self):
return self.marionette.find_element(*self._photos_toolbar_locator).is_displayed()
@property
def current_image_source(self):
return self.marionette.find_element(*self._current_image_locator).get_attribute('src')
@property
def current_image_size_width(self):
return self.marionette.find_element(*self._current_image_locator).size['width']
@property
def current_image_size_height(self):
return self.marionette.find_element(*self._current_image_locator).size['height']
@property
def current_image_frame(self):
return self.marionette.find_element(*self._current_frame_locator)
def flick_to_next_image(self):
self._flick_to_image('next')
def flick_to_previous_image(self):
self._flick_to_image('previous')
def _flick_to_image(self, direction):
image = self.marionette.find_element(*self._current_image_locator)
action = Actions(self.marionette)
x_start = (image.size['width'] / 100) * (direction == 'next' and 90 or 10)
x_end = (image.size['width'] / 100) * (direction == 'next' and 10 or 90)
y_start = image.size['height'] / 4
y_end = image.size['height'] / 4
action.flick(image, x_start, y_start, x_end, y_end, 200).perform()
Wait(self.marionette).until(
lambda m: abs(image.location['x']) >= image.size['width'])
# Workaround for bug 1161441, the transitionend event is not firing in this
# case with a Marionette flick action, as opposed to a manual flick action
self.marionette.execute_script("""
arguments[0].dispatchEvent(new CustomEvent("transitionend"));
""", [self.current_image_frame])
def tap_delete_button(self):
self.marionette.find_element(*self._delete_image_locator).tap()
Wait(self.marionette).until(expected.element_displayed(*self._confirm_delete_locator))
def tap_confirm_deletion_button(self):
element = self.marionette.find_element(*self._confirm_delete_locator)
element.tap()
Wait(self.marionette).until(expected.element_not_displayed(element))
def tap_edit_button(self):
self.marionette.find_element(*self._edit_photo_locator).tap()
from gaiatest.apps.gallery.regions.edit_photo import EditPhoto
return EditPhoto(self.marionette)
def go_back(self):
element = self.marionette.find_element(*self._go_back_locator)
element.tap()
Wait(self.marionette).until(expected.element_not_displayed(element))
from gaiatest.apps.gallery.app import Gallery
return Gallery(self.marionette)
def tap_switch_to_camera(self):
self.marionette.find_element(*self._camera_locator).tap()
from gaiatest.apps.camera.app import Camera
camera_app = Camera(self.marionette)
camera_app.wait_to_be_displayed()
self.apps.switch_to_displayed_app()
camera_app.wait_for_capture_ready()
Wait(self.marionette).until(expected.element_not_displayed(*self._loading_screen_locator))
return camera_app
def double_tap_image(self):
image = self.marionette.find_element(*self._current_image_locator)
action = Actions(self.marionette)
action.double_tap(image)
action.perform()
@property
def photo_toolbar_width(self):
return self.marionette.find_element(*self._photos_toolbar_locator).rect['width']
@property
def photo_toolbar_options(self):
return self.marionette.find_elements(*self._photo_toolbar_options_locator)

View file

@ -0,0 +1,68 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from marionette_driver import expected, By, Wait
from gaiatest.apps.base import Base
class MultipleSelectionView(Base):
_select_picture_header_locator = (By.ID, 'thumbnails-number-selected')
_thumbnail_list_view_locator = (By.CSS_SELECTOR, '.thumbnail')
_share_thumbnail_locator = (By.ID, 'thumbnails-share-button')
_delete_thumbnail_locator = (By.ID, 'thumbnails-delete-button')
_delete_confirm_locator = (By.ID, 'confirm-ok')
_delete_cancel_locator = (By.ID, 'confirm-cancel')
def __init__(self, marionette):
Base.__init__(self, marionette)
select_picture_header = Wait(self.marionette).until(
expected.element_present(*self._select_picture_header_locator))
Wait(self.marionette).until(expected.element_displayed(select_picture_header))
def select_first_picture(self):
self.thumbnails[0].tap()
def select_nth_picture(self, n):
assert len(self.thumbnails) > n
self.thumbnails[n].tap()
@property
def number_of_selected_images(self):
select_picture_header = Wait(self.marionette).until(
expected.element_present(*self._select_picture_header_locator))
if 'selected' in select_picture_header.text:
return int(select_picture_header.text[:1])
else:
return 0
@property
def thumbnails(self):
return self.marionette.find_elements(*self._thumbnail_list_view_locator)
def tap_share_button(self):
share_button = Wait(self.marionette).until(
expected.element_present(*self._share_thumbnail_locator))
Wait(self.marionette).until(expected.element_displayed(share_button))
share_button.tap()
from gaiatest.apps.system.regions.activities import Activities
return Activities(self.marionette)
# one can choose to cancel deletion by entering optional parameter
def tap_delete_button(self, confirm=True):
delete_button = Wait(self.marionette).until(
expected.element_present(*self._delete_thumbnail_locator))
Wait(self.marionette).until(expected.element_displayed(delete_button))
delete_button.tap()
if confirm:
confirm_decision_button = Wait(self.marionette).until(
expected.element_present(*self._delete_confirm_locator))
else:
confirm_decision_button = Wait(self.marionette).until(
expected.element_present(*self._delete_cancel_locator))
Wait(self.marionette).until(expected.element_displayed(confirm_decision_button))
confirm_decision_button.tap()

View file

@ -0,0 +1,43 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from marionette_driver import expected, By, Wait
from gaiatest.apps.base import Base
from gaiatest.form_controls.header import GaiaHeader
class ViewImage(Base):
_header_locator = (By.ID, 'header')
_banner_message_locator = (By.ID, 'message')
_save_image_button_locator = (By.ID, 'save')
_image_locator = (By.CSS_SELECTOR, 'img.image-view')
manifest_url = '{}gallery{}/manifest.webapp'.format(Base.DEFAULT_PROTOCOL,Base.DEFAULT_APP_HOSTNAME)
def __init__(self, marionette):
Base.__init__(self, marionette)
from gaiatest.apps.gallery.app import Gallery
Gallery(self.marionette).wait_to_be_displayed()
self.apps.switch_to_displayed_app()
Wait(self.marionette).until(expected.element_displayed(
Wait(self.marionette).until(expected.element_present(
*self._image_locator))))
@property
def is_image_visible(self):
return self.is_element_displayed(*self._image_locator)
@property
def banner_message(self):
element = Wait(self.marionette).until(
expected.element_present(*self._banner_message_locator))
Wait(self.marionette).until(expected.element_displayed(element))
return element.text
def tap_back_button(self):
GaiaHeader(self.marionette, self._header_locator).go_back(exit_app=True, app=self)
def tap_save_image(self):
self.marionette.find_element(*self._save_image_button_locator).tap()