Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions app_src/tests/test_download_apk_screen.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,35 @@ def test_apk_is_valid_rejects_wrong_size(tmp_path):

class _FakeResponse:
def __init__(self, content):
"""
Initialize a response with content and its byte length.

Parameters:
content: The response content.
"""
self.content = content
self.headers = {"content-length": str(len(content))}

def raise_for_status(self):
return None

def iter_content(self, _):
"""Yield the response content as a single chunk."""
yield self.content


@pytest.fixture
def fake_download_dir(tmp_path, monkeypatch):
"""
Configure APK downloads to use a temporary directory.

Parameters:
tmp_path: Temporary directory used as the APK download location.
monkeypatch: Fixture used to replace the APK directory resolver.

Returns:
The configured temporary directory.
"""
monkeypatch.setattr(d, "get_apk_directory", lambda: str(tmp_path))
return tmp_path

Expand Down Expand Up @@ -106,6 +123,7 @@ def unbind(self, *_, **__):

class _FakeUpdateButton:
def __init__(self):
"""Initialize the fake button with an unclicked state and a fake streak."""
self.clicked = False
self.streak = _FakeStreak()

Expand All @@ -118,6 +136,7 @@ class _FakeLaterButton:


def _instantiate_screen():
"""Create a download screen with mocked application dependencies for testing."""
from kivy.event import EventDispatcher
from kivy.properties import StringProperty
from kivymd.app import MDApp
Expand Down Expand Up @@ -148,9 +167,17 @@ def test_start_download_uses_versioned_url_and_filename():

class _FakeThread:
def __init__(self, target=None, daemon=None):
"""
Capture the callable provided as the thread target.

Parameters:
target (callable, optional): Callable assigned as the thread target.
daemon (bool, optional): Thread daemon setting.
"""
captured["target"] = target

def start(self):
"""Run the captured target function."""
captured["target"]()

with mock.patch("threading.Thread", _FakeThread), \
Expand Down
48 changes: 46 additions & 2 deletions app_src/ui/screens/download_apk_screen.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,12 @@ def add_body_to_new_stuff_container(self, markup_text):

def start_download(self,_=None):
#p("Clicked start download...")
if not self.built_ui:
"""
Start downloading the update APK or switch to installation when a valid cached APK is available.

The download runs in a background thread and updates the progress button as data arrives.
"""
if not self.built_ui:
return
import threading

Expand All @@ -390,6 +395,9 @@ def progress(percent):
self.clock_for_progress_update.cancel()
self.clock_for_progress_update = Clock.schedule_once(lambda dt: self.update_button.update_progress(percent))
def worker():
"""
Download the selected release APK and switch the download control to installation mode when successful.
"""
filename = get_apk_filename(self.new_version)
apk_path__ = download_apk(
get_apk_download_url(self.new_version),
Expand Down Expand Up @@ -526,7 +534,16 @@ def do_not_go_to_update_screen(msg):
Clock.schedule_once(lambda dt, e=e: do_not_go_to_update_screen(f"Failed:{e}"))

def get_release_note_txt(data,latest_version):
"""Check GitHub latest release version"""
"""
Retrieve release notes for a specific version from the release assets.

Parameters:
data (dict): GitHub release metadata containing an ``assets`` collection.
latest_version (str): Version used to identify the release-notes asset.

Returns:
str: Downloaded release notes, or default release notes when the asset is unavailable or cannot be downloaded.
"""
import time
import traceback
import requests
Expand Down Expand Up @@ -557,13 +574,40 @@ def get_release_note_txt(data,latest_version):
return release_notes or DEFAULT_RELEASE_NOTE

def get_apk_filename(version):
"""
Build the filename for a versioned APK.

Parameters:
version: The APK version identifier.

Returns:
str: The versioned APK filename.
"""
return f"waller-v{version}.apk"

def get_apk_download_url(version):
"""
Build the GitHub release URL for a versioned APK.

Parameters:
version: The APK release version.

Returns:
str: The download URL for the versioned APK.
"""
filename = get_apk_filename(version)
return f"https://github.com/Fector101/wallpaper-carousel/releases/download/v{version}/{filename}"

def get_apk_size(data):
"""
Finds the size of the first APK asset in release metadata.

Parameters:
data (dict): Release metadata containing an `assets` collection.

Returns:
int: The APK file size in bytes, or `0` if no APK asset is found.
"""
for asset in data["assets"]:
if asset["name"].endswith(".apk"):
size = asset["size"]
Expand Down