Keep the current language pack until the new one is downloaded
The package downloader deleted the installed language pack as soon as a version difference with the server was detected, before the download had even started. If the download then failed (connection drop, server error), the device was left with an empty language directory: on the next offline launch, the directory check failed and the app was unusable until internet access was restored. The early cleanup was also redundant: _copy_data() already removes the existing directory right before extracting the new archive, i.e. after the download has succeeded (HTTP 200). Changes in package_downloader.gd: - Remove the pre-download cleanup of the current language directory; the previous pack now stays usable for offline play until the new one has been fully downloaded. - Check the return value of HTTPRequest.request() and show the download error popup when the request cannot be started, instead of leaving the screen waiting forever on a request that was never sent. - Surface extraction failures (missing archive, unzip error) through the error popup instead of silently returning from the extraction thread and leaving the user stuck on a frozen progress screen. Changes in login.gd: - Handle the result of UserDataManager.login_student(), which was previously logged and ignored. The synchronization performed right before the login can delete or move the student locally (e.g. the server requested a local deletion), in which case the child was sent to the gardens scene with no student session loaded, ending up on a dead screen. On failure, play the wrong-password feedback and reset the code keyboard instead of changing scene. Verified with the GUT test suite (58/58 passing).
This commit is contained in:
@@ -97,16 +97,16 @@ func _ready() -> void:
|
||||
# Create the language_resources folder
|
||||
if not DirAccess.dir_exists_absolute(USER_LANGUAGE_RESOURCES_PATH):
|
||||
DirAccess.make_dir_recursive_absolute(USER_LANGUAGE_RESOURCES_PATH)
|
||||
|
||||
# Delete the files from old language pack
|
||||
if DirAccess.dir_exists_absolute(current_language_path):
|
||||
Log.trace("PackageDownloader: Cleaning existing language directory at %s" % current_language_path)
|
||||
Utils.clean_dir(current_language_path)
|
||||
|
||||
# Download the pack
|
||||
|
||||
# Download the pack. The previous pack is kept on disk so the app can
|
||||
# still run offline if the download fails; it is only removed during
|
||||
# extraction, once the new pack has been fully downloaded.
|
||||
http_request.set_download_file(USER_LANGUAGE_RESOURCES_PATH.path_join(language + ".zip"))
|
||||
Log.trace("PackageDownloader: Downloading pack from %s" % res.body.url)
|
||||
http_request.request(res.body.url as String)
|
||||
var request_error: Error = http_request.request(res.body.url as String)
|
||||
if request_error != OK:
|
||||
Log.error("PackageDownloader: Cannot start language pack download: %s" % error_string(request_error))
|
||||
_show_error(2) # Error downloading
|
||||
else:
|
||||
download_bar.value = 1
|
||||
extract_bar.value = 1
|
||||
@@ -152,6 +152,7 @@ func _copy_data(this: PackageDownloader) -> void:
|
||||
# Check if a zip exists for the complete locale
|
||||
if not FileAccess.file_exists(USER_LANGUAGE_RESOURCES_PATH.path_join(language + ".zip")):
|
||||
Log.warn("PackageDownloader: No downloaded archive found for %s" % language)
|
||||
this.call_thread_safe("_show_error", 2) # Error downloading
|
||||
return
|
||||
|
||||
Log.trace("PackageDownloader: Extracting downloaded package")
|
||||
@@ -184,6 +185,7 @@ func _copy_data(this: PackageDownloader) -> void:
|
||||
var subfolder: String = unzipper.extract(language_zip_path, USER_LANGUAGE_RESOURCES_PATH, false)
|
||||
if subfolder == "":
|
||||
Log.error("PackageDownloader: Extraction failed for %s" % language_zip_path)
|
||||
this.call_thread_safe("_show_error", 2) # Error downloading
|
||||
return
|
||||
|
||||
# Move the data to the locale folder of the user
|
||||
|
||||
@@ -63,6 +63,13 @@ func _on_code_keyboard_password_entered(password: String) -> void:
|
||||
var login_success: bool = UserDataManager.login_student(password)
|
||||
Log.info("LoginScreen: Login attempt for student code %s returned %s" % [password, str(login_success)])
|
||||
kalulu_button.hide()
|
||||
if not login_success:
|
||||
# The synchronization above may have deleted or moved the student
|
||||
Log.warn("LoginScreen: Login failed for student code %s after synchronization" % password)
|
||||
await kalulu.play_kalulu_speech(wrong_password_speech)
|
||||
keyboard.reset_password()
|
||||
kalulu_button.show()
|
||||
return
|
||||
await kalulu.play_kalulu_speech(right_password_speech)
|
||||
await OpeningCurtain.close()
|
||||
Log.trace("LoginScreen: Start loading next scene")
|
||||
|
||||
Reference in New Issue
Block a user