Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add revert to backup option to file menu #3434

Merged
merged 4 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion CONTRIBUTORS
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ Ben Nguyen <105088397+bpnguyen107@users.noreply.github.com>
Themis Demetriades <themis100@outlook.com>
Luke Bartholomew <lukesbart@icloud.com>
Gregory Abrasaldo <degeemon@gmail.com>
Taylor Obyen <https://github.com/taylorobyen>
Taylor Obyen <taylorobyen@gmail.com>
Kris Cherven <krischerven@gmail.com>

********************
Expand Down
1 change: 1 addition & 0 deletions ftl/qt/qt-accel.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,4 @@ qt-accel-reset-zoom = &Reset Zoom
qt-accel-zoom-editor-in = Zoom Editor &In
qt-accel-zoom-editor-out = Zoom Editor &Out
qt-accel-create-backup = Create &Backup
qt-accel-load-backup = &Load Backup
dae marked this conversation as resolved.
Show resolved Hide resolved
5 changes: 4 additions & 1 deletion ftl/qt/qt-misc.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ qt-misc-please-select-1-card = (please select 1 card)
qt-misc-please-select-a-deck = Please select a deck.
qt-misc-please-use-fileimport-to-import-this = Please use File>Import to import this file.
qt-misc-processing = Processing...
qt-misc-replace-your-collection-with-an-earlier = Replace your collection with an earlier backup?
qt-misc-just-now = just now
qt-misc-unspecified-time = an unspecified time in the past
qt-misc-ago = ago
qt-misc-replace-your-collection-with-an-earlier = Replace your collection with an earlier backup from { $val }?
qt-misc-revert-to-backup = Revert to backup
# please do not change the quote character, and please only change the font name if you have confirmed the new name is a valid Windows font
qt-misc-segoe-ui = "Segoe UI"
Expand Down
1 change: 1 addition & 0 deletions qt/aqt/about.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ def on_dialog_destroyed() -> None:
"Susanna Björverud",
"Sylvain Durand",
"Tacutu",
"Taylor Obyen",
"Timm Preetz",
"Timo Paulssen",
"Ursus",
Expand Down
6 changes: 6 additions & 0 deletions qt/aqt/forms/main.ui
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
<addaction name="actionExport"/>
<addaction name="separator"/>
<addaction name="action_create_backup"/>
<addaction name="action_open_backup"/>
<addaction name="separator"/>
<addaction name="actionExit"/>
</widget>
Expand Down Expand Up @@ -277,6 +278,11 @@
<string>qt_accel_create_backup</string>
</property>
</action>
<action name="action_open_backup">
<property name="text">
<string>qt_accel_load_backup</string>
</property>
</action>
</widget>
<resources>
<include location="icons.qrc"/>
Expand Down
57 changes: 43 additions & 14 deletions qt/aqt/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
checkInvalidFilename,
current_window,
disallow_full_screen,
get_relative_file_modified_time,
getFile,
getOnlyText,
openHelp,
Expand Down Expand Up @@ -424,32 +425,59 @@ def onRemProfile(self) -> None:
self.pm.remove(self.pm.name)
self.refreshProfilesList()

def _handle_load_backup_success(self) -> None:
"""
Actions that occur when profile backup has been loaded successfully
"""
if self.state == "profileManager":
self.profileDiag.closeWithoutQuitting()

self.loadProfile()

def _handle_load_backup_failure(self, error: Exception) -> None:
"""
Actions that occur when a profile has loaded unsuccessfully
"""
showWarning(str(error))
if self.state != "profileManager":
self.loadProfile()

def onOpenBackup(self) -> None:
if not askUser(
tr.qt_misc_replace_your_collection_with_an_earlier(),
msgfunc=QMessageBox.warning,
defaultno=True,
):
return

def doOpen(path: str) -> None:
self._openBackup(path)
def do_open(path: str) -> None:
if not askUser(
tr.qt_misc_replace_your_collection_with_an_earlier(
get_relative_file_modified_time(path)
),
msgfunc=QMessageBox.warning,
defaultno=True,
):
return

showInfo(tr.qt_misc_automatic_syncing_and_backups_have_been())

# Collection is still loaded if called from main window, so we unload. This is already
# unloaded if called from the ProfileManager window.
if self.col:
self.unloadProfile(lambda: self._start_restore_backup(path))
return

self._start_restore_backup(path)

getFile(
self.profileDiag,
self.profileDiag if self.state == "profileManager" else self,
tr.qt_misc_revert_to_backup(),
cb=doOpen, # type: ignore
cb=do_open, # type: ignore
filter="*.colpkg",
dir=self.pm.backupFolder(),
)

def _openBackup(self, path: str) -> None:
def _start_restore_backup(self, path: str):
self.restoring_backup = True
showInfo(tr.qt_misc_automatic_syncing_and_backups_have_been())

import_collection_package_op(
self, path, success=self.onOpenProfile
).run_in_background()
self, path, success=self._handle_load_backup_success
).failure(self._handle_load_backup_failure).run_in_background()

def _on_downgrade(self) -> None:
self.progress.start()
Expand Down Expand Up @@ -1349,6 +1377,7 @@ def setupMenus(self) -> None:
qconnect(m.actionImport.triggered, self.onImport)
qconnect(m.actionExport.triggered, self.onExport)
qconnect(m.action_create_backup.triggered, self.on_create_backup_now)
qconnect(m.action_open_backup.triggered, self.onOpenBackup)
qconnect(m.actionExit.triggered, self.close)

# Help
Expand Down
31 changes: 31 additions & 0 deletions qt/aqt/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import subprocess
import sys
from collections.abc import Callable, Sequence
from datetime import datetime
from functools import partial, wraps
from pathlib import Path
from typing import TYPE_CHECKING, Any, Literal, Union
Expand Down Expand Up @@ -610,6 +611,36 @@ def setWindowIcon(widget: QWidget) -> None:
######################################################################


def get_relative_file_modified_time(file_path: str) -> str:
"""
Provided a full file path, return relative file time such as:
- Normal files: `2 hours ago`, `5 minutes ago`, `1 day ago`
- Non-existant files: `an unspecified time in the past`
- Just created: `just now`
"""
if not os.path.exists(file_path):
return tr.qt_misc_unspecified_time()

units = [
(tr.scheduling_time_span_years, 31556952),
(tr.scheduling_time_span_months, 2678400),
(tr.scheduling_time_span_days, 86400),
(tr.scheduling_time_span_hours, 3600),
(tr.scheduling_time_span_minutes, 60),
(tr.scheduling_time_span_seconds, 1),
]

modified_time = os.path.getmtime(file_path)
modified_since = datetime.now().timestamp() - modified_time

for name, seconds in units:
if modified_since > seconds:
converted_time = int(modified_since // seconds)
return f"{name(converted_time)} {tr.qt_misc_ago()}"

return tr.qt_misc_just_now()


def getFile(
parent: QWidget,
title: str,
Expand Down