Skip to content
Open
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: 26 additions & 1 deletion ou_dedetai/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ def status(self, message: str, percent: Optional[int | float] = None):
# Perhaps this should just raise NotImplementedError to avoid confusion?
@abc.abstractmethod
def _status(self, message: str, percent: Optional[int] = None):
"""Implementation for updating status pre-front end
"""Implementation for updating status per-front end

Args:
message: str - message to send to user
Expand Down Expand Up @@ -276,7 +276,32 @@ def get_progressbar(pct, w=10, suffix=''):
print(f"{message}")
if bar:
print(bar)

def pop_up(self, title: str, message: str):
"""An intrusive message requiring user attention

Args:
title: str - title of the alert
message: str - message to send to user
"""
# Check to see if we want to suppress all output
if self.conf._overrides.quiet:
return

self._pop_up(title=title,message=message)

# FIXME: This implementation is overridden in every implementation
# Perhaps this should just raise NotImplementedError to avoid confusion?
@abc.abstractmethod
def _pop_up(self, title: str, message: str):
"""Implementation for opening a pop up per-front end

Args:
title: str - title of the alert
message: str - message to send to user
"""
# Fallback to just sending a status if pop up isn't implemented.
self._status(message=message)

@property
def superuser_command(self) -> str:
Expand Down
3 changes: 3 additions & 0 deletions ou_dedetai/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,9 @@ def _status(self, message: str, percent: Optional[int] = None):
if progress_str:
print(progress_str, end="\r")

def _pop_up(self, title, message):
self._status(message=message)

@property
def superuser_command(self) -> str:
if shutil.which('sudo'):
Expand Down
6 changes: 6 additions & 0 deletions ou_dedetai/gui_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ def _info(self, message):
"""Display information to the user"""
InfoPopUp(message)

def _pop_up(self, title, message):
messagebox.showinfo(
title=title,
message=message
)

def _status(self, message, percent = None):
message = message.strip()
if percent is not None:
Expand Down
14 changes: 12 additions & 2 deletions ou_dedetai/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,11 @@ def ensure_appimage_download(app: App):
check_system_compatibility(app=app)
app.installer_step += 1

if app.conf.faithlife_product_version != '9' and not str(app.conf.wine_binary).lower().endswith('appimage'):
if (
app.conf.faithlife_product_version != '9'
and not str(app.conf.wine_binary).lower().endswith('appimage')
and app.conf.wine_binary not in [constants.WINE_RECOMMENDED_SIGIL, constants.WINE_BETA_SIGIL]
):
return
app.status("Ensuring wine AppImage is downloaded…")

Expand Down Expand Up @@ -619,7 +623,13 @@ def create_launcher_shortcuts(app: App):
filename=url_handler_desktop_filename,
app_name=f"{flproduct} URL Handler",
comment="Handles logos4: and libronixdls: URL Schemes",
exec_cmd=f"{oudedetai_executable} --wine '{app.conf.logos_exe_windows_path.replace('\\','\\\\')}' '%u'",
exec_cmd=(
f"/bin/sh -c \""
f"({oudedetai_executable} --wine '{app.conf.logos_exe_windows_path.replace('\\','\\\\')}' ''%u'') "
"|| (echo 'Failed to spawn logos. If you are logging in please hit the link for not being redirected "
"automatically then the link for still having trouble. If you contact support please attach this log'"
"; sleep 60; exit 1); wait\""
),
icon_path=app_icon_path,
mime_types=["x-scheme-handler/logos4","x-scheme-handler/libronixdls"],
terminal=True
Expand Down
55 changes: 54 additions & 1 deletion ou_dedetai/logos.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
import psutil
import threading

from ou_dedetai import database
from ou_dedetai import constants, database
from ou_dedetai.app import App
from ou_dedetai.config import get_logos_user_id

from . import system
from . import utils
Expand Down Expand Up @@ -100,6 +101,57 @@ def monitor(self):
# Useful if the install directory got deleted while executing
self.logos_state = State.STOPPED

def monitor_for_potential_issues(self):
"""A function to be run in parallel with running Logos to detect common issues and suggest workarounds"""
# Make sure we have a logos appdata, without it we can't reliably do any checks
logos_appdata_dir = self.app.conf._logos_appdata_dir
if logos_appdata_dir is None:
logging.warning("The user should have installed the Logos application by now and have this populated."
" Waiting until that is resolved...")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: change "..." to "…"

while logos_appdata_dir is None:
time.sleep(1)
logos_appdata_dir = self.app.conf._logos_appdata_dir

# See if the user is logged in, this may change which things we look for
is_user_logged_in: bool = False
if get_logos_user_id(logos_appdata_dir) is not None:
is_user_logged_in = True

sent_trouble_singing_in_message: bool = False
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct var name "sent_trouble_singing_in_message" to "sent_trouble_signing_in_message"


time_logos_started = time.time()

while True:
# Now we wait...
time.sleep(10)

if not is_user_logged_in:
if get_logos_user_id(logos_appdata_dir) is not None:
# User's now logged in - no fuss.
is_user_logged_in = True
else:
# Took me about ~1.5 minutes to sign on while simulating a little dilly-dallying and a couple
# incorrect password attempts. Should still be longer than most people take to sign on, but not SO
# long that people close OD in frustration to try again - fine line of balance.
if not sent_trouble_singing_in_message and time.time() - time_logos_started > 60 * 1.75:
# It's been five minutes since the user launched Logos and yet they haven't logged in yet.
# Are they having trouble?
self.app.pop_up(
"Trouble Signing In?",
"If you're having trouble signing in, try these workarounds:\n\n" \
"If the browser isn't launching after you hit \"Sign In\" in the Logos application "
"consider installing firefox from your system's package manager and temporarily setting "
"that as your default browser.\n\n"
"If the browser opens and entering your credentials is successful but nothing happens: "
"on the Logos browser page try hitting the button for not being redirected automatically "
"then click on the link that shows up that suggests to click it if you're still having "
"trouble. That should cause you to sign in on the Logos application.\n\n"
f"If you still need help use \"Get Support\" on the main page of {constants.APP_NAME}"
)
# We only want to send this message once
sent_trouble_singing_in_message = True


def start(self):
self.logos_state = State.STARTING
wine_release, _ = wine.get_wine_release(self.app.conf.wine_binary)
Expand Down Expand Up @@ -132,6 +184,7 @@ def run_logos():
wine.wineserver_kill(self.app)
# Don't send "Running" message to GUI b/c it never clears.
logging.info(f"Running {self.app.conf.faithlife_product}…")
self.app.start_thread(self.monitor_for_potential_issues, daemon_bool=False)
self.app.start_thread(run_logos, daemon_bool=False)
# NOTE: The following code would keep the CLI open while running
# Logos, but since wine logging is sent directly to wine.log,
Expand Down
3 changes: 3 additions & 0 deletions ou_dedetai/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,9 @@ def check_opengl_version(app: App, required_version="3.2") -> tuple[bool, str]:
return False, "glxinfo command not found. Please install mesa-utils or equivalent."
except subprocess.CalledProcessError as e:
return False, f"glxinfo command failed: {e.stderr.strip()}"

if not result:
return False, "failed to launch glxinfo."

match = re.search(r"OpenGL version string:\s+([\d\.]+)", result.stdout)
if not match:
Expand Down
20 changes: 20 additions & 0 deletions ou_dedetai/tui_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,7 @@ def choice_processor(self, stdscr, screen_id, choice):
1: self.custom_appimage_select,
2: self.handle_ask_response,
8: self.waiting,
9: self.pop_up_select,
10: self.waiting_releases,
11: self.wineconfig_menu_select,
12: self.logos.start,
Expand Down Expand Up @@ -798,6 +799,13 @@ def custom_appimage_select(self, choice: str):
self.appimage_q.put(str(self.conf.wine_appimage_path))
self.appimage_e.set()

def pop_up_select(self, choice):
# Only one option - go back to the main menu.
# Ideally this would just remove the current screen, however ran into issues when trying to implement that.
# Don't want to risk the stability of the app for fixing the aforementioned bug ()
if choice == self._exit_option:
self.go_to_main_menu()

def waiting(self, choice):
pass

Expand Down Expand Up @@ -928,6 +936,18 @@ def _status(self, message: str, percent: int | None = None):
percent=percent or 0,
)

def _pop_up(self, title, message):
self.console_log.append(message)
self.stack_confirm(
9,
self.status_q,
self.status_e,
message,
no_text="",
secondary=title,
options=[self._exit_option]
)

def _config_update_hook(self):
self.update_main_window_contents()
self.set_curses_color_scheme()
Expand Down
8 changes: 4 additions & 4 deletions ou_dedetai/tui_curses.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,18 @@ def text_centered(app: App, stdscr: curses.window, text: str, start_y=0) -> tupl
text_lines = wrap_text(app, text)
text_start_y = start_y
text_width = max(len(line) for line in text_lines)
column_margin = app.terminal_margin * 2
for i, line in enumerate(text_lines):
if text_start_y + i < app.window_height:
x = app.window_width // 2 - text_width // 2
# Terminal margin is subtracted to account for wrapping
x = app.window_width // 2 - text_width // 2 # - app.terminal_margin
write_line(
app,
stdscr,
text_start_y + i,
max(column_margin, x),
max(app.terminal_margin, x),
line,
# column_margin is doubled to account for the left side's column_margin
app.window_width - (column_margin * 2),
app.window_width - (app.terminal_margin * 2),
curses.A_BOLD
)

Expand Down